diff options
Diffstat (limited to 'common/log.c')
-rw-r--r-- | common/log.c | 165 |
1 files changed, 112 insertions, 53 deletions
diff --git a/common/log.c b/common/log.c index df394d2..607aa82 100644 --- a/common/log.c +++ b/common/log.c @@ -1,5 +1,5 @@ /* - Copyright (C) 2012 Red Hat, Inc. + Copyright (C) 2012-2015 Red Hat, Inc. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -19,6 +19,7 @@ #include <config.h> #endif +#include <glib.h> #include <stdlib.h> #include <stdio.h> #include <sys/types.h> @@ -29,37 +30,9 @@ #include "log.h" #include "backtrace.h" -static int debug_level = -1; +static int glib_debug_level = 0; static int abort_level = -1; -static const char * spice_log_level_to_string(SpiceLogLevel level) -{ -#ifdef _MSC_VER - /* MSVC++ does not implement C99 */ - static const char *to_string[] = { - "ERROR", - "CRITICAL", - "Warning", - "Info", - "Debug"}; -#else - static const char *to_string[] = { - [ SPICE_LOG_LEVEL_ERROR ] = "ERROR", - [ SPICE_LOG_LEVEL_CRITICAL ] = "CRITICAL", - [ SPICE_LOG_LEVEL_WARNING ] = "Warning", - [ SPICE_LOG_LEVEL_INFO ] = "Info", - [ SPICE_LOG_LEVEL_DEBUG ] = "Debug", - }; -#endif - const char *str = NULL; - - if (level < SPICE_N_ELEMENTS(to_string)) { - str = to_string[level]; - } - - return str; -} - #ifndef SPICE_ABORT_LEVEL_DEFAULT #ifdef SPICE_DISABLE_ABORT #define SPICE_ABORT_LEVEL_DEFAULT -1 @@ -68,41 +41,127 @@ static const char * spice_log_level_to_string(SpiceLogLevel level) #endif #endif -void spice_logv(const char *log_domain, - SpiceLogLevel log_level, - const char *strloc, - const char *function, - const char *format, - va_list args) +static GLogLevelFlags spice_log_level_to_glib(SpiceLogLevel level) { - const char *level = spice_log_level_to_string(log_level); + static GLogLevelFlags glib_levels[] = { + [ SPICE_LOG_LEVEL_ERROR ] = G_LOG_LEVEL_ERROR, + [ SPICE_LOG_LEVEL_CRITICAL ] = G_LOG_LEVEL_CRITICAL, + [ SPICE_LOG_LEVEL_WARNING ] = G_LOG_LEVEL_WARNING, + [ SPICE_LOG_LEVEL_INFO ] = G_LOG_LEVEL_INFO, + [ SPICE_LOG_LEVEL_DEBUG ] = G_LOG_LEVEL_DEBUG, + }; + g_return_val_if_fail ((level >= 0) || (level < G_N_ELEMENTS(glib_levels)), 0); + + return glib_levels[level]; +} - if (debug_level == -1) { - debug_level = getenv("SPICE_DEBUG_LEVEL") ? atoi(getenv("SPICE_DEBUG_LEVEL")) : SPICE_LOG_LEVEL_WARNING; +static void spice_log_set_debug_level(void) +{ + if (glib_debug_level == 0) { + char *debug_str = getenv("SPICE_DEBUG_LEVEL"); + if (debug_str != NULL) { + int debug_level; + char *debug_env; + + /* FIXME: To be removed after enough deprecation time */ + g_warning("Setting SPICE_DEBUG_LEVEL is deprecated, use G_MESSAGES_DEBUG instead"); + debug_level = atoi(debug_str); + glib_debug_level = spice_log_level_to_glib(debug_level); + + /* If the debug level is too high, make sure we don't try to enable + * display of glib debug logs */ + if (debug_level < SPICE_LOG_LEVEL_INFO) + return; + + /* Make sure GLib default log handler will show the debug messages. Messing with + * environment variables like this is ugly, but this only happens when the legacy + * SPICE_DEBUG_LEVEL is used + */ + debug_env = (char *)g_getenv("G_MESSAGES_DEBUG"); + if (debug_env == NULL) { + g_setenv("G_MESSAGES_DEBUG", SPICE_LOG_DOMAIN, FALSE); + } else { + debug_env = g_strconcat(debug_env, ":", SPICE_LOG_DOMAIN, NULL); + g_setenv("G_MESSAGES_DEBUG", SPICE_LOG_DOMAIN, FALSE); + g_free(debug_env); + } + } } +} + +static void spice_log_set_abort_level(void) +{ if (abort_level == -1) { - abort_level = getenv("SPICE_ABORT_LEVEL") ? atoi(getenv("SPICE_ABORT_LEVEL")) : SPICE_ABORT_LEVEL_DEFAULT; + char *abort_str = getenv("SPICE_ABORT_LEVEL"); + if (abort_str != NULL) { + GLogLevelFlags glib_abort_level; + + /* FIXME: To be removed after enough deprecation time */ + g_warning("Setting SPICE_ABORT_LEVEL is deprecated, use G_DEBUG instead"); + abort_level = atoi(abort_str); + glib_abort_level = spice_log_level_to_glib(abort_level); + if (glib_abort_level != 0) { + unsigned int fatal_mask = G_LOG_FATAL_MASK; + while (glib_abort_level >= G_LOG_LEVEL_ERROR) { + fatal_mask |= glib_abort_level; + glib_abort_level >>= 1; + } + g_log_set_fatal_mask(SPICE_LOG_DOMAIN, fatal_mask); + } + } else { + abort_level = SPICE_ABORT_LEVEL_DEFAULT; + } } +} - if (debug_level < (int) log_level) - return; - - fprintf(stderr, "(%s:%d): ", getenv("_"), getpid()); - - if (log_domain) { - fprintf(stderr, "%s-", log_domain); +static void spice_logger(const gchar *log_domain, + GLogLevelFlags log_level, + const gchar *message, + gpointer user_data) +{ + if (glib_debug_level != 0) { + if ((log_level & G_LOG_LEVEL_MASK) > glib_debug_level) + return; // do not print anything } - if (level) { - fprintf(stderr, "%s **: ", level); + g_log_default_handler(log_domain, log_level, message, NULL); +} + +static inline void spice_log_init_once(void) +{ + static gsize logging_initialized = FALSE; + + if (g_once_init_enter(&logging_initialized)) { + spice_log_set_debug_level(); + spice_log_set_abort_level(); + g_once_init_leave (&logging_initialized, TRUE); + g_log_set_handler(SPICE_LOG_DOMAIN, + G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL | G_LOG_FLAG_RECURSION, + spice_logger, NULL); } +} + +static void spice_logv(const char *log_domain, + SpiceLogLevel log_level, + const char *strloc, + const char *function, + const char *format, + va_list args) +{ + GString *log_msg; + + spice_log_init_once(); + + g_return_if_fail(spice_log_level_to_glib(log_level) != 0); + + log_msg = g_string_new(NULL); if (strloc && function) { - fprintf(stderr, "%s:%s: ", strloc, function); + g_string_append_printf(log_msg, "%s:%s: ", strloc, function); } if (format) { - vfprintf(stderr, format, args); + g_string_append_vprintf(log_msg, format, args); } - - fprintf(stderr, "\n"); + g_log(log_domain, spice_log_level_to_glib(log_level), "%s", log_msg->str); + g_string_free(log_msg, TRUE); if (abort_level != -1 && abort_level >= (int) log_level) { spice_backtrace(); |