需求
syslog 虽然使用起来很方便,但是直接使用有几个问题:
- 虽然有日志信息,但是不够全面不方便定位
- 那么多的日志都混在一起,没有重点,调试时不方便
- debug 和 release 时,日志应该不一样。
解决
日志信息更丰富
syslog 可以使用 __FILE__
, __LINE__
, __FUNCTION
, 这几个来标识出当前的日志是在那个文件,第几行,哪个函数输出的。
syslog(LOG_DEBUG, "%s: %d: %s --> class construct", __FILE__, __LINE__, __FUNCTION__);
使用宏来开关日志
下面这个是普通替代的宏,可以用于开关日志.
#ifdef xxx
#define LOG(priority, format, ...) syslog(priority, format, ## __VA_ARGS__)
#else
#define LOG(priority, format, ...)
#endif
使用宏来减少输入
但是每条日志都要这样写,就太麻烦了,我们可以使用宏来解决这个问题:
#define LOG(priority, format, ...) syslog(priority, "%s: %d: %s --> "#format, __FILE__, __LINE__, __FUNCTION__, ## __VA_ARGS__)
LOG(LOG_DEBUG, "class construct");
上面这条宏,我们在使用时,不需要显式的写出相关的参数,宏展开的时候,会自动帮我们加上这些参数,日志会包含文件名,行号,函数名.
使用宏增加日志等级
当多条日志信息在一起的时候,比较难抓住重点,虽然可以使用搜索,但是终归没有那么方便。我们可以通过宏给日志消息里面附上对应的等级,也方便后期维护时使用脚本进行解析。
#define LOG(priority, format, ...) syslog(priority, "<"#priority "> %s: %d: %s --> "#format, __FILE__, __LINE__, __FUNCTION__, ## __VA_ARGS__)
只输出部分等级的日志
在 release 版本中,我们不希望暴露太多的内部消息,只需要给出警告、错误等消息即可。在 debug 版本中,我们希望能够暴露出更多的消息。我们可以通过 int setlogmask(int mask)
来控制输出的日志等级,使用 LOG_MASK
和
LOG_UPTO
具体设置输出等级。0 不输出, 1 输出。
bit7 | bit6 | bit5 | bit4 | bit3 | bit2 | bit1 | bit0 |
---|---|---|---|---|---|---|---|
LOG_DEBUG | LOG_INFO | LOG_NOTICE | LOG_WARNING | LOG_ERR | LOG_CRIT | LOG_ALERT | LOG_EMERG |
//pri 取值: LOG_DEBUG ~ LOG_EMERG
#define LOG_MASK(pri) (1 << (pri)) /* mask for one priority */
#define LOG_UPTO(pri) ((1 << ((pri)+1)) - 1) /* all priorities through pri */
上面的宏可以看出:
LOG_MASK
只是输出某个等级的日志LOG_UPTO
可以输出某个等级到LOG_EMERG
的所有日志。这个宏也很有意思,通过向左多移一位,然后减去 1,来获得右边低位都是 1.
所以我们只需要在程序的开始设定当前的等级即可,比如下面设置为只输出 LOG_WARNING
~ LOG_EMERG
的日志
setlogmask(LOG_UPTO(LOG_WARNING));
使用宏自动区分 debug 和 release
如果手动的根据版本来调整日志输出等级,可能会出错,我们可以通过宏自动切换相应版本的日志情况。
# ifdef QT_DEBUG
#define LOG_MASK_BUILD LOG_DEBUG
#define LOG(priority, format, ...) syslog(priority, "<"#priority "> %s: %d: %s --> "#format, __FILE__, __LINE__, __FUNCTION__, ## __VA_ARGS__)
# else
#define LOG_MASK_BUILD LOG_WARNING
#define LOG(priority, format, ...) syslog(priority, format, ## __VA_ARGS__)
# endif
上面这个宏,有如下的作用:
- 在 build debug 版本的时候,会输出所有日志,并且会附带等级,文件名,行号,函数名
- 在 build release 版本的时候,会输出警告,错误等日志,并且只有简单的日志,没有行号之类的内部信息。