Log4cplus使用¶
1.1 简介
log4cplus是C++编写的开源日志系统,前身是java编写的log4j日志系统。log4cplus具有线程安全、灵活、以及多粒度控制的特点,通过将信息划分优先级使其可以面向程序调试、运行、测试、和维护等全生命周期; 你可以选择将信息输出到屏幕、文件、NT event log、甚至是远程服务器;通过指定策略对日志进行定期备份等等。
最新版本可以从"http://log4cplus.sourceforge.net"下载log4cplus-x.x.x。
1.2 LOG4CPLUS的安装
1.2.1 Linux下安装
①使用 tar xvzf log4cplus-x.x.x.tar.gz将log4cplus解压到当前目录。
②cd log4cplus-x.x.x进到log4cplus主目录下。
③执行当前目录下的./configure。
④然后通过make命令进行编译。
⑤通过make install命令进行安装。
⑥到此log4cplus已经在你的机器上安装完成,下面就可以使用了。
⑦特别说明,安装过程中最好使用root用户。
1.2.2 Windows下安装
不需要安装,有一个msvc6存放包括源代码和用例在内的开发工程(for VC6 only),使用之前请先编译"log4cplus_dll class"工程生成dll,或者编译"log4cplus_static class"工程生成lib。
1.3 使用前配置
1.3.1 Linux下的配置
确保你的Makefile中包含/usr/local/lib/liblog4cplus.a(静态库)或-llog4cplus(动态库)即可,头文件在/usr/local/include/log4cplus目录下。对于动态库而言,想要正常使用,还得将库安装路径加入到LD_LIBRARY_PATH中,一般可以这样做:以root身份登录,在/etc/ld.so.conf中加入安装路径,这里是/usr/local/lib,然后执行/sbin/ldconfig使设置生效即可。
1.3.2 Windows下的配置
将"log4cplus_dll class"工程或"log4cplus_static class"工程的dsp 文件插入到你的工程中,或者直接把两个工程编译生成的库以及头文件所在目录放到你的工程的搜索路径中,如果你使用静态库,请在你的工程中"project/setting/C++"的preprocessor definitions中加入LOG4CPLUS_STATIC。
1.4LOG4CPLUS构成要素简介
Layouts :布局器,控制输出消息的格式。
Appenders :挂接器,与布局器紧密配合,将特定格式的消息输出到所挂接的设备终端(如屏幕,文件等等)。
Logger :记录器,保存并跟踪对象日志信息变更的实体,当你需要对一个对象进行记录时,就需要生成一个logger。
Categories :分类器,层次化(hierarchy)的结构,用于对被记录信息的分类,层次中每一个节点维护一个logger的所有信息。
Priorities :优先权,包括TRACE, DEBUG, INFO, WARNING, ERROR, FATAL。
1.5 基本使用步骤
1. 实例化一个appender对象。
2. 实例化一个layout对象。
3. 将layout对象绑定(attach)到appender对象。
4. 实例化一个logger对象,调用静态函数:log4cplus::Logger::getInstance(“logger_name”)。
5. 将appender对象绑定(attach)到logger对象,如省略此步骤,标准输出(屏幕)appender对象会绑定到logger。
6. 设置logger的优先级,如省略此步骤,各种有限级的消息都将被记录。
1.6 三种控制输出格式的布局管理器
log4cplus通过布局器(Layouts)来控制输出的格式,log4cplus提供了三种类型的Layouts,分别是SimpleLayout、PatternLayout、和TTCCLayout。
1.6.1 SimpleLayout
是一种简单格式的布局器,在输出的原始信息之前加上LogLevel和一个"-",这里略。
1.6.2 PatternLayout
是一种有词法分析功能的模式布局器,一提起模式就会想起正则表达式,这里的模式和正则表达式类似,但是远比后者简单,能够对预定义的标识符(称为conversion specifiers)进行解析,转换成特定格式输出。通过填写特定格式的模式字符串"pattern",原始信息被包含到一堆有格式的信息当中,这就使得用户可以根据自身需要来定制显示内容。"pattern"可以包含普通字符串和预定义的标识符,其中:
(1)普通字符串,能够被直接显示的信息。
(2)预定义标识符,通过"%"与一个或多个字符共同构成预定义的标识符,能够产生出特定格式信息。
关于预定义标识符,log4cplus文档中提供了详细的格式说明,根据不同的pattern,各种消息格式使
用情况列举如下:
(1)"%%",转义为%, 即,std::string pattern = "%%" 时输出: "%"
(2)"%c",输出logger名称,比如std::string pattern ="%c" 时输出: "test_logger.subtest",也可以控制logger名称的显示层次,比如"%c{1}"时输出"test_logger",其中数字表示层次。
(3)"%D",显示本地时间,当std::string pattern ="%D" 时输出:"2004-10-16 18:55:45",%d显示标准时间,所以当std::string pattern ="%d" 时输出 "2004-10-16 10:55:45" (因为我们是东8区,差8个小时啊)。可以通过%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",输出当前记录器所在的文件名称,比如std::string pattern ="%F" 时输出: "main.cpp"
(5)"%L",输出当前记录器所在的文件行号,比如std::string pattern ="%L" 时输出: "51"
(6)"%l",输出当前记录器所在的文件名称和行号,比如std::string pattern ="%L" 时输出: "main.cpp:51"
(7)"%m",输出原始信息,比如std::string pattern ="%m" 时输出: "teststr",即上述代码中 LOG4CPLUS_DEBUG的第二个参数,这种实现机制可以确保原始信息被嵌入到带格式的信息中。
(8)"%n",换行符,没什么好解释的
(9)"%p",输出LogLevel,比如std::string pattern ="%p" 时输出: "DEBUG"
(10)"%t",输出记录器所在的线程ID,比如std::string pattern ="%t" 时输出: "1075298944"
(11)"%x",嵌套诊断上下文NDC (nested diagnostic context) 输出,从堆栈中弹出上下文信息,NDC可以用对不同源的log信息(同时地)交叉输出进行区分,关于NDC方面的详细介绍会在下文中提到。
(12)格式对齐,比如std::string pattern ="-10m"时表示左对齐,宽度是10,此时会输出"teststr ",当然其它的控制字符也可以相同的方式来使用,比如"%-12d","%-5p"等等
1.6.3 TTCCLayout
是在PatternLayout基础上发展的一种缺省的带格式输出的布局器, 其格式由时间,线程ID,Logger和NDC 组成(consists of time, thread, Logger and nested diagnostic context information, hence the name),因而得名。提供给那些想显示典型的信息(一般情况下够用了)又懒得配置pattern的同志们。
TTCCLayout在构造时有机会选择显示本地时间或GMT时间,缺省是按照本地时间显示:
TTCCLayout::TTCCLayout(bool use_gmtime = false)。
1.7 如何将LOG记录到文件
log4cplus在将log信息记录到文件的基础上,提供了更多的功能,可以按照你预先设定的大小来决定是否转储,当超过该大小,后续log信息会另存到新文件中,依次类推;或者按照日期来决定是否转储。 log4cplus提供了三个类用于文件操作,它们是FileAppender类、RollingFileAppender类、DailyRollingFileAppender类。
1.7.1 FileAppender类
实现了基本的文件操作功能,构造函数如下: FileAppender(const log4cplus::tstring& filename, LOG4CPLUS_OPEN_MODE_TYPE mode =LOG4CPLUS_FSTREAM_NAMESPACE::ios::trunc, bool immediateFlush = true);
filename : 文件名
mode : 文件类型,
可选择的文件类型包括app、ate、binary、in、out、trunc,因为实际上只是对stl的一个简单包装。缺省是trunc,表示将先前文件删除。 immediateFlush :缓冲刷新标志,如果true
表示每向文件写一条记录就刷新一次缓存,否则直到FileAppender被关闭或文件缓存已满才更新文件,一般是要设置true的,比如你往文件写的过程中出现了错误(如程序非正常退出),即使文件没有正常关闭也可以保证程序终止时刻之前的所有记录都会被正常保存。 FileAppender类的使用情况将在针对脚本配置这块来讲,另外两个类也是如此(特此说明)。
1.7.2 RollingFileAppender类
构造函数如下: log4cplus::RollingFileAppender::RollingFileAppender(const log4cplus::tstring& filename, long maxFileSize, int maxBackupIndex, bool immediateFlush)
filename : 文件名
maxFileSize : 文件的最大尺寸
maxBackupIndex : 最大记录文件数
immediateFlush : 缓冲刷新标志
RollingFileAppender类可以根据你预先设定的大小来决定是否转储,当超过该大小,后续log信息会另存到新文件中,除了定义每个记录文件的大小之外,你还要确定在RollingFileAppender类对象构造时最多需要多少个这样的记录文件(maxBackupIndex+1),当存储的文件数目超过maxBackupIndex+1时,会删除最早生成的文件,保证整个文件数目等于maxBackupIndex+1,然后继续记录。
1.7.3 DailyRollingFileAppender类
构造函数如下:
DailyRollingFileAppender::DailyRollingFileAppender(const log4cplus::tstring& filename, DailyRollingFileSchedule schedule, bool immediateFlush, int maxBackupIndex)
filename : 文件名
schedule : 存储频度
immediateFlush : 缓冲刷新标志
maxBackupIndex : 最大记录文件数
DailyRollingFileAppender类可以根据你预先设定的频度来决定是否转储,当超过该频度,后续log信息会另存到新文件中,
这里的频度包括:MONTHLY(每月)、WEEKLY(每周)、DAILY(每日)、TWICE_DAILY(每两天)、HOURLY(每时)、MINUTELY(每分),maxBackupIndex的含义同上所述。
1.8 日志输出优先级控制
log4cplus将输出的log信息按照LogLevel(从低到高)分为:
NOT_SET_LOG_LEVEL (-1) :接受缺省的LogLevel,如果有父logger则继承它的LogLevel;
ALL_LOG_LEVEL ( 0) :开放所有log信息输出;
TRACE_LOG_LEVEL ( 0) :开放trace信息输出(即ALL_LOG_LEVEL);
DEBUG_LOG_LEVEL (10000) :开放debug信息输出;
INFO_LOG_LEVEL (20000) :开放info信息输出;
WARN_LOG_LEVEL (30000) :开放warning信息输出;
ERROR_LOG_LEVEL (40000) :开放error信息输出;
FATAL_LOG_LEVEL (50000) :开放fatal信息输出;
OFF_LOG_LEVEL (60000) :关闭所有log信息输出。 可以通过
logger_name.setLogLevel(LogLevel)来设置日志输出的优先级。
1.9 基于脚本配置来过滤log信息
除了通过程序实现对log环境的配置之外,log4cplus通过PropertyConfigurator类实现了基于脚本配置的功能。通过脚本可以完成对logger、appender和layout的配置,因此可以解决怎样输出,输出到哪里的问题。
1.9.1 Appender的配置语法:
(1)设置名称:
/*设置方法*/
log4cplus.appender.appenderName=fully.qualified.name.of.appender.class
例如(列举了所有可能的Appender,其中SocketAppender后面会讲到):
log4cplus.appender.append_1=log4cplus::ConsoleAppender
log4cplus.appender.append_2=log4cplus::FileAppender
log4cplus.appender.append_3=log4cplus::RollingFileAppender
log4cplus.appender.append_4=log4cplus::DailyRollingFileAppender
log4cplus.appender.append_4=log4cplus::SocketAppender
(2)设置Filter:
包括选择过滤器和设置过滤条件,可选择的过滤器包括:LogLevelMatchFilter、LogLevelRangeFilter、和StringMatchFilter:
对LogLevelMatchFilter来说,过滤条件包括LogLevelToMatch和AcceptOnMatch(true|false), 只有当log信息的LogLevel值与LogLevelToMatch相同,且AcceptOnMatch为true
时才会匹配。LogLevelRangeFilter来说,过滤条件包括LogLevelMin、LogLevelMax和AcceptOnMatch,只有当log信息的LogLevel在LogLevelMin、LogLevelMax之间同时AcceptOnMatch为
true时才会匹配。对StringMatchFilter来说,过滤条件包括StringToMatch和AcceptOnMatch,只有当log信息的LogLevel值与StringToMatch对应的LogLevel值与相同, 且AcceptOnMatch为true时会匹配。过滤条件处理机制类似于IPTABLE的Responsibility chain,(即先deny、再allow)不过执行顺序刚好相反,后写的条件会被先执行,比如: log4cplus.appender.append_1.filters.1=log4cplus::spi::LogLevelMatchFilter
log4cplus.appender.append_1.filters.1.LogLevelToMatch=TRACE
log4cplus.appender.append_1.filters.1.AcceptOnMatch=true
#log4cplus.appender.append_1.filters.2=log4cplus::spi::DenyAllFilter
会首先执行filters.2的过滤条件,关闭所有过滤器,然后执行filters.1,仅匹配TRACE信息。
(3)设置Layout
可以选择不设置、TTCCLayout、或PatternLayout 如果不设置,会输出简单格式的log信息。
设置TTCCLayout如下所示:
log4cplus.appender.ALL_MSGS.layout=log4cplus::TTCCLayout
设置PatternLayout如下所示:
log4cplus.appender.append_1.layout=log4cplus::PatternLayout
log4cplus.appender.append_1.layout.ConversionPattern=%d{%m/%d/%y %H:%M:%S,%Q} [%t] %-5p - %m%n
1.9.2 logger的配置语法
包括rootLogger和non-root logger。
对于rootLogger来说: log4cplus.rootLogger=[LogLevel], appenderName, appenderName, ...
对于non-root logger来说: log4cplus.logger.logger_name=[LogLevel|INHERITED], appenderName, appenderName, ...
脚本方式使用起来非常简单,只要首先加载配置即可(urconfig.properties是自行定义的配置文件):PropertyConfigurator::doConfigure("urconfig.properties");
1.10 例子
#include <log4cplus/logger.h>
#include <log4cplus/fileappender.h>
#include <log4cplus/loggingmacros.h>
#include <log4cplus/consoleappender.h>
#include <log4cplus/layout.h>
#include <string>
#include <memory>
using namespace log4cplus;
using namespace log4cplus::helpers;
/*log4cplus 使用步骤:
*1. 实例化一个appender对象。
*2. 实例化一个layout对象。
*3. 将layout对象绑定(attach)到appender对象。
*4. 实例化一个logger对象,调用静态函数:log4cplus::Logger::getInstance(“logger_name”)。
*5. 将appender对象绑定(attach)到logger对象,如省略此步骤,标准输出(屏幕)appender对象会绑定到logger。
*6. 设置logger的优先级,如省略此步骤,各种有限级的消息都将被记录。
*/
int main()
{
//步骤1. 实例化一个appender对象。
//FileAppender(const log4cplus::tstring& filename,
// LOG4CPLUS_OPEN_MODE_TYPE mode = LOG4CPLUS_FSTREAM_NAMESPACE::ios::trunc,
// bool immediateFlush = true);
//filename : 文件名
//mode : 文件类型,可选择的文件类型包括app、ate、binary、in、out、trunc标志,缺省是trunc,表示将先前文件删除。
//immediateFlush :缓冲刷新标志,如果为true表示每向文件写一条记录就刷新一次缓存,否则直到FileAppender
// 被关闭或文件缓存已满才更新文件,一般是要设置true的,比如你往文件写的过程中出了错误(如程序非正常退出),
// 即使文件没有正常关闭也可以保证程序终止时刻之前的所有记录都会被正常保存。
// 定义一个文件Appender
SharedAppenderPtr pFileAppender(new FileAppender(("testlog.log")));
//log4cplus::RollingFileAppender::RollingFileAppender(const log4cplus::tstring& filename,
// long maxFileSize,
// int maxBackupIndex,
// bool immediateFlush)
//filename : 文件名
//maxFileSize : 文件的最大尺寸
//maxBackupIndex : 最大记录文件数
//immediateFlush : 缓冲刷新标志
//RollingFileAppender类可以根据你预先设定的大小来决定是否转储,当超过该大小,后续log信息会另存到新文件中,
//除了定义每个记录文件的大小之外,你还要确定在RollingFileAppender类对象构造时最多需要多少个这样的记录文件(maxBackupIndex+1),
//当存储的文件数目超过maxBackupIndex+1时,会删除最早生成的文件,保证整个文件数目等于maxBackupIndex+1。然后继续记录
//SharedAppenderPtr pFileAppender(new RollingFileAppender("testlog.log", 5*1024, 5));
//DailyRollingFileAppender::DailyRollingFileAppender(const log4cplus::tstring& filename,
// DailyRollingFileSchedule schedule,
// bool immediateFlush,
// int maxBackupIndex)
//DailyRollingFileAppender类可以根据你预先设定的频度来决定是否转储,当超过该频度,后续log信息会另存到新文件中
//,这里的频度包括:MONTHLY(每月)、WEEKLY(每周)、DAILY(每日)、TWICE_DAILY(每两天)、HOURLY(每时)、MINUTELY(每分)。
//maxBackupIndex的含义同上,
//下面代码运行后会以分钟为单位,分别生成名为Test.log.2004-10-17-03-03、
//Test.log.2004-10-17-03-04和Test.log.2004-10-17-03-05这样的文件;如果超过了就另存。
//SharedAppenderPtr pFileAppender(new DailyRollingFileAppender("test.log", MINUTELY, true, 5));
pFileAppender->setName("LoggerName");
//步骤2. 实例化一个layout对象。
//"%%",转义为%, 即,std::string pattern = "%%" 时输出: "%"
//"%c",输出logger名称,比如std::string pattern ="%c" 时输出: "test_logger.subtest",
// 也可以控制logger名称的显示层次,比如"%c{1}"时输出"test_logger",其中数字表示层次
//
//"%D",显示本地时间,当std::string pattern ="%D" 时输出:"2004-10-16 18:55:45",
// %d显示标准时间,所以当std::string pattern ="%d" 时输出 "2004-10-16 10:55:45" (因为我们是东8区,差8个小时啊)。
// 可以通过%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
//
//"%F",输出当前记录器所在的文件名称
//"%L",输出当前记录器所在的文件行号"
//"%l",输出当前记录器所在的文件名称和行号
//"%m",输出原始信息,以确保原始信息被嵌入到带格式的信息中。
//"%n",换行符,没什么好解释的
//"%p",输出LogLevel,比如std::string pattern ="%p" 时输出:"DEBUG"ï
//"%t",输出记录器所在的线程ID,比如std::string pattern ="%t" 时输出: "1075298944"
//"%x",嵌套诊断上下文NDC (nested diagnostic context) 输出,从堆栈中弹出上下文信息,
// NDC可以用对不同源的log信息(同时地)交叉输出进行区分,关于NDC方面的详细介绍会在下文中提到。
//格式对齐,比如std::string pattern ="%-10m"时表示左对齐,宽度是10,此时会输出"teststr ",
//当然其它的控制字符也可以相同的方式来使用,比如"%-12d","%-5p"等等
std::auto_ptr<Layout> pPatternLayout(new PatternLayout(("%p:%D -%m [%l - %t]%n")));
//步骤3. 将layout对象绑定(attach)到appender对象。
pFileAppender->setLayout(pPatternLayout);
//步骤4. 实例化一个logger对象,调用静态函数:log4cplus::Logger::getInstance(“logger_name”)。
// 定义Logger
Logger pTestLogger = Logger::getInstance(("LoggerName"));
//步骤5. 将appender对象绑定(attach)到logger对象,如省略此步骤,标准输出(屏幕)appender对象会绑定到logger。
// 将需要关联Logger的Appender添加到Logger上
pTestLogger.addAppender(pFileAppender);
// 输出日志信息
//LOG4CPLUS_WARN(pTestLogger, "This is a <Warn> log message");
//LOG4CPLUS_DEBUG(pTestLogger, "This is a <Warn> log message");
//步骤6. 设置logger的优先级,如省略此步骤,各种有限级的消息都将被记录。
pTestLogger.setLogLevel(TRACE_LOG_LEVEL);
LOG4CPLUS_TRACE(pTestLogger, "printMessages()");
LOG4CPLUS_DEBUG(pTestLogger, "This is a DEBUG message");
LOG4CPLUS_INFO(pTestLogger, "This is a INFO message");
LOG4CPLUS_WARN(pTestLogger, "This is a WARN message");
LOG4CPLUS_ERROR(pTestLogger, "This is a ERROR message");
LOG4CPLUS_FATAL(pTestLogger, "This is a FATAL message");
return 1;
}
编译执行
g++ log.cpp -I /usr/local/log4cplus/include/ -L /usr/local/log4cplus/lib -l log4cplus -o log
补充
1.编译时提示
此时在代码中添加头文件:#include <log4cplus/loggingmacros.h>
2.提示:error while loading shared libraries: liblog4cplus-1.1.so.9: cannot open shared object file: No such file or directory
find / -name liblog4cplus-1.1.so.9/*我的找到在/usr/local/lib/liblog4cplus-1.1.so.9*/
cd /etc
sudo gedit ld.so.conf (添加 /usr/local/lib/)
sudo ldconfig