用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);