[Spice-devel] [spice-common v3 03/19] log: allow filtering logs with subdomains
Victor Toso
victortoso at redhat.com
Sat Mar 12 14:32:04 UTC 2016
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
More information about the Spice-devel
mailing list