用glib的时候,一直习惯用g_message, g_warning 这几个g_log 的 wrapper 函数,并且知道这些函数的输出是能通过一个handler进行额外处理的但是一直没实践过。
某个项目中需要记录程序的日志,而先前所有日志都是用g_log做的,于是需要把把g_log的输出保存到syslog中。我错误的以为,g_warning、g_error、g_critical和LOG_WARNING、LOG_ERR、LOG_CRIT是一一对应的,一查头文件,发现原来不是。
glib的log level是用bitmap实现的,其中最后两位是log level以外的标志位:
typedef enum { /* log flags */ G_LOG_FLAG_RECURSION = 1 << 0, G_LOG_FLAG_FATAL = 1 << 1, /* GLib log levels */ G_LOG_LEVEL_ERROR = 1 << 2, /* always fatal */ G_LOG_LEVEL_CRITICAL = 1 << 3, G_LOG_LEVEL_WARNING = 1 << 4, G_LOG_LEVEL_MESSAGE = 1 << 5, G_LOG_LEVEL_INFO = 1 << 6, G_LOG_LEVEL_DEBUG = 1 << 7, G_LOG_LEVEL_MASK = ~(G_LOG_FLAG_RECURSION | G_LOG_FLAG_FATAL) } GLogLevelFlags;
而syslog的level是用连续的整数实现的
#define LOG_EMERG 0 /* system is unusable */ #define LOG_ALERT 1 /* action must be taken immediately */ #define LOG_CRIT 2 /* critical conditions */ #define LOG_ERR 3 /* error conditions */ #define LOG_WARNING 4 /* warning conditions */ #define LOG_NOTICE 5 /* normal but significant condition */ #define LOG_INFO 6 /* informational */ #define LOG_DEBUG 7 /* debug-level messages */
于是它们之间需要一个映射,感觉如果用python会很简洁:
static const char * logger_prioritynames[] = { "emerg", "alert", "crit", "err", "warning", "notice", "info", "debug" }; static void log2file (const gchar *log_domain, GLogLevelFlags log_level, const gchar *message, gpointer user_data) { log_level &= ~(G_LOG_FLAG_RECURSION | G_LOG_FLAG_FATAL); int prority = LOG_WARNING; switch (log_level) { case G_LOG_LEVEL_ERROR: prority = LOG_CRIT; break; case G_LOG_LEVEL_CRITICAL: prority = LOG_ERR; break; case G_LOG_LEVEL_WARNING: prority = LOG_WARNING; break; case G_LOG_LEVEL_MESSAGE: prority = LOG_NOTICE; break; case G_LOG_LEVEL_INFO: prority = LOG_INFO; break; case G_LOG_LEVEL_DEBUG: prority = LOG_DEBUG; break; default: break; } assert (prority <= (sizeof (logger_prioritynames) / sizeof (logger_prioritynames[0]))); syslog (prority, "<%s> %s", logger_prioritynames[prority], message); }
最后,在初始化的时候给glib设置这个handler:
g_log_set_default_handler (log2file, NULL);