需求

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_MASKLOG_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 版本的时候,会输出警告,错误等日志,并且只有简单的日志,没有行号之类的内部信息。

参考

syslog日志介绍

setlogmask(int mask)函数讲解

C++ 或 QT 判断当前模式是Debug还是Release模式

利用syslog函数,将日志写入自己指定的文件