为什么有这篇文章(what)
前面曾经写过两篇文章关于boost::logger的。 当时只是想学习一下怎么使用boost::logger。 前两天再次看到这个rep。想再完善一下这个rep, 用这篇文章记录一下过程和想法。
原来的rep有什么缺陷?(why)
- 在生产实践中,作为调试需求, log功能可能会被频繁的调用。原来的rep每次调用以后,虽然不会写到boost::log中,但是都已经组装好了log。在使用的时候,有的时候log会很大,IO操作很费时。经过profile,log竟然占到了一个程序的4%的CPU time(另一个rep做的测试),大多时间用在的IO上。
- 原来的rep的log interface扩展性不好。以后万一有xxxlog很难适配
- 之前的rep是以动态库的形式提供,如果想使用需要link动态库。所以动态库是部署的一部分。log作为一个简单的module,为什么不提供header only的module呢?
- 原来的rep loglevel并不是真的loglevel,而是函数名字。debug info 。。。这些名字实在是太普遍了,很容易和其他的命名冲突。
如何解决这些问题(how)
- 首先最急需解决的问题就是perfprmance的问题。
解决这个问题的原理很简单。那就是当loglevel大于等于设定的loglevel在准备打log。
所以我们要做的就是:
- check active_logger
- if loglevel equal or larger than current log level, then call the related log function
相应的代码也很简单,为了简单起见,我们定义一个宏:
#define CHECK_LOG_LEVEL(logLevel) ((active_logger && active_logger->get_log_level() <= log_level::logLevel##_level) ? true : false)
有了这个宏以后, 我们就可以这样打log了:
if (CHECK_LOG_LEVEL(error))
{
__LOG(error, "Out of Range error: " << oor.what());
}
- 扩展性问题
原来的rep把所有的sourece code都放到一个文件中了。为了解决这个问题。 把所有和interface相关的code抽出来放到一个单独的文件中。具体的实现放到另一个文件中。
- header only
为了实现header only, 有几个问题需要解决。
- active_logger作为一个全局变量,原来是在.cpp文件中定义,现在只能以static变量出现。
- active_logger是一个全局变量, 当它的使用者有不同的实现函数的话,无法同时支持。这个问题暂时没有很好的想法解决。但是这个并不影响我们实现header only。(这个问题应该不常出现,一般一个产品的log实现应该相同,如果真的要解决这个问题,可以通过不同的名字来区别)
- 命名冲突
解决这个问题要用到C语言的独特特性。
首先下面是log_level的定义
enum log_level
{
debug_level,
info_level,
warn_level,
error_level,
critical_level
};
我们使用了define的##用法:
#define SET_LOG_LEVEL(logLevel) \
{ \
if (active_logger) \
(active_logger->set_log_level(log_level::logLevel##_level)); \
}
这样就把debug展开为debug_level。