Log4cpp是一个开源的C++类库,它提供了C++程序中使用日志和跟踪调试的功能,它的优点如下:
提供应用程序运行上下文,方便跟踪调试;
可扩展的、多种方式记录日志,包括命令行、文件、回卷文件、内存、syslog服务器、Win事件日志等;
可以动态控制日志记录级别,在效率和功能中进行调整;
所有配置可以通过配置文件进行动态调整;
多语言支持,包括Java(log4j),C++(log4cpp、log4cplus),C(log4c),python(log4p)等;
Log4cpp有三个主要的组件:日志类别(Category)、输出源(Appender)和布局(Layout)。这三种类型的组件一起工作使得系统可以根据信息的类型和级别记录它们,并且在运行时控制这些信息的输出格式和位置。
三个组件的介绍:
1)日志类别(Category)含义是:如果配置文件中设置的级别是DEBUG,则任意的log都能打印出来;但如果配置的级别是ERROR,则只有高于ERROR优先级的日志才可以打印出来。
日志的常用优先级:DEBUG < INFO < WARN < ERROR < FATAL
2)输出源(Appender)用来输出日志(被layout格式化后)到一些设备上,比如文件、命令行、内存等。也可以定义自己的appender输出日志信息到别的设备上。log4cpp提供的appender如下:
FileAppender 输出到文件
RollingFileAppender 输出到回卷文件,即当文件到达某个大小后回卷
ConsoleAppender 输出到控制台
3)布局(Layout):显示样式PatternLayout表示让用户根据类似于C语言printf函数的转换模式来指定输出格式
三个组件之间的关系:
Category和Appender的关系是:多个Appender可以附加到一个Category上,这样一个日志消息可以同时输出到多个设备上。
Appender和Layout的关系是:Layout附加在Appender上,appender调用layout处理完日志消息后,记录到某个设备上。
内容如下:
#-------定义rootCategory的属性-------
#指定rootCategory的log优先级是ERROR,其Appenders有两个,分别是console,TESTAppender
log4cpp.rootCategory=ERROR, console,TESTAppender
#-------定义console属性-------
#consoleAppender类型:控制台输出
#下面这三条语句表示控制台输出的log输出的布局按照指定的格式;输出格式是:[%p] %d{%H:%M:%S.%l} (%c): %m%n
log4cpp.appender.console=ConsoleAppender
log4cpp.appender.console.layout=PatternLayout
log4cpp.appender.console.layout.ConversionPattern=[%p] %d{%H:%M:%S.%l} (%c): %m%n
#-------定义TESTAppender的属性-------
#RollingFileAppender类型:输出到回卷文件,即文件到达某个大小的时候产生一个新的文件
#下面的语句表示文件输出到指定的log文件,输出的布局按照指定的格式,输出的格式是:[%d{%Y-%m-%d %H:%M:%S.%l} - %p] (%c): %m%n
log4cpp.appender.TESTAppender=RollingFileAppender
#当日志文件到达maxFileSize大小时,将会自动滚动
log4cpp.appender.TESTAppender.maxFileSize=400000
#maxBackupIndex指定可以产生的滚动文件的最大数
log4cpp.appender.TESTAppender.maxBackupIndex=3
#fileName指定信息输出到logs/TESTAppender.txt文件
log4cpp.appender.TESTAppender.fileName=logs/TESTAppender.txt
#PatternLayout 表示可以灵活指定布局模式
log4cpp.appender.TESTAppender.layout=PatternLayout
#append=true 信息追加到上面指定的日志文件中,false表示将信息覆盖指定文件内容
log4cpp.appender.TESTAppender.append=true
log4cpp.appender.TESTAppender.layout.ConversionPattern=[%d{%Y-%m-%d %H:%M:%S.%l} - %p] (%c): %m%n
ConversionPattern的参数含义:
%d (datetime)输出日志时间点的日期或时间,可以在其后指定格式,如上%d{%Y-%m-%d %H:%M:%S.%l},输出类似:2017-02-14 09:25:00.953
%p (priority)优先级,即DEBUG,INFO,WARN,ERROR,FATAL
%c (category)输出日志信息所属的类目,通常就是所在类的全名
%m (message)输出log的具体信息
%n (nextline)回车换行
在问题定位的过程中,有时由于设置的日志级别较高,打印出来的信息不够全面,因此需要通过修改配置文件来动态调整日志级别,即修改属性值log4cpp.rootCategory=ERROR 为 log4cpp.rootCategory=DEBUG 这样就可以看到最新的DEBUG级别以上的日志信息了。
补充:
如何改变layout格式呢?
首先回顾一下HelloWorld的日志格式,它使用了最简单的BasicLayout:
1248337987 ERROR : Hello log4cpp in a Error Message!
1248337987 WARN : Hello log4cpp in a Warning Message!
上面的日志格式还可以,但显然不是许多程序员心中理想的格式,许多人理想的格式应该是这样的:
2009-07-24 15:59:55,703: INFO infoCategory : system is running
2009-07-24 15:59:55,703: WARN infoCategory : system has a warning
2009-07-24 15:59:55,703: ERROR infoCategory : system has a error, can't find a file
2009-07-24 15:59:55,718: FATAL infoCategory : system has a fatal error, must be shutdown
2009-07-24 15:59:55,718: INFO infoCategory : system shutdown, you can find some information in system log
要获得上面的格式,必须使用比BasicLayout复杂的PatternLayout,而且要花一个小时来熟悉一下PatternLayout的格式定义方式,如果你认为值得的话。
PatternLayout
在介绍PatternLayout以前,首先来看看log4cpp中所有的Layout子类(Layout本身是个虚类),一共三个:BasicLayout、PatternLayout和SimpleLayout,其中SimpleLayout并不建议使用,而BaiscLayout过于简单,因此如果程序员不自己扩展Layout的话,就只能使用PatternLayout了,值得庆幸的是,PatternLayout还是比较好用的。
PatternLayout使用setConversionPattern函数来设置日志的输出格式。该函数的声明如下:
void log4cpp::PatternLayout::setConversionPattern ( const std::string & conversionPattern ) throw (ConfigureFailure) [virtual]
其中参数类型为std::string,类似于C语言中的printf,使用格式化字符串来描述输出格式,其具体含义如下:
(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"等等。
因此,要得到上述的理想格式,可以将setConversionPattern的参数设置为“%d: %p %c %x: %m%n”,其具体含义是“时间: 优先级 Category NDC: 消息 换行”。使用PatternLayout的例子程序如下,项目名称是LayoutExam:
#include <iostream>
#include <log4cpp/Category.hh>
#include <log4cpp/OstreamAppender.hh>
#include <log4cpp/Priority.hh>
#include <log4cpp/PatternLayout.hh>
using namespace std;
int main(int argc, char* argv[])
{
log4cpp::OstreamAppender* osAppender = new log4cpp::OstreamAppender("osAppender", &cout);
log4cpp::PatternLayout* pLayout = new log4cpp::PatternLayout();
pLayout->setConversionPattern("%d: %p %c %x: %m%n");
osAppender->setLayout(pLayout);
log4cpp::Category& root = log4cpp::Category::getRoot();
log4cpp::Category& infoCategory = root.getInstance("infoCategory");
infoCategory.addAppender(osAppender);
infoCategory.setPriority(log4cpp::Priority::INFO);
infoCategory.info("system is running");
infoCategory.warn("system has a warning");
infoCategory.error("system has a error, can't find a file");
infoCategory.fatal("system has a fatal error,must be shutdown");
infoCategory.info("system shutdown,you can find some information in system log");
log4cpp::Category::shutdown();
return 0;
}
其运行结果即如下所示:
2009-07-24 15:59:55,703: INFO infoCategory : system is running
2009-07-24 15:59:55,703: WARN infoCategory : system has a warning
2009-07-24 15:59:55,703: ERROR infoCategory : system has a error, can't find a file
2009-07-24 15:59:55,718: FATAL infoCategory : system has a fatal error, must be shutdown
2009-07-24 15:59:55,718: INFO infoCategory : system shutdown, you can find some information in system log