Log4cplus使用指南

1.  Log4cplus简单介绍

log4cplus是C++编写的开源的日志系统,前身是java编写的log4j系统。受Apache
Software License保护。作者是Tad E. Smith。

log4cplus具有线程安全、灵活、以及多粒度控制的特点。通过将日志划分优先级使其能够面向程序调试、执行、測试、和维护等全生命周期。

你能够选择将日志输出到屏幕、文件、NT event log、甚至是远程server;通过指定策略对日志进行定期备份等等。

2.  安装方法

2.1.          linux

1- 解压: gzip -cd log4cplus-x.x.x.tar.gz | tar -xf -

2- 进入log4cplus根文件夹:
cd log4cplus-x.x.x

3- 产生Makefile: ./configure --prefix=/where/to/install -enable-threads=no

假设须要指定安装路径可使用--prefix參数, 否则将缺省安装到/usr/local文件夹下。另外,假设须要单线程版本号可通过參数-enable-threads=no指定, 否则默认将安装多线程版本号。

对于HP-UNIX平台用户, 因为aCC编译器选项兼容性问题,请另外增加參数CXXFLAGS=”-AA
-w”(单线程版本号)或CXXFLAGS=”-AA –mt
-w”(多线程版本号)。

4- 创建: make

对于HP-UNIX用户,因为aCC编译器不包括-Wall选项来显示全部警告,创建时将导致无效的-W參数错误,请改动/log4cplus-x.x.x/src文件夹下的Makefile。将AM_CPPFLAGS
= -Wall 行的-Wall选项删除或凝视掉。

此外,某些HP-UNIX平台的套接字连接接受函数accept()第三个參数要求为int*,而在socket-unix.cxx源文件153行实现中实际传入的是socklen_t*类型,平台并不支持,也将导致编译错误。

解决方法是将源码该行中的传入參数强制转换为int*类型就可以。

注意AIX和Linux平台眼下并没有上述两处创建错误。

对于AIX平台用户请保证创建时使用的编译器是xlC而不是g++。否则将导致log4cplus脚本配置功能执行时产生段异常,生成core文件。

有鉴于此。也请保证HP-UNIX用户尽量使用aCC编译器进行创建。

5- 创建/log4cplus/tests文件夹下的測试用例:
make check

6- 安装: make install

成功安装后将在/usr/local文件夹或指定的文件夹下创建include和lib两个子文件夹及对应文件。当中include文件夹包括头文件,lib文件夹包括终于打包生成的静态和动态库。在动态连接log4cplus库时请使用-llog4cplus选项。

2.2.          win

3.  主要类说明

类名

说明

Filter

过滤器,过滤输出消息。

过滤器,解决哪些信息须要输出的问题,比方DEBUG,WARR,INFO等的输出控制

Layout

布局器。控制输出消息的格式。格式化输出信息,攻克了怎样输出的问题。

Appender

挂接器,与布局器和过滤器紧密配合,将特定格式的消息过滤后输出到所挂接的设备终端如屏幕,文件等等)。

接收日志的各个设备,如控制台、文件、网络等。

攻克了输出到哪里去的问题

Logger

记录器。保存并跟踪对象日志信息变更的实体,当你须要对一个对象进行记录时。就须要生成一个logger。

日志模块,程序中唯一一个必须得使用的模块,攻克了在哪里使用日志的问题。

Hierarchy

分类器,层次化的树型结构,用于对被记录信息的分类,层次中每个节点维护一个logger的全部信息。

LogLevel

优先权,包含TRACE,  DEBUG, INFO, WARNING, ERROR, FATAL。

4.  基本使用

4.1.          基本步骤

使用log4cplus有六个基本步骤:

l  实例化一个封装了输出介质的appender对象;

l  实例化一个封装了输出格式的layout对象;

l  将layout对象绑定(attach)到appender对象;如省略此步骤。简单布局器SimpleLayout(參见5.1小节)对象会绑定到logger。

l  实例化一个封装了日志输出logger对象,并调用其静态函数getInstance()获得实例,log4cplus::Logger::getInstance("logger_name")。

l  将appender对象绑定(attach)到logger对象;

l  设置logger的优先级。如省略此步骤,各种有限级的日志都将被输出。

4.2.          使用演示样例

以下通过一些样例来了解log4cplus的基本使用。

4.2.1.   例1-标准使用

/*

*标准使用。严格实现步骤1-6。

 */

#include <log4cplus/logger.h>

#include <log4cplus/consoleappender.h>

#include <log4cplus/layout.h>

using namespace log4cplus;

using namespace log4cplus::helpers;

int main()

{

/* step 1: Instantiate an appender object */

SharedObjectPtr<Appender> _append (new ConsoleAppender());

_append->setName("append for  test");

   

/* step 2: Instantiate a layout object */

std::string pattern = "%d{%m/%d/%y  %H:%M:%S}  - %m [%l]%n";

std::auto_ptr<Layout> _layout(new PatternLayout(pattern));

   

/* step 3: Attach the layout object to the appender */

_append->setLayout( _layout );

   

/* step 4:  Instantiate a logger object */

Logger _logger = Logger::getInstance("test");

   

/* step 5: Attach the appender object to the  logger  */

_logger.addAppender(_append);

   

/* step 6: Set a priority for the logger  */

_logger.setLogLevel(ALL_LOG_LEVEL);

   

/* log activity */

LOG4CPLUS_DEBUG(_logger, "This is the  FIRST log message...")

sleep(1);

LOG4CPLUS_WARN(_logger, "This is the  SECOND log message...")

return 0;

}

输出结果:

10/14/04  09:06:24  - This is the FIRST log  message... [main.cpp:31]

10/14/04  09:06:25  - This is the SECOND log  message... [main.cpp:33]

4.2.2.   例2-简洁使用

/*

 *简洁使用,仅实现步骤1、4、5。

 */

#include <log4cplus/logger.h>

#include <log4cplus/consoleappender.h>

using namespace log4cplus;

using namespace log4cplus::helpers;

int main()

{

/* step 1: Instantiate an appender object */

SharedAppenderPtr _append(new ConsoleAppender());

_append->setName("append  test");

   

/* step 4: Instantiate a logger object */

Logger _logger = Logger::getInstance("test");

   

/* step 5: Attach the appender object to the  logger  */

_logger.addAppender(_append);

   

/* log activity */

LOG4CPLUS_DEBUG(_logger, "This is the  FIRST log message...")

sleep(1);

LOG4CPLUS_WARN(_logger, "This is the  SECOND log message...")

   

return 0;

}

输出结果:

DEBUG - This is  the FIRST log message...

WARN - This is the  SECOND log message...

4.2.3.   例3-输出日志到控制台

/*

 *iostream模式,appender输出到控制台。

 */

#include<log4cplus/logger.h>

#include<log4cplus/consoleappender.h>

#include<iomanip>

usingnamespacelog4cplus;

int main()

{

/*step1:Instantiateanappenderobject*/

SharedAppenderPtr_append(new  ConsoleAppender());

_append->setName("appendtest");

   

/*step4:Instantiatealoggerobject*/

Logger_logger = Logger::getInstance("test");

   

/*step5:Attachtheappenderobjecttothelogger*/

_logger.addAppender(_append);

   

/*logactivity*/

LOG4CPLUS_TRACE(_logger, "Thisis" << "justat" << "est." <<
 std::endl)

LOG4CPLUS_DEBUG(_logger, "Thisisabool:" << true)

LOG4CPLUS_INFO(_logger, "Thisisachar:" << 'x')

LOG4CPLUS_WARN(_logger, "Thisisaint:" <<
1000)

LOG4CPLUS_ERROR(_logger, "Thisisalong(hex):" <<
std::hex  << 100000000)

LOG4CPLUS_FATAL(_logger, "Thisisadouble:" <<
 std::setprecision(15) << 1.2345234234)

   

return0;

}

输出结果:

DEBUG-Thisisabool:1

INFO-Thisisachar:x

WARN-Thisisaint:1000

ERROR-Thisisalong(hex):5f5e100

FATAL-Thisisadouble:1.2345234234

4.2.4.   例4-输出日志到文件

/*

*文件模式。appender输出到文件。

 */

#include<log4cplus/logger.h>

#include<log4cplus/fileappender.h>

usingnamespacelog4cplus;

int main()

{

/*step1:Instantiateanappenderobject*/

SharedAppenderPtr_append(new FileAppender("Test.log"));

_append->setName("filelogtest");

   

/*step4:Instantiatealoggerobject*/

Logger_logger = Logger::getInstance("test.subtestof_filelog");

   

/*step5:Attachtheappenderobjecttothelogger*/

_logger.addAppender(_append);

   

/*logactivity*/

for (int
i = 0; i < 5; ++i) {

LOG4CPLUS_DEBUG(_logger, "Enteringloop#" <<
i  << "Endline#")

}

return0;

}

输出结果(Test.log文件):

DEBUG-Enteringloop#0Endline#

DEBUG-Enteringloop#1Endline#

DEBUG-Enteringloop#2Endline#

DEBUG-Enteringloop#3Endline#

DEBUG-Enteringloop#4Endline#

4.2.5.   例5-使用loglog输出日志

LogLog类实现了debug, warn, error 函数用于logcplus执行时显示log4cplus自身的调试、警告或错误信息。是对标准输出的简单封装,它也能够用来进行简单的日志输出。

LogLog 同一时候提供了两个方法来进一步控制所输出的信息。当中setInternalDebugging()方法用来控制是否屏蔽输出信息中的调试信息。当输入參数为false则屏蔽,缺省设置为false。 setQuietMode()方法用来控制是否屏蔽全部输出信息。当输入參数为true则屏蔽。缺省设置为false。

/*

通过loglog来控制输出调试、警告或错误信息,appender输出到屏幕。

*/

#include <iostream>

#include <log4cplus/helpers/loglog.h>

using namespace log4cplus::helpers;

void printMsgs(void)

{

std::cout << "Entering  printMsgs()..." <<
std::endl;

LogLog::getLogLog()->debug("This is a  Debug statement...");

LogLog::getLogLog()->warn("This is a  Warning...");

LogLog::getLogLog()->error("This is a  Error...");

std::cout << "Exiting  printMsgs()..." <<
std::endl << std::endl;

}

int main()

{

printMsgs();

std::cout << "Turning on  debug..." <<
std::endl;

LogLog::getLogLog()->setInternalDebugging(true);

printMsgs();

std::cout << "Turning on  quiet mode..." <<
std::endl;

LogLog::getLogLog()->setQuietMode(true);

printMsgs();

return 0;

}

输出结果:

EnteringprintMsgs()...

log4cplus:WARNThisisaWarning...

log4cplus:ERRORThisisaError...

ExitingprintMsgs()...

Turningondebug...

EnteringprintMsgs()...

log4cplus:ThisisaDebugstatement...

log4cplus:WARNThisisaWarning...

log4cplus:ERRORThisisaError...

ExitingprintMsgs()...

Turningonquietmode...

EnteringprintMsgs()...

ExitingprintMsgs()...

注意输出信息中总是包括"log4cplus:"前缀。假设须要定制使其使用其它的前缀请參见9.2小节。

4.3.          日志输出宏

log4cplus在头文件loggingmacros.h中提供了下面的日志输出宏:

LOG4CPLUS_TRACE_METHOD(logger,logEvent)

LOG4CPLUS_TRACE(logger,logEvent)

LOG4CPLUS_TRACE_STR(logger,logEvent)

LOG4CPLUS_DEBUG(logger,logEvent)

LOG4CPLUS_DEBUG_STR(logger,logEvent)

LOG4CPLUS_INFO(logger,logEvent)

LOG4CPLUS_INFO_STR(logger,logEvent)

LOG4CPLUS_WARN(logger,logEvent)

LOG4CPLUS_WARN_STR(logger,logEvent)

LOG4CPLUS_ERROR(logger,logEvent)

LOG4CPLUS_ERROR_STR(logger,logEvent)

LOG4CPLUS_FATAL(logger,logEvent)

LOG4CPLUS_FATAL_STR(logger,logEvent)

当中logger 为Logger实例名称,logEvent为日志内容。因为log4cplus选用C++的流机制进行日志输出,因此为了区分包括<<运算符和不包括<<运算符的日志内容。分别提供了LOG4CPLUS_XXXX和LOG4CPLUS_XXXX_STR两种日志输出宏。 另外,日志输出宏LOG4CPLUS_TRACE_METHOD主要用来跟踪方法的调用轨迹。

5.  输出格式控制(layout)

log4cplus通过布局器(Layouts)来控制输出的格式,log4cplus提供了三种类型的Layouts,各自是SimpleLayout、PatternLayout、和TTCCLayout。

5.1.          SimpleLayout

一种简单格式的布局器。在输出的原始信息之前加上LogLevel和一个"-",假设初始化时没有将布局器附加到挂接器,则默认使用SimpleLayout。

下面代码片段演示了怎样使用SimpleLayout。

... ...

/* step 1:  Instantiate an appender object */

SharedObjectPtr  _append (new ConsoleAppender());

_append->setName("append for  test");

/* step 2:  Instantiate a layout object */

std::auto_ptr<Layout>  _layout(new  log4cplus::SimpleLayout());

/* step 3: Attach  the layout object to the appender */

_append->setLayout(_layout);

/* step 4:  Instantiate a logger object */

Logger _logger =  Logger::getInstance("test");

/* step 5: Attach  the appender object to the logger  */

_logger.addAppender(_append);

/* log activity */

LOG4CPLUS_DEBUG(_logger,  "This  is the simple formatted log message...")

... ...

输出结果:

DEBUG - This is  the simple formatted log message...

5.2.          PatternLayout

一种有词法分析功能的模式布局器,类似于C语言的printf()函数,可以对提前定义的转换标识符(conversion
specifiers)进行解析。转换成特定格式输出。

下面代码片段演示了怎样使用PatternLayout。

... ...

/* step 1:  Instantiate an appender object */

SharedObjectPtr _append  (new  ConsoleAppender());

_append->setName("append for  test");

/* step 2:  Instantiate a layout object */

std::string  pattern = "%d{%m/%d/%y  %H:%M:%S}  - %m [%l]%n";

std::auto_ptr<Layout>  _layout(new  PatternLayout(pattern));

/* step 3: Attach  the layout object to the appender */

_append->setLayout(_layout);

   

/* step 4:  Instantiate a logger object */

Logger _logger =  Logger::getInstance("test_logger.subtest");

   

/* step 5: Attach  the appender object to the logger  */

_logger.addAppender(_append);

/* log activity */

LOG4CPLUS_DEBUG(_logger,  "teststr")

... ...

输出结果:

10/16/04 18:51:25  - teststr  [main.cpp:51]

5.2.1.   转换标识符

PatterLayout支持的转换标识符主要包含:

(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"等等。

5.3.          TTCCLayout

是在PatternLayout基础上发展的一种缺省的带格式输出的布局器,其格式由时间。线程ID,Logger和NDC 组成(consists
of time, thread, Logger and nested diagnostic context information, hence the name)。因而得名,关于NDC请參见6.4小节。

下面代码片段演示了怎样使用TTCCLayout。

 ......

/*step1:Instantiateanappenderobject*/

SharedObjectPtr_append(new  ConsoleAppender());

_append->setName("appendfortest");

   

/*step2:Instantiatealayoutobject*/

std::auto_ptr_layout(new  TTCCLayout());

   

/*step3:Attachthelayoutobjecttotheappender*/

_append->setLayout(_layout);

   

/*step4:Instantiatealoggerobject*/

Logger_logger=Logger::getInstance("test_logger");

   

/*step5:Attachtheappenderobjecttothelogger*/

_logger.addAppender(_append);

   

/*logactivity*/

LOG4CPLUS_DEBUG(_logger,"teststr")

......

输出结果:

10-16-04 19:08:27,501 [1075298944] DEBUG test_logger <> -  teststr

TTCCLayout在构造时,有机会选择显示本地时间或GMT时间,缺省是依照本地时间显示:TTCCLayout::TTCCLayout(bool
use_gmtime  = false)。

假设须要构造TTCCLayout对象时选择GMT时间格式,则使用方式例如以下代码片断所看到的。

... ...

/* step 2:  Instantiate a layout object */

std::auto_ptr  _layout(new TTCCLayout(true));

... ...

输出结果:

10-16-04 11:12:47,678 [1075298944] DEBUG test_logger <> -  teststr

6.  输出重定向(appender)

6.1.          重定向到控制台

log4cplus默认将输出到控制台,提供ConsoleAppender用于操作。

演示样例代码请參见4.2.1、4.2.2或4.2.3小节,这里不再赘述。

6.2.          重定向到文件

log4cplus提供了三个类用于文件操作,它们是FileAppender类、RollingFileAppender类、DailyRollingFileAppender类。

6.2.1.   FileAppender

实现了主要的文件操作功能,构造函数例如以下:

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类的使用情况请參考4.2.5小节。这里不再赘述。

6.2.2.   RollingFileAppender

实现能够滚动转储的文件操作功能。构造函数例如以下:

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。然后继续记录,比方下面代码片段:

... ...

#define LOOP_COUNT 200000

SharedAppenderPtr  _append(new  RollingFileAppender("Test.log",
5*1024, 5));

_append->setName("file  test");

_append->setLayout(  std::auto_ptr(new  TTCCLayout())
);

Logger::getRoot().addAppender(_append);

Logger root =  Logger::getRoot();

Logger test =  Logger::getInstance("test");

Logger subTest =  Logger::getInstance("test.subtest");

for(int i=0;
i < LOOP_COUNT; ++i)  {

NDCContextCreator _context("loop");

LOG4CPLUS_DEBUG(subTest, "Entering  loop #"  <<
i)

}

... ...

输出结果:

执行后会产生6个输出文件,Test.log、Test.log.1、Test.log.2、Test.log.3、Test.log.4、Test.log.5当中Test.log存放着最新写入的信息。而最后一个文件里并不包括第一个写入信息,说明已经被不断更新了。

   须要指出的是,这里除了Test.log之外,每一个文件的大小都是200K,而不是我们想像中的5K。这是由于log4cplus中隐含定义了文件的最小尺寸是200K,仅仅有大于200K的设置才生效,<=
200k的设置都会被觉得是200K。

6.2.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的含义同上所述,比方下面代码片段:

... ...

SharedAppenderPtr  _append(new  DailyRollingFileAppender("Test.log",
MINUTELY, true, 5));

_append->setName("file  test");

_append->setLayout(  std::auto_ptr(new  TTCCLayout())
);

Logger::getRoot().addAppender(_append);

Logger root =  Logger::getRoot();

Logger test =  Logger::getInstance("test");

Logger subTest =  Logger::getInstance("test.subtest");

for(int i=0;
i < LOOP_COUNT; ++i) {

NDCContextCreator _context("loop");

LOG4CPLUS_DEBUG(subTest, "Entering  loop #"  <<
i)

}

... ...

输出结果:

执行后会以分钟为单位,分别生成名为Test.log.2004-10-17-03-03、Test.log.2004-10-17-03-04和Test.log.2004-10-17-03-05这种文件。

须要指出的是这里的"频度"并非你写入文件的速度,事实上是否转储的标准并不依赖你写入文件的速度,而是依赖于写入的那一时刻是否满足了频度条件。即是否超过了以分钟、小时、周、月为单位的时间刻度,假设超过了就另存。

6.3.          重定向到远程server

log4cplus提供了SocketAppender。实现了C/S方式的日志记录,用于支持重定向到远程server。

6.3.1.   client程序须要做的工作

(1) 定义一个SocketAppender类型的挂接器

SharedAppenderPtr _append(new SocketAppender(host, 8888, "ServerName"));

(2) 把该挂接器增加到logger中

Logger::getRoot().addAppender(_append);

(3) SocketAppender类型不须要Layout, 直接调用宏就能够将信息发往loggerServer了LOG4CPLUS_INFO(Logger::getRoot(),
"This is a test: ")

注意这里对宏的调用事实上是调用了SocketAppender::append(),里面有一个传输数据约定。即先发送一个兴许数据的总长度,然后再发送实际的数据:

... ...

SocketBuffer  buffer = convertToBuffer(event,
serverName);

SocketBuffer  msgBuffer(LOG4CPLUS_MAX_MESSAGE_SIZE);

msgBuffer.appendSize_t(buffer.getSize());

msgBuffer.appendBuffer(buffer);

... ...

6.3.2.   server端程序须要做的工作

(1) 定义一个ServerSocket

ServerSocket serverSocket(port);

(2) 调用accept函数创建一个新的socket与client连接

Socket sock = serverSocket.accept();

(3) 此后就可以用该sock进行数据read/write了,形如(完整代码见6.3.3小节):

  SocketBuffer msgSizeBuffer(sizeof(unsigned int));

  if(!clientsock.read(msgSizeBuffer)){

      return;

  }

  unsigned int msgSize = msgSizeBuffer.readInt();

  SocketBuffer buffer(msgSize);

  if(!clientsock.read(buffer)){

      return;

}

(4) 为了将读到的数据正常显示出来,须要将SocketBuffer存放的内容转换成InternalLoggingEvent格式:

  log4cplus::spi::InternalLoggingEvent event = readFromBuffer(buffer);

 然后输出:

  Logger logger = Logger::getInstance(event.getLoggerName());

  logger.callAppenders(event);

注意read/write是依照堵塞方式实现的,意味着对其调用直到满足了所接收或发送的个数才返回。

6.3.3.   例6-重定向到远程server

   下面是server端代码。

#include <log4cplus/config.h>

#include <log4cplus/configurator.h>

#include <log4cplus/consoleappender.h>

#include <log4cplus/socketappender.h>

#include <log4cplus/helpers/loglog.h>

#include <log4cplus/helpers/socket.h>

#include <log4cplus/helpers/threads.h>

#include <log4cplus/spi/loggerimpl.h>

#include <log4cplus/spi/loggingevent.h>

#include <iostream>

using namespace std;

using namespace log4cplus;

using namespace log4cplus::helpers;

using namespace log4cplus::thread;

namespace loggingserver

{

class ClientThread : public AbstractThread

{

public:

ClientThread(Socket clientsock)
: clientsock(clientsock) {

cout << "Received a  client connection!!!!" <<
endl;

}

~ClientThread() {

cout << "Client  connection closed." <<
endl;

}

virtual void run();

private:

Socket clientsock;

};

}

int main(int argc, char** argv)

{

if (argc <
3) {

cout << "Usage: port  config_file" <<
endl;

return 1;

}

int port
= atoi(argv[1]);

tstring configFile =  LOG4CPLUS_C_STR_TO_TSTRING(argv[2]);

PropertyConfigurator config(configFile);

config.configure();

ServerSocket serverSocket(port);

while (1)
{

loggingserver::ClientThread*
thr = newloggingserver::ClientThread(serverSocket.accept());

thr->start();

}

return 0;

}

//////////////////////////////////////////////////////////////////////////////

//  loggingserver::ClientThread implementation

//////////////////////////////////////////////////////////////////////////////

void loggingserver::ClientThread::run()

{

while (1)
{

if (!clientsock.isOpen())
{

return;

}

SocketBuffer msgSizeBuffer(sizeof(unsigned int));

if (!clientsock.read(msgSizeBuffer))
 {

return;

}

unsigned int msgSize
= msgSizeBuffer.readInt();

SocketBuffer buffer(msgSize);

if (!clientsock.read(buffer))
{

return;

}

spi::InternalLoggingEvent event =
readFromBuffer(buffer);

Logger logger = Logger::getInstance(event.getLoggerName());

logger.callAppenders(event);

}

}

下面是client代码。

#include <log4cplus/logger.h>

#include <log4cplus/socketappender.h>

#include <log4cplus/loglevel.h>

#include <log4cplus/tstring.h>

#include <log4cplus/helpers/threads.h>

#include <iomanip>

using namespace std;

using namespace log4cplus;

int main(int argc, char **argv)

{

log4cplus::helpers::sleep(1);

tstring serverName = (argc >
1 ?  LOG4CPLUS_C_STR_TO_TSTRING(argv[1]) : tstring());

//tstring host =  LOG4CPLUS_TEXT("192.168.2.10");

tstring host = LOG4CPLUS_TEXT("127.0.0.1");

SharedAppenderPtr append_1(new SocketAppender(host,
9998,  serverName));

append_1->setName( LOG4CPLUS_TEXT("First")
);

Logger::getRoot().addAppender(append_1);

Logger root = Logger::getRoot();

Logger test = Logger::getInstance(  LOG4CPLUS_TEXT("socket.test")
);

LOG4CPLUS_DEBUG(root,    "This is"

<< " a reall"

<< "y long message." <<
endl

<< "Just testing it out" <<
endl

<< "What do you think?

")

test.setLogLevel(NOT_SET_LOG_LEVEL);

LOG4CPLUS_DEBUG(test, "This is a  bool: "  << true)

LOG4CPLUS_INFO(test, "This is a  char: "  << 'x')

LOG4CPLUS_INFO(test, "This is a  short: "  <<
(short)-100)

LOG4CPLUS_INFO(test, "This is a  unsigned short: " <<
(unsignedshort)100)

log4cplus::helpers::sleep(0, 500000);

LOG4CPLUS_INFO(test, "This is a  int: "  <<
(int)1000)

LOG4CPLUS_INFO(test, "This is a  unsigned int: " <<
(unsignedint)1000)

LOG4CPLUS_INFO(test, "This is a  long(hex): " <<
hex << (long)100000000)

LOG4CPLUS_INFO(test, "This is a  unsigned long: " <<
(unsignedlong)100000000)

LOG4CPLUS_WARN(test, "This is a  float: "  <<
(float)1.2345)

LOG4CPLUS_ERROR(test, "This is a  double: "

<< setprecision(15)

<< (double)1.2345234234)

LOG4CPLUS_FATAL(test, "This is a  long double: "

<< setprecision(15)

<< (long double)123452342342.342)

return 0;

}

6.4.          嵌入诊断上下文NDC

log4cplus中的嵌入诊断上下文(Nested Diagnostic Context),即NDC。对log系统而言,当输入源可能不止一个,而仅仅有一个输出时。往往须要分辩所要输出消息的来源,比方server处理来自不同client的消息时就须要作此推断。NDC能够为交错显示的信息打上一个标记(stamp)。使得辨认工作看起来比較easy些。

这个标记是线程特有的,利用了线程局部存储机制,称为线程私有数据(Thread-Specific
Data,或TSD)。相关定义例如以下,包含定义、初始化、获取、设置和清除操作:

linux pthread

#define LOG4CPLUS_THREAD_LOCAL_TYPE pthread_key_t*

#define LOG4CPLUS_THREAD_LOCAL_INIT ::log4cplus::thread::createPthreadKey()

#define LOG4CPLUS_GET_THREAD_LOCAL_VALUE(
key )  pthread_getspecific(*key)

#defineLOG4CPLUS_SET_THREAD_LOCAL_VALUE(key,value)  \

  pthread_setspecific(*key,
value)

#define LOG4CPLUS_THREAD_LOCAL_CLEANUP(
key ) pthread_key_delete(*key)

win32

#define LOG4CPLUS_THREAD_LOCAL_TYPE DWORD

#define LOG4CPLUS_THREAD_LOCAL_INIT TlsAlloc()

#define LOG4CPLUS_GET_THREAD_LOCAL_VALUE(
key )  TlsGetValue(key)

#define LOG4CPLUS_SET_THREAD_LOCAL_VALUE(
key, value ) \

TlsSetValue(key, static_cast(value))

#define LOG4CPLUS_THREAD_LOCAL_CLEANUP(
key )  TlsFree(key)

使用起来比較简单,在某个线程中:

NDC& ndc =  log4cplus::getNDC();

ndc.push("ur ndc  string");

LOG4CPLUS_DEBUG(logger,  "this  is a NDC test");

... ...

ndc.pop();

... ...

LOG4CPLUS_DEBUG(logger,  "There  should be no NDC...");

ndc.remove();

输出结果(当设定输出格式为TTCCLayout时):

10-21-04 21:32:58, [3392] DEBUG test  - this is a NDC test

10-21-04 21:32:58, [3392] DEBUG test <> - There should be no  NDC...

也能够在自己定义的输出格式中使用NDC(用%x) ,比方:

... ...

std::string  pattern = "NDC:[%x]  - %m %n";

std::auto_ptr  _layout(new  PatternLayout(pattern));

... ...

LOG4CPLUS_DEBUG(_logger,  "This  is the FIRST log message...")

NDC& ndc =  log4cplus::getNDC();

ndc.push("ur ndc  string");

LOG4CPLUS_WARN(_logger,  "This  is the SECOND log message...")

ndc.pop();

ndc.remove();

... ...

输出结果:

NDC:[]  - This is the FIRST  log message...

NDC:[ur ndc string]  - This  is the SECOND log message...

第二种更简单的用法是在线程中直接用NDCContextCreator:

NDCContextCreator _first_ndc("ur ndc string");

G4CPLUS_DEBUG(logger, "this is a NDC test")

不必显式地调用push/pop了,并且当出现异常时,可以确保push与pop的调用是匹配的。

7.  输出过滤(filter)

7.1.          利用日志级别进行输出过滤

7.1.1.   日志级别管理

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信息输出

在log4cplus中。全部logger都通过一个层次化的结构(事实上内部是hash表)来组织的,有一个Root级别的logger,能够通过下面方法获取:Logger
root = Logger::getRoot();

用户定义的logger都有一个名字与之相应。比方:Logger test = Logger::getInstance("test");

能够定义该logger的子logger: Logger subTest = Logger::getInstance("test.subtest");

注意Root级别的logger仅仅有通过getRoot方法获取,Logger::getInstance("root")获得的是它的子对象而已。有了这些具有父子关系的logger之后可分别设置其LogLevel,比方:

root.setLogLevel( ... );

Test.setLogLevel( ... );

subTest.setLogLevel( ... );

各个logger能够通过setLogLevel设置自己的优先级。当某个logger的LogLevel设置成NOT_SET_LOG_LEVEL时,该logger会继承父logger的优先级,另外,假设定义了重名的多个logger, 对当中不论什么一个的改动都会同一时候改变其他logger。

7.1.2.   利用日志级别进行输出过滤

log4cplus支持编译时候和执行时刻利用日志级别进行输出过滤。编译时刻通过例如以下的提前定义变量进行过滤:   

#define LOG4CPLUS_DISABLE_FATAL

#define  LOG4CPLUS_DISABLE_WARN

#define  LOG4CPLUS_DISABLE_ERROR

#define  LOG4CPLUS_DISABLE_INFO

#define  LOG4CPLUS_DISABLE_DEBUG

#define  LOG4CPLUS_DISABLE_TRACE

执行时刻的过滤则通过使用Logger的setLogLevel设置日志级别进行过滤。

7.1.3.   例7-日志的优先级

#include "log4cplus/logger.h"

#include "log4cplus/consoleappender.h"

#include "log4cplus/loglevel.h"

#include <iostream>

using namespace std;

using namespace log4cplus;

int main()

{

SharedAppenderPtr _append(new ConsoleAppender());

_append->setName("test");

Logger::getRoot().addAppender(_append);

Logger root = Logger::getRoot();

Logger test = Logger::getInstance("test");

Logger subTest = Logger::getInstance("test.subtest");

LogLevelManager& llm =  getLogLevelManager();

cout << endl << "Before  Setting, Default LogLevel" <<
endl;

LOG4CPLUS_FATAL(root, "root: " <<
 llm.toString(root.getChainedLogLevel()));

LOG4CPLUS_FATAL(root, "test: " <<
 llm.toString(test.getChainedLogLevel()));

LOG4CPLUS_FATAL(root,"test.subtest:" <<
 llm.toString(subTest.getChainedLogLevel()));

cout << endl << "Setting  test.subtest to WARN" <<
endl;

subTest.setLogLevel(WARN_LOG_LEVEL);

LOG4CPLUS_FATAL(root, "root: " <<
 llm.toString(root.getChainedLogLevel()));

LOG4CPLUS_FATAL(root, "test: " <<
 llm.toString(test.getChainedLogLevel()));

LOG4CPLUS_FATAL(root, "test.subtest:  "  <<
llm.toString(subTest.getChainedLogLevel()));

cout << endl << "Setting test  to TRACE" <<
endl;

test.setLogLevel(TRACE_LOG_LEVEL);

LOG4CPLUS_FATAL(root, "root: " <<
 llm.toString(root.getChainedLogLevel()));

LOG4CPLUS_FATAL(root, "test: " <<
 llm.toString(test.getChainedLogLevel()));

LOG4CPLUS_FATAL(root, "test.subtest:  "  <<
llm.toString(subTest.getChainedLogLevel()));

cout << endl << "Setting  test.subtest to NO_LEVEL" <<
endl;

subTest.setLogLevel(NOT_SET_LOG_LEVEL);

LOG4CPLUS_FATAL(root, "root: " <<
 llm.toString(root.getChainedLogLevel()));

LOG4CPLUS_FATAL(root, "test: " <<
llm.toString(test.getChainedLogLevel()));

LOG4CPLUS_FATAL(root, "test.subtest:  "  <<
llm.toString(subTest.getChainedLogLevel()) << '\n');

cout << "create a logger test_bak,  named \"test_\", too. " <<
endl;

Logger test_bak = Logger::getInstance("test");

cout << "Setting test to INFO, so  test_bak also be set to INFO" <<
endl;

test.setLogLevel(INFO_LOG_LEVEL);

LOG4CPLUS_FATAL(root, "test: " <<
 llm.toString(test.getChainedLogLevel()));

LOG4CPLUS_FATAL(root, "test_bak:  "  <<
llm.toString(test_bak.getChainedLogLevel()));

return 0;

}

输出结果:

Before Setting, Default LogLevel

FATAL - root: DEBUG

FATAL - test: DEBUG

FATAL - test.subtest: DEBUG

Setting test.subtest to WARN

FATAL - root: DEBUG

FATAL - test: DEBUG

FATAL - test.subtest: WARN

Setting test to TRACE

FATAL - root: DEBUG

FATAL - test: TRACE

FATAL - test.subtest: WARN

Setting test.subtest to NO_LEVEL

FATAL - root: DEBUG

FATAL - test: TRACE

FATAL - test.subtest: TRACE

create a logger test_bak, named "test_", too.

Setting test to INFO, so test_bak also be set to INFO

FATAL - test: INFO

FATAL - test_bak: INFO

7.1.4.   例8-执行时利用日志级别进行输出过滤

#include "log4cplus/logger.h"

#include "log4cplus/consoleappender.h"

#include "log4cplus/loglevel.h"

#include <iostream>

using namespace std;

using namespace log4cplus;

void ShowMsg(void)

{

LOG4CPLUS_TRACE(Logger::getRoot(),"info");

LOG4CPLUS_DEBUG(Logger::getRoot(),"info");

LOG4CPLUS_INFO(Logger::getRoot(),"info");

LOG4CPLUS_WARN(Logger::getRoot(),"info");

LOG4CPLUS_ERROR(Logger::getRoot(),"info");

LOG4CPLUS_FATAL(Logger::getRoot(),"info");

}

int main()

{

SharedAppenderPtr _append(new ConsoleAppender());

_append->setName("test");

_append->setLayout(std::auto_ptr(new TTCCLayout()));

Logger root = Logger::getRoot();

root.addAppender(_append);

cout << endl << "all-log  allowed"  <<
endl;

root.setLogLevel(ALL_LOG_LEVEL);

ShowMsg();

cout << endl << "trace-log  and above allowed" <<
endl;

root.setLogLevel(TRACE_LOG_LEVEL);

ShowMsg();

cout << endl << "debug-log  and above allowed" <<
endl;

root.setLogLevel(DEBUG_LOG_LEVEL);

ShowMsg();

cout << endl << "info-log and  above allowed" <<
endl;

root.setLogLevel(INFO_LOG_LEVEL);

ShowMsg();

cout << endl << "warn-log and  above allowed" <<
endl;

root.setLogLevel(WARN_LOG_LEVEL);

ShowMsg();

cout << endl << "error-log  and above allowed" <<
endl;

root.setLogLevel(ERROR_LOG_LEVEL);

ShowMsg();

cout << endl << "fatal-log  and above allowed" <<
endl;

root.setLogLevel(FATAL_LOG_LEVEL);

ShowMsg();

cout << endl << "log  disabled" <<
endl;

root.setLogLevel(OFF_LOG_LEVEL);

ShowMsg();

return 0;

}

输出结果:

all-log allowed

10-17-04  10:11:40,587 [1075298944] TRACE root <> - info

10-17-04  10:11:40,590 [1075298944] DEBUG root <> - info

10-17-04  10:11:40,591 [1075298944] INFO root <> - info

10-17-04  10:11:40,591 [1075298944] WARN root <> - info

10-17-04  10:11:40,592 [1075298944] ERROR root <> - info

10-17-04  10:11:40,592 [1075298944] FATAL root <> - info

trace-log and  above allowed

10-17-04  10:11:40,593 [1075298944] TRACE root <> - info

10-17-04  10:11:40,593 [1075298944] DEBUG root <> - info

10-17-04  10:11:40,594 [1075298944] INFO root <> - info

10-17-04  10:11:40,594 [1075298944] WARN root <> - info

10-17-04 10:11:40,594  [1075298944] ERROR root <> - info

10-17-04  10:11:40,594 [1075298944] FATAL root <> - info

debug-log and  above allowed

10-17-04  10:11:40,595 [1075298944] DEBUG root <> - info

10-17-04  10:11:40,595 [1075298944] INFO root <> - info

10-17-04 10:11:40,596  [1075298944] WARN root <> - info

10-17-04  10:11:40,596 [1075298944] ERROR root <> - info

10-17-04  10:11:40,596 [1075298944] FATAL root <> - info

info-log and above  allowed

10-17-04  10:11:40,597 [1075298944] INFO root <> - info

10-17-04  10:11:40,597 [1075298944] WARN root <> - info

10-17-04  10:11:40,597 [1075298944] ERROR root <> - info

10-17-04  10:11:40,598 [1075298944] FATAL root <> - info

warn-log and above  allowed

10-17-04  10:11:40,598 [1075298944] WARN root <> - info

10-17-04  10:11:40,598 [1075298944] ERROR root <> - info

10-17-04  10:11:40,599 [1075298944] FATAL root <> - info

error-log and  above allowed

10-17-04  10:11:40,599 [1075298944] ERROR root <> - info

10-17-04  10:11:40,600 [1075298944] FATAL root <> - info

fatal-log and  above allowed

10-17-04  10:11:40,600 [1075298944] FATAL root <> - info

log disabled

7.2.          利用脚本配置进行输出过滤

因为log4cplus脚本配置中能够设置日志的级别、过滤器Filter,因此它也是进行输出过滤的一种非常好的选择。脚本配置的使用详细參见第8节。

7.3.          LogLog的输出过滤

Loglog能够使用setInternalDebugging()方法用来控制是否屏蔽输出信息中的调试信息。当输入參数为false则屏蔽,缺省设置为false。 另外方法setQuietMode()方法用来控制是否屏蔽全部输出信息。当输入參数为true则屏蔽。缺省设置为false。详细使用方法请參见4.2.5小节。

8.  脚本配置

除了通过程序实现对log环境的配置之外,log4cplus通过PropertyConfigurator类实现了基于脚本配置的功能。通过脚本能够完毕对logger、appender和layout的配置,因此能够解决如何输出,输出到哪里的问题。

以下将简介一下脚本的语法规则,包含基本配置语法和高级配置语法。

8.1.          基本配置

基本配置语法主要针对包含rootLogger和non-root logger。

8.1.1.   根Logger的配置

语法:log4cplus.rootLogger=[LogLevel], appenderName, appenderName, ...

8.1.2.   非根Logger的配置

语法:log4cplus.logger.logger_name=[LogLevel|INHERITED], appenderName, appenderName, ...

说明:INHERITED表示继承父Logger的日志级别。

8.2.          高级配置

8.2.1.   Appender配置

语法:

log4cplus.appender.appenderName=fully.qualified.name.of.appender.class

fully.qualified.name.of.appeneder.class可用值:

log4cplus::ConsoleAppender

终端输出

log4cplus::FileAppender

一般文件输出

log4cplus::RollingFileAppender

日志大小输出

log4cplus::DailyRollingFileAppender

日期输出

log4cplus::SocketAppender

网络port输出

文件通用选项:

选项

作用

ImmediateFlush

是否马上刷新(默觉得true)

log4cplus.appender.ALL_MSGS.ImmediateFlush=true

File

使用的文件名称

log4cplus.appender.ALL_MSGS.File=all_msgs.log

Append

是否追加到之前的文件

log4cplus.appender.ALL_MSGS.Append=true

ReopenDelay

先将日志缓存起来,等指定时间之后再往文件里插入

降低文件的保存次数

log4cplus.appender.ALL_MSGS.ReopenDelay=10【单位为秒】

UseLockFile

是否使用加锁的方式去写文件,默认是false

log4cplus.appender.ALL_MSGS.UseLockFile=true

LockFile

使用的加锁文件名称

log4cplus.appender.ALL_MSGS.LockFile=fuck_are_you.lock[文件名称没有详细要求]

Locale

使用的字符集

log4cplus.appender.ALL_MSGS.Locale=chs【en,其它參数详细见imbue參数】

Threshold

指定日志消息的输出最低层次

log4cplus.appender.ALL_MSGS.Threshold=DEBUG

DailyRollingFileAppender相关配置:

选项

作用

Schedule

文件保存频率 可选值:MONTHLY,  WEEKLY, DAILY,

TWICE_DAILY, HOURLY, MINUTELY

log4cplus.appender.ALL_MSGS.Schedule=MINUTELY

MaxBackupIndex

最多文件个数

log4cplus.appender.ALL_MSGS.  MaxBackupIndex=10

DatePattern

指定文件名称的日期格式

1)'.'yyyy-MM: 每月

2)'.'yyyy-ww: 每周

3)'.'yyyy-MM-dd: 每天

4)'.'yyyy-MM-dd-a: 每天两次

5)'.'yyyy-MM-dd-HH: 每小时

6)'.'yyyy-MM-dd-HH-mm: 每分钟

log4cplus.appender.ALL_MSGS.DatePattern='.'yyyy-ww

RollingFileAppender相关配置:

选项

作用

MaxFileSize

最大文件大小,当小于200kb的时候。默觉得200kb,单位有(MB、KB)

log4cplus.appender.ALL_MSGS.  MaxFileSize=10

MaxBackupIndex

最多文件个数

log4cplus.appender.ALL_MSGS.  MaxBackupIndex=10

8.2.2.   Filter配置

Appender能够附加Filter组成的链表,假设Filter链中存在过滤器Filter, log4cplus在输出日志之前将调用链表中Filter的过滤方法decide(),依据该方法的返回值决定是否过滤该输出日志。

语法:

log4cplus.appender.appenderName.Filters.FilterNumber=fully.qualified.name.of.Filter.class

log4cplus.appender.appenderName.Filters.FilterNumber.FilterCondition=value.of.FilterCondition

log4cplus.appender.appenderName.Filters.AcceptOnMatch=true|false

举例:

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

眼下log4plus提供的过滤器包含DenyAllFilter 、LogLevelMatchFilter、LogLevelRangeFilter、和StringMatchFilter。

l  LogLevelMatchFilter依据特定的日志级别进行过滤。

过滤条件包含LogLevelToMatch和AcceptOnMatch(true|false), 仅仅有当日志的LogLevel值与LogLevelToMatch同样,且AcceptOnMatch为true时才会匹配。

l  LogLevelRangeFilter依据依据日志级别的范围进行过滤。

过滤条件包含LogLevelMin、LogLevelMax和AcceptOnMatch,仅仅有当日志的LogLevel在LogLevelMin、LogLevelMax之间同一时候AcceptOnMatch为true时才会匹配。

l  StringMatchFilter依据日志内容是否包括特定字符串进行过滤。

过滤条件包括StringToMatch和AcceptOnMatch。仅仅有当日志包括StringToMatch字符串 且AcceptOnMatch为true时会匹配。

l  DenyAllFilter则过滤掉全部消息。

过滤条件处理机制类似于Linux中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信息。

8.2.3.   Layout配置

能够选择不设置、TTCCLayout、或PatternLayout,假设不设置。会输出SimpleLayout格式的日志。

设置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

8.2.4.   例9-脚本配置

脚本方式使用起来很easy。仅仅要首先载入配置就可以(urconfig.properties是自行定义的配置文件):PropertyConfigurator::doConfigure("urconfig.properties");

以下我们通过样例体会一下log4cplus强大的基于脚本过滤log信息的功能。以下是urconfig.properties演示样例脚本配置内容。

log4cplus.rootLogger=TRACE,  ALL_MSGS, TRACE_MSGS, DEBUG_INFO_MSGS, FATAL_MSGS

log4cplus.appender.ALL_MSGS=log4cplus::RollingFileAppender

log4cplus.appender.ALL_MSGS.File=all_msgs.log

log4cplus.appender.ALL_MSGS.layout=log4cplus::TTCCLayout

log4cplus.appender.TRACE_MSGS=log4cplus::RollingFileAppender

log4cplus.appender.TRACE_MSGS.File=trace_msgs.log

log4cplus.appender.TRACE_MSGS.layout=log4cplus::TTCCLayout

log4cplus.appender.TRACE_MSGS.filters.1=log4cplus::spi::LogLevelMatchFilter

log4cplus.appender.TRACE_MSGS.filters.1.LogLevelToMatch=TRACE

log4cplus.appender.TRACE_MSGS.filters.1.AcceptOnMatch=true

log4cplus.appender.TRACE_MSGS.filters.2=log4cplus::spi::DenyAllFilter

log4cplus.appender.DEBUG_INFO_MSGS=log4cplus::RollingFileAppender

log4cplus.appender.DEBUG_INFO_MSGS.File=debug_info_msgs.log

log4cplus.appender.DEBUG_INFO_MSGS.layout=log4cplus::TTCCLayout

log4cplus.appender.DEBUG_INFO_MSGS.filters.1=log4cplus::spi::LogLevelRangeFilter

log4cplus.appender.DEBUG_INFO_MSGS.filters.1.LogLevelMin=DEBUG

log4cplus.appender.DEBUG_INFO_MSGS.filters.1.LogLevelMax=INFO

log4cplus.appender.DEBUG_INFO_MSGS.filters.1.AcceptOnMatch=true

log4cplus.appender.DEBUG_INFO_MSGS.filters.2=log4cplus::spi::DenyAllFilter

log4cplus.appender.FATAL_MSGS=log4cplus::RollingFileAppender

log4cplus.appender.FATAL_MSGS.File=fatal_msgs.log

log4cplus.appender.FATAL_MSGS.layout=log4cplus::TTCCLayout

log4cplus.appender.FATAL_MSGS.filters.1=log4cplus::spi::StringMatchFilter

log4cplus.appender.FATAL_MSGS.filters.1.StringToMatch=FATAL

log4cplus.appender.FATAL_MSGS.filters.1.AcceptOnMatch=true

log4cplus.appender.FATAL_MSGS.filters.2=log4cplus::spi::DenyAllFilter

下面是演示样例代码。

#include <log4cplus/logger.h>

#include <log4cplus/configurator.h>

#include <log4cplus/helpers/stringhelper.h>

#include <log4cplus/loggingmacros.h>

#include <iostream>

#include <string>

using namespace std;

using namespace log4cplus;

using namespace log4cplus::helpers;

using namespace log4cplus::thread;

static Logger logger
= Logger::getInstance(LOG4CPLUS_TEXT("log"));

void printDebug()

{

LOG4CPLUS_TRACE_METHOD(logger, LOG4CPLUS_TEXT("::printDebug()"));

LOG4CPLUS_DEBUG(logger, "This
is a DEBUG message");

LOG4CPLUS_INFO(logger, "This
is a INFO message");

LOG4CPLUS_WARN(logger, "This
is a WARN message");

LOG4CPLUS_ERROR(logger, "This
is a ERROR message");

LOG4CPLUS_FATAL(logger, "This
is a FATAL message");

}

int main()

{

Logger root
= Logger::getRoot();

PropertyConfigurator::doConfigure(LOG4CPLUS_TEXT("urconfig.properties"));

printDebug();

return 0;

}

输出结果:

1. all_msgs.log

10-17-04  14:55:25,858 [1075298944] TRACE log <> - ENTER: ::printDebug()

10-17-04  14:55:25,871 [1075298944] DEBUG log <> - This is a DEBUG message

10-17-04  14:55:25,873 [1075298944] INFO log <> - This is a INFO message

10-17-04  14:55:25,873 [1075298944] WARN log <> - This is a WARN message

10-17-04 14:55:25,874  [1075298944] ERROR log <> - This is a ERROR message

10-17-04  14:55:25,874 [1075298944] FATAL log <> - This is a FATAL message

10-17-04  14:55:25,875 [1075298944] TRACE log <> - EXIT:::printDebug()

2. trace_msgs.log

10-17-04  14:55:25,858 [1075298944] TRACE log <> - ENTER: ::printDebug()

10-17-04  14:55:25,875 [1075298944] TRACE log <> - EXIT:::printDebug()

3.  debug_info_msgs.log

10-17-04  14:55:25,871 [1075298944] DEBUG log <> - This is a DEBUG message

10-17-04  14:55:25,873 [1075298944] INFO log <> - This is a INFO message

4. fatal_msgs.log

10-17-04  14:55:25,874 [1075298944] FATAL log <> - This is a FATAL message

8.3.          脚本配置的动态载入

多线程版本号的log4cplus提供了有用类ConfigureAndWatchThread,该类启动线程对配置脚本进行监控,一旦发现配置脚本被更新则立马又一次载入配置。

类ConfigureAndWatchThread的构造函数定义为:

ConfigureAndWatchThread(const log4cplus::tstring& propertyFile,

unsigned int millis = 60 * 1000);

第一个參数propertyFile为配置脚本的路径名。第二个參数为监控时两次更新检查相隔的时间。单位为耗秒ms。

8.3.1.   例10-使用线程监控脚本的更新

#include <log4cplus/logger.h>

#include <log4cplus/configurator.h>

#include <log4cplus/helpers/loglog.h>

#include <log4cplus/helpers/stringhelper.h>

using namespace std;

using namespace log4cplus;

using namespace log4cplus::helpers;

Logger log_1  =  Logger::getInstance("test.log_1");

Logger log_2  =  Logger::getInstance("test.log_2");

Logger log_3  =  Logger::getInstance("test.log_3");

void printMsgs(Logger& logger)

{

LOG4CPLUS_TRACE_METHOD(logger, "printMsgs()");

LOG4CPLUS_DEBUG(logger, "printMsgs()");

LOG4CPLUS_INFO(logger, "printMsgs()");

LOG4CPLUS_WARN(logger, "printMsgs()");

LOG4CPLUS_ERROR(logger, "printMsgs()");

}

int main()

{

cout << "Entering main()..." <<
endl;

LogLog::getLogLog()->setInternalDebugging(true);

Logger root = Logger::getRoot();

try {

ConfigureAndWatchThread configureThread("log4cplus.properties",
5 * 1000);

LOG4CPLUS_WARN(root, "Testing....");

for(int i=0;
i<100; ++i) {

printMsgs(log_1);

printMsgs(log_2);

printMsgs(log_3);

log4cplus::helpers::sleep(1);

}

} catch(...)
{

cout << "Exception..." <<
endl;

LOG4CPLUS_FATAL(root, "Exception  occured...")

}

cout << "Exiting main()..." <<
endl;

return 0;

}

下面是配置脚本log4cplus.properties的内容。

log4cplus.rootLogger=INFO,  STDOUT, R

log4cplus.logger.test=WARN

log4cplus.logger.test.log_1=FATAL

log4cplus.logger.test.log_2=FATAL

log4cplus.logger.test.log_3=WARN

log4cplus.appender.STDOUT=log4cplus::ConsoleAppender

log4cplus.appender.STDOUT.layout=log4cplus::PatternLayout

log4cplus.appender.STDOUT.layout.ConversionPattern=%d{%m/%d/%y  %H:%M:%S} [%t] %-5p %c{2} %%%x%% - %m [%l]%n

log4cplus.appender.R=log4cplus::RollingFileAppender

log4cplus.appender.R.File=output.log

#log4cplus.appender.R.MaxFileSize=5MB

log4cplus.appender.R.MaxFileSize=500KB

log4cplus.appender.R.MaxBackupIndex=5

log4cplus.appender.R.layout=log4cplus::TTCCLayout

9.  定制Log4cplus

9.1.          定制日志级别

log4cplus支持日志级别的定制。

假设须要定义自己的优先级,则能够按下面步骤进行定制。

l  定义新日志级别相应的常量整数和输出宏。

/*

* customloglevel.h

*/

#include <log4cplus/logger.h>

#include <log4cplus/helpers/loglog.h>

using namespace log4cplus;

using namespace log4cplus::helpers;

const LogLevel CRITICAL_LOG_LEVEL =  45000;

#define LOG4CPLUS_CRITICAL(logger,
logEvent)  \

if(logger.isEnabledFor(CRITICAL_LOG_LEVEL))
{ \

log4cplus::tostringstream _log4cplus_buf;  \

_log4cplus_buf << logEvent; \

logger.forcedLog(CRITICAL_LOG_LEVEL,  _log4cplus_buf.str(), __FILE__,__LINE__);
\

}

l  定义新日志级别相应的字符串、常量整数与字符串之间的转换函数,定义自己的初始化器将转换函数注冊到LogLevelManage。

#include "customloglevel.h"

#define _CRITICAL_STRING "CRITICAL"

tstring  criticalToStringMethod(LogLevel ll)

{

if(ll ==
CRITICAL_LOG_LEVEL) {

return _CRITICAL_STRING;

} else {

return tstring();

}

}

LogLevel  criticalFromStringMethod(const tstring& s)

{

if(s == _CRITICAL_STRING) return CRITICAL_LOG_LEVEL;

return NOT_SET_LOG_LEVEL;

}

class CriticalLogLevelInitializer {

public:

CriticalLogLevelInitializer() {

getLogLevelManager().pushToStringMethod(criticalToStringMethod);

getLogLevelManager().pushFromStringMethod(criticalFromStringMethod);

}

};

CriticalLogLevelInitializer  criticalLogLevelInitializer_;

l  使用新定义的日志级别

#include "customloglevel.h"

#include <log4cplus/consoleappender.h>

#include <iomanip>

#include <iostream>

using namespace std;

using namespace log4cplus;

int main()

{

SharedAppenderPtr append_1(new ConsoleAppender());

append_1->setName("First");

Logger::getRoot().addAppender(append_1);

Logger root = Logger::getRoot();

LOG4CPLUS_CRITICAL(root, "This is a  new logginglevel");

return 0;

}

9.2.          定制LogLog

LogLog输出信息中总是包括"log4cplus:"前缀,这是由于LogLog在实现时候在构造函数中进行了硬编码:

LogLog::LogLog()

: mutex(LOG4CPLUS_MUTEX_CREATE),

debugEnabled(false),

quietMode(false),

PREFIX( LOG4CPLUS_TEXT("log4cplus:  ")
),

WARN_PREFIX( LOG4CPLUS_TEXT("log4cplus:WARN  ")
),

ERR_PREFIX( LOG4CPLUS_TEXT("log4cplus:ERROR  ")
)

{

}


Log4cplus入门的更多相关文章

  1. Angular2入门系列教程7-HTTP(一)-使用Angular2自带的http进行网络请求

    上一篇:Angular2入门系列教程6-路由(二)-使用多层级路由并在在路由中传递复杂参数 感觉这篇不是很好写,因为涉及到网络请求,如果采用真实的网络请求,这个例子大家拿到手估计还要自己写一个web ...

  2. ABP入门系列(1)——学习Abp框架之实操演练

    作为.Net工地搬砖长工一名,一直致力于挖坑(Bug)填坑(Debug),但技术却不见长进.也曾热情于新技术的学习,憧憬过成为技术大拿.从前端到后端,从bootstrap到javascript,从py ...

  3. Oracle分析函数入门

    一.Oracle分析函数入门 分析函数是什么?分析函数是Oracle专门用于解决复杂报表统计需求的功能强大的函数,它可以在数据中进行分组然后计算基于组的某种统计值,并且每一组的每一行都可以返回一个统计 ...

  4. Angular2入门系列教程6-路由(二)-使用多层级路由并在在路由中传递复杂参数

    上一篇:Angular2入门系列教程5-路由(一)-使用简单的路由并在在路由中传递参数 之前介绍了简单的路由以及传参,这篇文章我们将要学习复杂一些的路由以及传递其他附加参数.一个好的路由系统可以使我们 ...

  5. Angular2入门系列教程5-路由(一)-使用简单的路由并在在路由中传递参数

    上一篇:Angular2入门系列教程-服务 上一篇文章我们将Angular2的数据服务分离出来,学习了Angular2的依赖注入,这篇文章我们将要学习Angualr2的路由 为了编写样式方便,我们这篇 ...

  6. Angular2入门系列教程4-服务

    上一篇文章 Angular2入门系列教程-多个组件,主从关系 在编程中,我们通常会将数据提供单独分离出来,以免在编写程序的过程中反复复制粘贴数据请求的代码 Angular2中提供了依赖注入的概念,使得 ...

  7. wepack+sass+vue 入门教程(三)

    十一.安装sass文件转换为css需要的相关依赖包 npm install --save-dev sass-loader style-loader css-loader loader的作用是辅助web ...

  8. wepack+sass+vue 入门教程(二)

    六.新建webpack配置文件 webpack.config.js 文件整体框架内容如下,后续会详细说明每个配置项的配置 webpack.config.js直接放在项目demo目录下 module.e ...

  9. wepack+sass+vue 入门教程(一)

    一.安装node.js node.js是基础,必须先安装.而且最新版的node.js,已经集成了npm. 下载地址 node安装,一路按默认即可. 二.全局安装webpack npm install ...

随机推荐

  1. RESTful-rest_framework版本控制、分页器-第六篇

     版本控制: 源码位置分析第一步: 源码位置分析第二步:在APIView-despath方法-initial-determine_version #执行determine_version,返回两个值, ...

  2. ValueStack、ActionContext

    笔者不知道该用哪个词来形容ValueStack.ActionContext等可以在Struts2中用来存放数据的类.这些类使用的范围不同,得到的方法也不同,下面就来一一介绍. 1. ValueStac ...

  3. java连接mysql数据库 三 实现增删改查操作

    同以前一样,先写一个数据库打开和关闭操作类 public class DBConnection { String driver = "com.mysql.jdbc.Driver"; ...

  4. Angularjs的$apply及其优化使用

    今天,我们要聊得是Angularjs中的小明星$apply.当我们数据更新了,但是view层却没反应时,总能听到有人说,用apply吧,然后,懵懂无知的我们,在赋值代码后面加了$scope.$appl ...

  5. .bat 批处理

    最简单的一个批处理文件 @echo off echo 这是测试内容1 echo 这是测试内容2 pause 输出: 这是测试内容1 这是测试内容2 请按任意键继续. . .

  6. 理解exports

    webpack-nodejs-模块系统 其实,Module.exports才是真正的接口,exports只不过是它的一个辅助工具. 最终返回给调用的是Module.exports而不是exports. ...

  7. HDOJ 1398 Square Coins

    Square Coins Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Tota ...

  8. IOS-内存检测以及优化

    IOS-内存检测以及优化 2014年01月23日 Jason PS:开始写这个系列的笔记:主要是对过去自己比较模糊的一些概念进行测试,明确结果,提高自己 IOS 应用如果占用系统的内容过大(8GB), ...

  9. AtCoder Regular Contest 077 E - guruguru 线性函数 前缀和

    题目链接 题意 灯有\(m\)个亮度等级,\(1,2,...,m\),有两种按钮: 每次将亮度等级\(+1\),如\(1\rightarrow 2,2\rightarrow 3,...,m-1\rig ...

  10. Android下设置CPU核心数和频率

    现在的Android手机双核.四核变得非常普遍,同时CPU频率经常轻松上2G,功耗肯定会显著增加.而大多数的ARM架构的CPU采用的是对称多处理(SMP)的方式处理多CPU.这就意味着每个CPU核心是 ...