前段时间的一个C#项目我用了log4net,感觉不错。最近开了个新坑,对于服务器来说,日志是必不可少的组件,当然不仅仅是服务端程序,在大多数客户端程序上也需要用日志来记录用户的一些行为以及操作过程。除了为.net准备的log4net之外,类似的开源日志库其实还有log4j, log4cxx, log4cpp,log4cplus, glog等,还有为C语言准备的log4c,为python准备的log4p,以及最原始的log4j。对于C++系列的几个,估计有人会困扰应该选哪个,因此我在这里做一个归纳:
log4cxx:Apache的产品,属于apache的子项目之一,由log4j移植过来的。移植过来的东西多数都有一个特点,那就是要依赖各种碗糕。log4cxx就需要依赖apr-utils,编译起来没那么直接,因此我放弃了它。
log4cpp:感觉上log4cpp和log4cplus大同小异,支持的功能也类似。上上一次更新是在2007年,不过在时隔五年之后的去年年底(2012年),它突然又更新了, 从1.0版提升到了1.1版,有点不容易,感觉诈尸了。另外,它也是由log4j移植过来的。
log4cplus:log4cplus究竟和log4cpp区别在哪,如果一定要作对比似乎log4cplus比log4cpp复杂了那么一点点。log4cplus的功能比log4cpp支持的功能更加全面,支持线程安全(log4cpp的代码里也做了一些对线程安全的保证,但官方没有介绍它支持线程安全,反而log4cplus宣称自己是线程安全的),另外log4plus更新非常频繁,对于一个有版本洁癖的人来说,这也是我选择它的原因,新版本提供了vc10的解决方案,还支持可选编译Unicode和非Unicode版本。
glog:这个就不介绍了,全称Google Glog, Google的东西一直比较让人放心。它比log4系列的库都要简单,不过它不支持用配置文件控制日志行为,这对我来说是个遗憾。
log4系列的库前身都是log4j,log4j真是深藏功与名。以下通过log4plus来介绍一下它的基本用法和魅力。
log4plus基本用法
log4cplus用了properties配置文件对日志行为进行配置,从java移植过来的东西,用properties文件作为配置不奇怪。它的格式基本上是key=value,一项占一行,以#号作为注释的开始。
我的新坑项目有客户端和服务端,当我们想为两边配置不同的日志输出格式时,就需要用到了log4plus提供的appender概念。在定义appender之前,需要先为client和server配置logger对象。完整的配置如下:
log4cplus.logger.SERVER_LOGGER=DEBUG, ServerAppender
log4cplus.logger.CLIENT_LOGGER=DEBUG, ClientAppender
#server appender configuration
log4cplus.appender.ServerAppender=log4cplus::ConsoleAppender
log4cplus.appender.ServerAppender.layout=log4cplus::PatternLayout
log4cplus.appender.ServerAppender.layout.ConversionPattern=%d[%m/%d/%y %H:%M:%S] [%t] %-5p %c - %m %n
#client appender configuration
log4cplus.appender.ClientAppender=log4cplus::ConsoleAppender
log4cplus.appender.ClientAppender.layout=log4cplus::PatternLayout
log4cplus.appender.ClientAppender.layout.ConversionPattern=%d[%m/%d/%y %H:%M:%S] [%t] %-5p %c - %m %n
前面两行是定义了两个Logger对象,对象名分别是SERVER_LOG和CLIENT_LOGGER。在编写程序的时候,可以通过getInstance方法来取得Logger对象。右边的是Logger对象的值,DEBUG表示日志的级别,而用逗号隔开的右边的是与改Logger对象绑定的Appender。定义Logger对象的格式如下:
log4cplus.logger.LoggerName=LogLevel, AppenderName
接下来的内容就是定义Appender,所谓的appender其实是用于定义日志的输出媒介与各种参数。其中log4cplus::ConsoleAppender定义了由控制台输出。layout对象用于描述Appender的输出格式,而Appender就是输出类型。log4plus支持多种输出渠道,而且可以同时在配置中定义,比如:通过控制台,日志文件,VC的DEBUG窗口,网络(SOCKET)等方式。此处以控制台为例。定义格式如下:
log4cplus.appender.AppenderName=log4cplus::ConsoleAppender
log4cplus.appender.AppenderName.layout=log4cplus::PatternLayout
log4cplus.appender.AppenderName.layout.ConversionPattern=%pattern
这里要注意的是,不同的Appender有不同的layout参数可配置,比如说如果你用了文件输出方式的Appender(FileAppender / RollingFileAppender / DailyRollingFileAppender),那么就会有filename等类似配置项。
写完配置文件,那就应该在代码中把它搞起来。log4plus提供了一些很简单的调用方法,代码如下:
log4cplus::initialize();
PropertyConfigurator::doConfigure(LOG4CPLUS_TEXT("log4cplus.properties.conf"));
Logger
serverLogger = Logger::getInstance(LOG4CPLUS_TEXT("SERVER_LOG"));
Logger
clientLogger = Logger::getInstance(LOG4CPLUS_TEXT("CLIENT_LOG"));
LOG4CPLUS_DEBUG(serverLogger,"server
log");
LOG4CPLUS_DEBUG(clientLogger
, "client
log");
代码很容易理解:
log4cplus::initialize()
初始化log4cplus环境,在初始化的时候调用一次即可。
PropertyConfigurator::doConfigure()
加载配置文件,也是调用一次即可。这里要注意根据你的是否是Unicode版本而使用LOG4CPLUS_TEXT宏。
Logger::getInstance()
获取一个Logger对象,该对象在配置中定义。唯一参数就是Logger对象的名称。获取成功的话会返回一个Logger类的实例。
LOG4CPLUS_DEBUG()
是个宏,根据所获得的Logger对象输出一行DEBUG日志,类似的还有LOG4CPLUS_INFO, LOG4CPLUS_WARN, LOG4CPLUS_ERROR等。
附录
一、日志内容转义符(Pattern)
(1)”%%”,转义为% 。
(2)”%c”,输出logger名称,如test.subtest 。也可以控制logger名称的显示层次,比如”%c{1}”时输出”test”,其中数字表示层次。
(3)”%D”,显示本地时间,比如:”2004-10-16 18:55:45″,%d显示标准时间。
可以通过%d{…}定义更详细的显示格式,比如%d{%H:%M:%s}表示要显示小时:分钟:秒。大括号中可显示的预定义标识符如下:
%a — 表示礼拜几,英文缩写形式,比如”Fri”
%A — 表示礼拜几,比如”Friday”
%b — 表示几月份,英文缩写形式,比如”Oct”
%B — 表示几月份,”October”
%c — 标准的日期+时间格式,如 “Sat Oct 16 18:56:19 2004″
%d — 表示今天是这个月的几号(1-31)”16″
%H — 表示当前时刻是几时(0-23),如 “18″
%I — 表示当前时刻是几时(1-12),如 “6″
%j — 表示今天是哪一天(1-366),如 “290″
%m — 表示本月是哪一月(1-12),如 “10″
%M — 表示当前时刻是哪一分钟(0-59),如 “59″
%p — 表示现在是上午还是下午, AM or PM
%q — 表示当前时刻中毫秒部分(0-999),如 “237″
%Q — 表示当前时刻中带小数的毫秒部分(0-999.999),如 “430.732″
%S — 表示当前时刻的多少秒(0-59),如 “32″
%U — 表示本周是今年的第几个礼拜,以周日为第一天开始计算(0-53),如 “41″
%w — 表示礼拜几,(0-6, 礼拜天为0),如 “6″
%W — 表示本周是今年的第几个礼拜,以周一为第一天开始计算(0-53),如 “41″
%x — 标准的日期格式,如 “10/16/04″
%X — 标准的时间格式,如 “19:02:34″
%y — 两位数的年份(0-99),如 “04″
%Y — 四位数的年份,如 “2004″
%Z — 时区名,比如 “GMT”
(4)”%F”,输出当前记录器所在的文件名称,比如”main.cpp”
(5)”%L”,输出当前记录器所在的文件行号,比如”51″
(6)”%l”,输出当前记录器所在的文件名称和行号,比如”main.cpp:51″
(7)”%m”,输出原始信息。
(8)”%n”,换行符。
(9)”%p”,输出LogLevel,比如”DEBUG”
(10)”%t”,输出记录器所在的线程ID,比如 “1075298944″
(11)”%x”,嵌套诊断上下文NDC (nested diagnostic context) 输出,从堆栈中弹出上下文信息,NDC可以用对不同源的log信息(同时地)交叉输出进行区分。
(12)格式对齐,比如”%-10m”时表示左对齐,宽度是10,当然其它的控制字符也可以相同的方式来使用,比如”%-12d”,”%-5p”等等。
二、Appender类型
(1)控制台输出
ConsoleAppender
(2)文件输出
FileAppender / RollingFileAppender / DailyRollingFileAppender