From 060814daa83f6a94f5934464ae42a406c5c7e947 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Fri, 27 Sep 2013 22:31:24 +0200 Subject: Log: new logging library API Prepare to migrate away from GLib. Currently, we're still using GLib as a backend. --- src/Log.cxx | 345 ++++++++++++++++-------------------------------------------- 1 file changed, 90 insertions(+), 255 deletions(-) (limited to 'src/Log.cxx') diff --git a/src/Log.cxx b/src/Log.cxx index 869327d25..f36e68133 100644 --- a/src/Log.cxx +++ b/src/Log.cxx @@ -18,7 +18,7 @@ */ #include "config.h" -#include "Log.hxx" +#include "LogV.hxx" #include "ConfigData.hxx" #include "ConfigGlobal.hxx" #include "ConfigOption.hxx" @@ -30,322 +30,157 @@ #include "util/Domain.hxx" #include "system/FatalError.hxx" +#include + #include #include #include #include -#include #include #include #include #include #include #include -#include - -#ifdef HAVE_SYSLOG -#include -#endif - -#undef G_LOG_DOMAIN -#define G_LOG_DOMAIN "log" -#define LOG_LEVEL_SECURE G_LOG_LEVEL_INFO - -#define LOG_DATE_BUF_SIZE 16 -#define LOG_DATE_LEN (LOG_DATE_BUF_SIZE - 1) - -static constexpr Domain log_domain("log"); - -static GLogLevelFlags log_threshold = G_LOG_LEVEL_MESSAGE; +static GLogLevelFlags +ToGLib(LogLevel level) +{ + switch (level) { + case LogLevel::DEBUG: + return G_LOG_LEVEL_DEBUG; -static const char *log_charset; + case LogLevel::INFO: + return G_LOG_LEVEL_MESSAGE; -static bool stdout_mode = true; -static int out_fd; -static Path out_path = Path::Null(); + case LogLevel::WARNING: + case LogLevel::ERROR: + return G_LOG_LEVEL_WARNING; + } -static void redirect_logs(int fd) -{ - assert(fd >= 0); - if (dup2(fd, STDOUT_FILENO) < 0) - FatalSystemError("Failed to dup2 stdout"); - if (dup2(fd, STDERR_FILENO) < 0) - FatalSystemError("Failed to dup2 stderr"); + assert(false); + gcc_unreachable(); } -static const char *log_date(void) +void +Log(const Domain &domain, LogLevel level, const char *msg) { - static char buf[LOG_DATE_BUF_SIZE]; - time_t t = time(NULL); - strftime(buf, LOG_DATE_BUF_SIZE, "%b %d %H:%M : ", localtime(&t)); - return buf; + g_log(domain.GetName(), ToGLib(level), "%s", msg); } -/** - * Determines the length of the string excluding trailing whitespace - * characters. - */ -static int -chomp_length(const char *p) +void +LogFormatV(const Domain &domain, LogLevel level, const char *fmt, va_list ap) { - size_t length = strlen(p); - - while (length > 0 && g_ascii_isspace(p[length - 1])) - --length; - - return (int)length; + g_logv(domain.GetName(), ToGLib(level), fmt, ap); } -static void -file_log_func(const gchar *domain, - GLogLevelFlags log_level, - const gchar *message, gcc_unused gpointer user_data) +void +LogFormat(const Domain &domain, LogLevel level, const char *fmt, ...) { - char *converted; - - if (log_level > log_threshold) - return; - - if (log_charset != NULL) { - converted = g_convert_with_fallback(message, -1, - log_charset, "utf-8", - NULL, NULL, NULL, NULL); - if (converted != NULL) - message = converted; - } else - converted = NULL; - - if (domain == nullptr) - domain = ""; - - fprintf(stderr, "%s%s%s%.*s\n", - stdout_mode ? "" : log_date(), - domain, *domain == 0 ? "" : ": ", - chomp_length(message), message); - - g_free(converted); + va_list ap; + va_start(ap, fmt); + LogFormatV(domain, level, fmt, ap); + va_end(ap); } -static void -log_init_stdout(void) +void +FormatDebug(const Domain &domain, const char *fmt, ...) { - g_log_set_default_handler(file_log_func, NULL); + va_list ap; + va_start(ap, fmt); + LogFormatV(domain, LogLevel::DEBUG, fmt, ap); + va_end(ap); } -static int -open_log_file(void) +void +FormatInfo(const Domain &domain, const char *fmt, ...) { - assert(!out_path.IsNull()); - - return OpenFile(out_path, O_CREAT | O_WRONLY | O_APPEND, 0666); + va_list ap; + va_start(ap, fmt); + LogFormatV(domain, LogLevel::INFO, fmt, ap); + va_end(ap); } -static bool -log_init_file(unsigned line, Error &error) +void +FormatWarning(const Domain &domain, const char *fmt, ...) { - assert(!out_path.IsNull()); - - out_fd = open_log_file(); - if (out_fd < 0) { - const std::string out_path_utf8 = out_path.ToUTF8(); - error.FormatErrno("failed to open log file \"%s\" (config line %u)", - out_path_utf8.c_str(), line); - return false; - } - - g_log_set_default_handler(file_log_func, NULL); - return true; + va_list ap; + va_start(ap, fmt); + LogFormatV(domain, LogLevel::WARNING, fmt, ap); + va_end(ap); } -#ifdef HAVE_SYSLOG - -static int -glib_to_syslog_level(GLogLevelFlags log_level) +void +FormatError(const Domain &domain, const char *fmt, ...) { - switch (log_level & G_LOG_LEVEL_MASK) { - case G_LOG_LEVEL_ERROR: - case G_LOG_LEVEL_CRITICAL: - return LOG_ERR; - - case G_LOG_LEVEL_WARNING: - return LOG_WARNING; - - case G_LOG_LEVEL_MESSAGE: - return LOG_NOTICE; - - case G_LOG_LEVEL_INFO: - return LOG_INFO; - - case G_LOG_LEVEL_DEBUG: - return LOG_DEBUG; - - default: - return LOG_NOTICE; - } + va_list ap; + va_start(ap, fmt); + LogFormatV(domain, LogLevel::ERROR, fmt, ap); + va_end(ap); } -static void -syslog_log_func(const gchar *domain, - GLogLevelFlags log_level, const gchar *message, - gcc_unused gpointer user_data) +void +LogError(const Error &error) { - if (stdout_mode) { - /* fall back to the file log function during - startup */ - file_log_func(domain, log_level, - message, user_data); - return; - } - - if (log_level > log_threshold) - return; - - if (domain == nullptr) - domain = ""; - - syslog(glib_to_syslog_level(log_level), "%s%s%.*s", - domain, *domain == 0 ? "" : ": ", - chomp_length(message), message); + Log(error.GetDomain(), LogLevel::ERROR, error.GetMessage()); } -static void -log_init_syslog(void) +void +LogError(const Error &error, const char *msg) { - assert(out_path.IsNull()); - - openlog(PACKAGE, 0, LOG_DAEMON); - g_log_set_default_handler(syslog_log_func, NULL); + LogFormat(error.GetDomain(), LogLevel::ERROR, "%s: %s", + msg, error.GetMessage()); } -#endif - -static inline GLogLevelFlags -parse_log_level(const char *value, unsigned line) +void +FormatError(const Error &error, const char *fmt, ...) { - if (0 == strcmp(value, "default")) - return G_LOG_LEVEL_MESSAGE; - if (0 == strcmp(value, "secure")) - return LOG_LEVEL_SECURE; - else if (0 == strcmp(value, "verbose")) - return G_LOG_LEVEL_DEBUG; - else { - FormatFatalError("unknown log level \"%s\" at line %u", - value, line); - return G_LOG_LEVEL_MESSAGE; - } + char msg[1024]; + va_list ap; + va_start(ap, fmt); + vsnprintf(msg, sizeof(msg), fmt, ap); + va_end(ap); + + LogError(error, msg); } void -log_early_init(bool verbose) +LogErrno(const Domain &domain, int e, const char *msg) { - if (verbose) - log_threshold = G_LOG_LEVEL_DEBUG; - - log_init_stdout(); + LogFormat(domain, LogLevel::ERROR, "%s: %s", msg, g_strerror(e)); } -bool -log_init(bool verbose, bool use_stdout, Error &error) +void +LogErrno(const Domain &domain, const char *msg) { - const struct config_param *param; - - g_get_charset(&log_charset); - - if (verbose) - log_threshold = G_LOG_LEVEL_DEBUG; - else if ((param = config_get_param(CONF_LOG_LEVEL)) != NULL) - log_threshold = parse_log_level(param->value, param->line); - - if (use_stdout) { - log_init_stdout(); - return true; - } else { - param = config_get_param(CONF_LOG_FILE); - if (param == NULL) { -#ifdef HAVE_SYSLOG - /* no configuration: default to syslog (if - available) */ - log_init_syslog(); - return true; -#else - error.Set(log_domain, - "config parameter 'log_file' not found"); - return false; -#endif -#ifdef HAVE_SYSLOG - } else if (strcmp(param->value, "syslog") == 0) { - log_init_syslog(); - return true; -#endif - } else { - out_path = config_get_path(CONF_LOG_FILE, error); - return !out_path.IsNull() && - log_init_file(param->line, error); - } - } + LogErrno(domain, errno, msg); } static void -close_log_files(void) +FormatErrnoV(const Domain &domain, int e, const char *fmt, va_list ap) { - if (stdout_mode) - return; + char msg[1024]; + vsnprintf(msg, sizeof(msg), fmt, ap); -#ifdef HAVE_SYSLOG - if (out_path.IsNull()) - closelog(); -#endif + LogErrno(domain, e, msg); } void -log_deinit(void) +FormatErrno(const Domain &domain, int e, const char *fmt, ...) { - close_log_files(); - out_path = Path::Null(); + va_list ap; + va_start(ap, fmt); + FormatErrnoV(domain, e, fmt, ap); + va_end(ap); } - -void setup_log_output(bool use_stdout) -{ - fflush(NULL); - if (!use_stdout) { -#ifndef WIN32 - if (out_path.IsNull()) - out_fd = open("/dev/null", O_WRONLY); -#endif - - if (out_fd >= 0) { - redirect_logs(out_fd); - close(out_fd); - } - - stdout_mode = false; - log_charset = NULL; - } -} - -int cycle_log_files(void) +void +FormatErrno(const Domain &domain, const char *fmt, ...) { - int fd; - - if (stdout_mode || out_path.IsNull()) - return 0; - - assert(!out_path.IsNull()); - - g_debug("Cycling log files...\n"); - close_log_files(); - - fd = open_log_file(); - if (fd < 0) { - const std::string out_path_utf8 = out_path.ToUTF8(); - g_warning("error re-opening log file: %s", - out_path_utf8.c_str()); - return -1; - } + const int e = errno; - redirect_logs(fd); - g_debug("Done cycling log files\n"); - return 0; + va_list ap; + va_start(ap, fmt); + FormatErrnoV(domain, e, fmt, ap); + va_end(ap); } -- cgit v1.2.3