Each .c file that want to use spice logging must include common/log.h and define its subdomain with SPICE_LOG_SUBDOMAIN_STATIC (name) helper. This static variable is initialized in its first use depending on SPICE_DEBUG env var. examples: - debug level for all subdomains export SPICE_DEBUG=6 export SPICE_DEBUG=*:debug export SPICE_DEBUG=*:* - only debug audio subdomain export SPICE_DEBUG=*:-,audio:* export SPICE_DEBUG=*:none,audio:debug - warn or worse for everything, debug usb export SPICE_DEBUG=*:warning,usb:* export SPICE_DEBUG=3,usb:debug --- common/log.c | 164 +++++++++++++++++++++++++++++++++++++++++++++++++++++++---- common/log.h | 21 +++++++- 2 files changed, 173 insertions(+), 12 deletions(-) diff --git a/common/log.c b/common/log.c index 9c2f2b2..5dcb4e7 100644 --- a/common/log.c +++ b/common/log.c @@ -23,6 +23,8 @@ #include <stdlib.h> #include <stdio.h> #include <sys/types.h> +#include <string.h> +#include <errno.h> #ifndef _MSC_VER #include <unistd.h> #endif @@ -30,9 +32,18 @@ #include "log.h" #include "backtrace.h" +const gchar *spice_debug_env = NULL; + static int glib_debug_level = 0; static int abort_level = -1; +static gchar *level2name[SPICE_LOG_NUM_LEVELS] = { + "none", "error", "critical", "warning", "message", "info", "debug" +}; + +#define SPICE_DOMAIN_STR_ALL "*" +#define SPICE_DOMAIN_STR_NONE "-" + #ifndef SPICE_ABORT_LEVEL_DEFAULT #ifdef SPICE_DISABLE_ABORT #define SPICE_ABORT_LEVEL_DEFAULT -1 @@ -117,33 +128,161 @@ static void spice_log_set_abort_level(void) } } +static SpiceLogLevel domain_get_level_from_spec_str(const gchar *level_spec) +{ + guint i; + long int level_num; + char *tail; + + /* "-" or "none" (from level2name) can be used to disable all logging */ + if (strcmp(level_spec, SPICE_DOMAIN_STR_NONE) == 0) { + return SPICE_LOG_LEVEL_NONE; + } + + /* '*' means everything */ + if (strcmp(level_spec, SPICE_DOMAIN_STR_ALL) == 0) { + return SPICE_LOG_NUM_LEVELS - 1; + } + + errno = 0; + level_num = strtol(level_spec, &tail, 0); + if (!errno && + tail != level_spec && + level_num >= SPICE_LOG_LEVEL_NONE && + level_num < SPICE_LOG_NUM_LEVELS) + return (SpiceLogLevel) level_num; + + /* match level by name */ + for (i = 0; i < SPICE_LOG_NUM_LEVELS; i++) + if (g_ascii_strcasecmp(level_spec, level2name[i]) == 0) + return i; + + /* If the spec does not match one of our levels, just return the current + * default log level */ + return glib_debug_level; +} + +static SpiceLogLevel domain_get_level_from_numeric_str(const gchar *str) +{ + /* Try for backwards compatiblity */ + char *tail; + long int level_num = SPICE_LOG_NUM_LEVELS; + + level_num = strtol(str, &tail, 0); + if (level_num >= SPICE_LOG_LEVEL_NONE + && level_num < SPICE_LOG_NUM_LEVELS) { + return (SpiceLogLevel) level_num; + } + + return glib_debug_level; +} + +/* Look by @domain in SPICE_DEBUG and returns its level */ +static SpiceLogLevel domain_get_domain_level_from_env(const gchar *domain_name) +{ + gchar **pairs; + gchar **pair; + + if (spice_debug_env == NULL || domain_name == NULL) { + return glib_debug_level; + } + + pair = pairs = g_strsplit(spice_debug_env, ",", 0); + + while (*pair) { + SpiceLogSubDomain *domain; + gchar **info; + + /* [0] is the domain and [1] the domain's level */ + info = g_strsplit(*pair, ":", 2); + if (info[0] && info[1]) { + if (g_strcmp0(domain_name, info[0]) == 0) { + SpiceLogLevel level = domain_get_level_from_spec_str(info[1]); + g_strfreev(info); + g_strfreev(pairs); + return level; + } + g_strfreev(info); + } else { + if (strcmp(domain_name, SPICE_DOMAIN_STR_ALL) == 0) { + /* Backwards compatibility for SPICE_DEBUG=<log-level> */ + SpiceLogLevel level = domain_get_level_from_numeric_str(*pair); + g_strfreev(info); + g_strfreev(pairs); + return level; + } + g_strfreev(info); + } + + pair++; + } + + g_strfreev(pairs); + return glib_debug_level; +} + +static void domain_init(void) +{ + const gchar *messages_env; + + spice_debug_env = g_getenv("SPICE_DEBUG"); + if (spice_debug_env == NULL) { + return; + } + + glib_debug_level = domain_get_domain_level_from_env(SPICE_DOMAIN_STR_ALL); + + /* Add Spice log domain to G_MESSAGES_DEBUG, so the messages are not + * filtered by default handler */ + messages_env = g_getenv ("G_MESSAGES_DEBUG"); + if (!messages_env) { + g_setenv ("G_MESSAGES_DEBUG", SPICE_LOG_DOMAIN, FALSE); + } else if (g_strcmp0 (messages_env, "all") != 0) { + gchar *new_messages_env; + new_messages_env = g_strconcat (messages_env, ":" SPICE_LOG_DOMAIN, NULL); + g_setenv ("G_MESSAGES_DEBUG", new_messages_env, TRUE); + g_free (new_messages_env); + } +} + +static void domain_set_domain_level(SpiceLogSubDomain *domain) +{ + if (domain == NULL || domain->initialized == TRUE) { + return; + } + + domain->initialized = TRUE; + domain->log_level = domain_get_domain_level_from_env(domain->name); + spice_debug ("Domain: %s, Level: %s", domain->name, + level2name[domain->log_level]); +} + 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 - } g_log_default_handler(log_domain, log_level, message, NULL); } -static inline void spice_log_init_once(void) +static void spice_log_init_once(SpiceLogSubDomain *domain) { static gsize logging_initialized = FALSE; if (g_once_init_enter(&logging_initialized)) { spice_log_set_debug_level(); spice_log_set_abort_level(); + domain_init(); 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); } + + domain_set_domain_level(domain); } -static void spice_logv(const char *log_domain, +static void spice_logv(SpiceLogSubDomain *domain, SpiceLogLevel log_level, const char *strloc, const char *function, @@ -152,10 +291,14 @@ static void spice_logv(const char *log_domain, { GString *log_msg; - spice_log_init_once(); + spice_log_init_once(domain); g_return_if_fail(spice_log_level_to_glib(log_level) != 0); + if (domain->log_level < log_level) { + return; + } + log_msg = g_string_new(NULL); if (strloc && function) { g_string_append_printf(log_msg, "%s:%s: ", strloc, function); @@ -163,7 +306,8 @@ static void spice_logv(const char *log_domain, if (format) { g_string_append_vprintf(log_msg, format, args); } - g_log(log_domain, spice_log_level_to_glib(log_level), "%s", log_msg->str); + g_log(SPICE_LOG_DOMAIN, spice_log_level_to_glib(log_level), + "[%s] %s", domain->name, log_msg->str); g_string_free(log_msg, TRUE); if (abort_level != -1 && abort_level >= (int) log_level) { @@ -172,7 +316,7 @@ static void spice_logv(const char *log_domain, } } -void spice_log(const char *log_domain, +void spice_log(SpiceLogSubDomain *domain, SpiceLogLevel log_level, const char *strloc, const char *function, @@ -182,6 +326,6 @@ void spice_log(const char *log_domain, va_list args; va_start (args, format); - spice_logv (log_domain, log_level, strloc, function, format, args); + spice_logv (domain, log_level, strloc, function, format, args); va_end (args); } diff --git a/common/log.h b/common/log.h index 68f6a24..64e6377 100644 --- a/common/log.h +++ b/common/log.h @@ -44,7 +44,24 @@ typedef enum { SPICE_LOG_NUM_LEVELS } SpiceLogLevel; -void spice_log(const char *log_domain, + +typedef struct _SpiceLogSubDomain SpiceLogSubDomain; +typedef SpiceLogSubDomain *SpiceLogSubDomainPtr; + +struct _SpiceLogSubDomain { + const gchar *name; + SpiceLogLevel log_level; + gboolean initialized; +}; + +#define SPICE_LOG_DOMAIN_STATIC(n) \ + static SPICE_GNUC_UNUSED SpiceLogSubDomain SPICE_LOG_SUB_DOMAIN = { \ + .name = "" n "", \ + .log_level = SPICE_LOG_LEVEL_ERROR, \ + .initialized = FALSE, \ + }; + +void spice_log(SpiceLogSubDomainPtr subdomain, SpiceLogLevel log_level, const char *strloc, const char *function, @@ -53,7 +70,7 @@ void spice_log(const char *log_domain, #define SPICE_LOG(level, format, ...) G_STMT_START { \ - spice_log(SPICE_LOG_DOMAIN, \ + spice_log(&SPICE_LOG_SUB_DOMAIN, \ (level), \ SPICE_STRLOC, \ G_STRFUNC, \ -- 2.5.0 _______________________________________________ Spice-devel mailing list Spice-devel@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/spice-devel