From f488e1005337bcfcf1bd8dc418a84b6dafdddf30 Mon Sep 17 00:00:00 2001 From: Chris Novakovic Date: Mon, 25 Sep 2023 22:42:01 +0100 Subject: [PATCH] Log to syslog when running in background Log messages are unconditionally written to stderr, and are therefore lost after the fork when running in the background (`-g`). If syslog support is detected at compile time, and provided we're not on a platform for which an alternative non-stderr logging facility is provided (i.e. Windows), send log messages to syslog when running in the background. --- CMakeLists.txt | 4 ++ src/log.c | 120 ++++++++++++++++++++++++++++++++++++++++--------- src/log.h | 8 ++++ src/stubby.c | 6 +++ 4 files changed, 118 insertions(+), 20 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3202377..ac87245 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -103,6 +103,10 @@ set(SERVER_DEBUG ${ENABLE_DEBUG_SERVER}) check_symbol_exists(getopt "unistd.h" HAVE_GETOPT) +check_symbol_exists(vsyslog "syslog.h" HAVE_VSYSLOG) +if (HAVE_VSYSLOG) + add_compile_definitions(-DHAVE_VSYSLOG) +endif () # Does the compiler accept the "format" attribute? try_compile(HAVE_ATTR_FORMAT diff --git a/src/log.c b/src/log.c index ae77202..df99b2d 100644 --- a/src/log.c +++ b/src/log.c @@ -35,12 +35,74 @@ #include #endif +#if defined(HAVE_VSYSLOG) +#include +#endif + #include "log.h" +stubby_log_target_t log_target = STUBBY_LOG_STDERR; + +#if defined(HAVE_VSYSLOG) +static void stubby_syslog_open() +{ + static int is_syslog_open = 0; + + if (!is_syslog_open) { + openlog("stubby", LOG_PID, LOG_DAEMON); + is_syslog_open = 1; + } +} + +static int stubby_syslog_priority(getdns_loglevel_type level) +{ + int priority = LOG_INFO; + + switch (level) { + case GETDNS_LOG_EMERG: + priority = LOG_EMERG; + break; + case GETDNS_LOG_ALERT: + priority = LOG_ALERT; + break; + case GETDNS_LOG_CRIT: + priority = LOG_CRIT; + break; + case GETDNS_LOG_ERR: + priority = LOG_ERR; + break; + case GETDNS_LOG_WARNING: + priority = LOG_WARNING; + break; + case GETDNS_LOG_NOTICE: + priority = LOG_NOTICE; + break; + case GETDNS_LOG_INFO: + priority = LOG_INFO; + break; + case GETDNS_LOG_DEBUG: + priority = LOG_DEBUG; + break; + } + + return priority; +} +#endif + static void default_stubby_verror(getdns_loglevel_type level, const char *fmt, va_list ap) { - (void) level; - (void) vfprintf(stderr, fmt, ap); + switch (log_target) { +#if defined(HAVE_VSYSLOG) + case STUBBY_LOG_SYSLOG: + stubby_syslog_open(); + vsyslog(stubby_syslog_priority(level), fmt, ap); + break; +#endif + case STUBBY_LOG_STDERR: + (void) level; + (void) vfprintf(stderr, fmt, ap); + break; + } } long log_level = GETDNS_LOG_DEBUG + 1; @@ -49,27 +111,40 @@ static void default_stubby_vlog(void *userarg, uint64_t system, getdns_loglevel_type level, const char *fmt, va_list ap) { - struct timeval tv; - struct tm tm; - char buf[10]; + (void)userarg; (void)system; + + switch (log_target) { +#if defined(HAVE_VSYSLOG) + case STUBBY_LOG_SYSLOG: + stubby_syslog_open(); + vsyslog(stubby_syslog_priority(level), fmt, ap); + break; +#endif + case STUBBY_LOG_STDERR: + (void)0; + struct timeval tv; + struct tm tm; + char buf[10]; #if defined(STUBBY_ON_WINDOWS) - struct _timeb timeb; - time_t tsec; - if (level > log_level) return; - - _ftime_s(&timeb); - tsec = (time_t)timeb.time; - tv.tv_usec = timeb.millitm * 1000; - gmtime_s(&tm, &tsec); + struct _timeb timeb; + time_t tsec; + if (level > log_level) return; + + _ftime_s(&timeb); + tsec = (time_t)timeb.time; + tv.tv_usec = timeb.millitm * 1000; + gmtime_s(&tm, &tsec); #else - if (level > log_level) return; - gettimeofday(&tv, NULL); - gmtime_r(&tv.tv_sec, &tm); + if (level > log_level) return; + gettimeofday(&tv, NULL); + gmtime_r(&tv.tv_sec, &tm); #endif - strftime(buf, 10, "%H:%M:%S", &tm); - (void)userarg; (void)system; (void)level; - (void) fprintf(stderr, "[%s.%.6d] STUBBY: ", buf, (int)tv.tv_usec); - (void) vfprintf(stderr, fmt, ap); + strftime(buf, 10, "%H:%M:%S", &tm); + (void)level; + (void) fprintf(stderr, "[%s.%.6d] STUBBY: ", buf, (int)tv.tv_usec); + (void) vfprintf(stderr, fmt, ap); + break; + } } static stubby_verror_t stubby_verror = default_stubby_verror; @@ -114,6 +189,11 @@ void stubby_set_log_funcs(stubby_verror_t errfunc, stubby_vlog_t logfunc) stubby_vlog = logfunc; } +void stubby_set_log_target(stubby_log_target_t target) +{ + log_target = target; +} + void stubby_set_getdns_logging(getdns_context *context, int loglevel) { (void) getdns_context_set_logfunc(context, NULL, GETDNS_LOG_UPSTREAM_STATS, loglevel, stubby_vlog); diff --git a/src/log.h b/src/log.h index 7c53df8..6aa0a18 100644 --- a/src/log.h +++ b/src/log.h @@ -34,6 +34,13 @@ #include #include +typedef enum stubby_log_target { +#if defined(HAVE_VSYSLOG) + STUBBY_LOG_SYSLOG, +#endif + STUBBY_LOG_STDERR +} stubby_log_target_t; + typedef void(*stubby_verror_t)(getdns_loglevel_type level, const char *fmt, va_list ap); typedef void(*stubby_vlog_t)(void *userarg, uint64_t system, getdns_loglevel_type level, @@ -50,6 +57,7 @@ void stubby_warning(const char *fmt, ...); void stubby_debug(const char *fmt, ...); void stubby_set_log_funcs(stubby_verror_t errfunc, stubby_vlog_t logfunc); +void stubby_set_log_target(stubby_log_target_t target); void stubby_set_getdns_logging(getdns_context *context, int loglevel); diff --git a/src/stubby.c b/src/stubby.c index 3dd7b54..8322906 100644 --- a/src/stubby.c +++ b/src/stubby.c @@ -169,6 +169,12 @@ main(int argc, char **argv) } #endif +#if defined(HAVE_VSYSLOG) && !defined(STUBBY_ON_WINDOWS) + if (!run_in_foreground) { + stubby_set_log_target(STUBBY_LOG_SYSLOG); + } +#endif + if ((r = getdns_context_create(&context, 1))) { stubby_error("Create context failed: %s", stubby_getdns_strerror(r));