From fa977f45f45d113dfb69e82d46c704d3bb78318c Mon Sep 17 00:00:00 2001 From: john30 Date: Sun, 6 Oct 2019 14:12:52 +0200 Subject: [PATCH] add support for logging to syslog (fixes #293), log exit on errors during daemonization, log config path on error, better variable names --- src/ebusd/main.cpp | 18 +++++------ src/lib/utils/log.cpp | 70 ++++++++++++++++++++++++++++++------------- src/lib/utils/log.h | 2 +- 3 files changed, 59 insertions(+), 31 deletions(-) mode change 100644 => 100755 src/ebusd/main.cpp diff --git a/src/ebusd/main.cpp b/src/ebusd/main.cpp old mode 100644 new mode 100755 index a5f2ae1d..1da71025 --- a/src/ebusd/main.cpp +++ b/src/ebusd/main.cpp @@ -223,7 +223,7 @@ static const struct argp_option argpoptions[] = { {"updatecheck", O_UPDCHK, "MODE", 0, "Set automatic update check to MODE (on|off) [on]", 0 }, {nullptr, 0, nullptr, 0, "Log options:", 5 }, - {"logfile", 'l', "FILE", 0, "Write log to FILE (only for daemon) [" PACKAGE_LOGFILE "]", 0 }, + {"logfile", 'l', "FILE", 0, "Write log to FILE (only for daemon, empty string for using syslog) [" PACKAGE_LOGFILE "]", 0 }, {"log", O_LOG, "AREAS LEVEL", 0, "Only write log for matching AREA(S) below or equal to LEVEL" " (alternative to --logareas/--logevel, may be used multiple times) [all notice]", 0 }, {"logareas", O_LOGARE, "AREAS", 0, "Only write log for matching AREA(S): main|network|bus|update|all" @@ -487,7 +487,7 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) { // Log options: case 'l': // --logfile=/var/log/ebusd.log - if (arg == nullptr || arg[0] == 0 || strcmp("/", arg) == 0) { + if (arg == nullptr || strcmp("/", arg) == 0) { argp_error(state, "invalid logfile"); return EINVAL; } @@ -599,7 +599,7 @@ void daemonize() { pid_t pid = fork(); if (pid < 0) { - logError(lf_main, "fork() failed"); + logError(lf_main, "fork() failed, exiting"); exit(EXIT_FAILURE); } @@ -612,14 +612,14 @@ void daemonize() { // Create a new SID for the child process and // detach the process from the parent (normally a shell) if (setsid() < 0) { - logError(lf_main, "setsid() failed"); + logError(lf_main, "setsid() failed, exiting"); exit(EXIT_FAILURE); } // Change the current working directory. This prevents the current // directory from being locked; hence not being able to remove it. if (chdir("/tmp") < 0) { - logError(lf_main, "daemon chdir() failed"); + logError(lf_main, "daemon chdir() failed, exiting"); exit(EXIT_FAILURE); } @@ -642,7 +642,7 @@ void daemonize() { } } if (pidFile == nullptr) { - logError(lf_main, "can't open pidfile: %s", opt.pidFile); + logError(lf_main, "can't open pidfile: %s, exiting", opt.pidFile); exit(EXIT_FAILURE); } @@ -701,7 +701,7 @@ void signalHandler(int sig) { switch (sig) { case SIGHUP: logNotice(lf_main, "SIGHUP received"); - if (!opt.foreground) { + if (!opt.foreground && opt.logFile && opt.logFile[0] != 0) { // for log file rotation closeLogFile(); setLogFile(opt.logFile); } @@ -988,8 +988,8 @@ result_t loadConfigFiles(MessageMap* messages, bool verbose, bool denyRecursive) if (result == RESULT_OK) { logInfo(lf_main, "read config files"); } else { - logError(lf_main, "error reading config files: %s, last error: %s", getResultCode(result), - errorDescription.c_str()); + logError(lf_main, "error reading config files from %s: %s, last error: %s", opt.configPath, + getResultCode(result), errorDescription.c_str()); } messages->unlock(); return RESULT_OK; diff --git a/src/lib/utils/log.cpp b/src/lib/utils/log.cpp index ecf26021..350cda61 100755 --- a/src/lib/utils/log.cpp +++ b/src/lib/utils/log.cpp @@ -27,12 +27,13 @@ #include #include #include +#include #include "lib/utils/clock.h" namespace ebusd { /** the name of each @a LogFacility. */ -static const char *facilityNames[] = { +static const char *s_facilityNames[] = { "main", "network", "bus", @@ -43,7 +44,7 @@ static const char *facilityNames[] = { }; /** the name of each @a LogLevel. */ -static const char* levelNames[] = { +static const char* s_levelNames[] = { "none", "error", "notice", @@ -52,19 +53,32 @@ static const char* levelNames[] = { nullptr }; +/** the syslog level of each @a LogLevel. */ +static const int s_syslogLevels[] = { + LOG_INFO, + LOG_ERR, + LOG_NOTICE, + LOG_INFO, + LOG_DEBUG, + 0 +}; + /** the current log level by log facility. */ static LogLevel s_facilityLogLevel[] = { ll_notice, ll_notice, ll_notice, ll_notice, ll_notice, }; -/** the current log FILE. */ +/** the current log FILE, or nullptr if closed or syslog is used. */ static FILE* s_logFile = stdout; +/** whether to log to syslog. */ +static bool s_useSyslog = false; + LogFacility parseLogFacility(const char* facility) { if (!facility) { return lf_COUNT; } char *input = strdup(facility); char *opt = reinterpret_cast(input), *value = nullptr; - int val = getsubopt(&opt, (char *const *)facilityNames, &value); + int val = getsubopt(&opt, (char *const *)s_facilityNames, &value); if (val < 0 || val >= lf_COUNT || value || *opt) { free(input); return lf_COUNT; @@ -78,7 +92,7 @@ int parseLogFacilities(const char* facilities) { char *opt = reinterpret_cast(input), *value = nullptr; int newFacilites = 0; while (*opt) { - int val = getsubopt(&opt, (char *const *)facilityNames, &value); + int val = getsubopt(&opt, (char *const *)s_facilityNames, &value); if (val < 0 || val > lf_COUNT || value) { free(input); return -1; @@ -99,7 +113,7 @@ LogLevel parseLogLevel(const char* level) { } char *input = strdup(level); char *opt = reinterpret_cast(input), *value = nullptr; - int val = getsubopt(&opt, (char *const *)levelNames, &value); + int val = getsubopt(&opt, (char *const *)s_levelNames, &value); if (val < 0 || val >= ll_COUNT || value || *opt) { free(input); return ll_COUNT; @@ -109,11 +123,11 @@ LogLevel parseLogLevel(const char* level) { } const char* getLogFacilityStr(LogFacility facility) { - return facilityNames[facility]; + return s_facilityNames[facility]; } const char* getLogLevelStr(LogLevel level) { - return levelNames[level]; + return s_levelNames[level]; } bool setFacilitiesLogLevel(int facilities, LogLevel level) { @@ -132,6 +146,12 @@ LogLevel getFacilityLogLevel(LogFacility facility) { } bool setLogFile(const char* filename) { + if (filename[0] == 0) { + closeLogFile(); + openlog("ebusd", LOG_NDELAY|LOG_PID, LOG_USER); + s_useSyslog = true; + return true; + } FILE* newFile = fopen(filename, "a"); if (newFile == nullptr) { return false; @@ -148,27 +168,35 @@ void closeLogFile() { } s_logFile = nullptr; } + if (s_useSyslog) { + closelog(); + s_useSyslog = false; + } } bool needsLog(const LogFacility facility, const LogLevel level) { return s_facilityLogLevel[facility] >= level; } -void logWrite(const char* facility, const char* level, const char* message, va_list ap) { - if (s_logFile == nullptr) { +void logWrite(const char* facility, const LogLevel level, const char* message, va_list ap) { + if (s_logFile == nullptr && !s_useSyslog) { return; } - struct timespec ts; - struct tm td; - clockGettime(&ts); - localtime_r(&ts.tv_sec, &td); char* buf; if (vasprintf(&buf, message, ap) >= 0 && buf) { - fprintf(s_logFile, "%04d-%02d-%02d %02d:%02d:%02d.%03ld [%s %s] %s\n", - td.tm_year+1900, td.tm_mon+1, td.tm_mday, - td.tm_hour, td.tm_min, td.tm_sec, ts.tv_nsec/1000000, - facility, level, buf); - fflush(s_logFile); + if (s_useSyslog) { + syslog(s_syslogLevels[level], "[%s %s] %s", facility, s_levelNames[level], buf); + } else { + struct timespec ts; + struct tm td; + clockGettime(&ts); + localtime_r(&ts.tv_sec, &td); + fprintf(s_logFile, "%04d-%02d-%02d %02d:%02d:%02d.%03ld [%s %s] %s\n", + td.tm_year+1900, td.tm_mon+1, td.tm_mday, + td.tm_hour, td.tm_min, td.tm_sec, ts.tv_nsec/1000000, + facility, s_levelNames[level], buf); + fflush(s_logFile); + } } if (buf) { free(buf); @@ -178,14 +206,14 @@ void logWrite(const char* facility, const char* level, const char* message, va_l void logWrite(const LogFacility facility, const LogLevel level, const char* message, ...) { va_list ap; va_start(ap, message); - logWrite(facilityNames[facility], levelNames[level], message, ap); + logWrite(s_facilityNames[facility], level, message, ap); va_end(ap); } void logWrite(const char* facility, const LogLevel level, const char* message, ...) { va_list ap; va_start(ap, message); - logWrite(facility, levelNames[level], message, ap); + logWrite(facility, level, message, ap); va_end(ap); } diff --git a/src/lib/utils/log.h b/src/lib/utils/log.h index 0cd41ae8..4a6e264a 100755 --- a/src/lib/utils/log.h +++ b/src/lib/utils/log.h @@ -98,7 +98,7 @@ LogLevel getFacilityLogLevel(LogFacility facility); /** * Set the log file to use. - * @param filename the name of the log file to use. + * @param filename the name of the log file to use, or the empty string for syslog. * @return true on success, false on error. */ bool setLogFile(const char* filename);