zoukankan      html  css  js  c++  java
  • Log4cplus入门

    Log4cplus使用指南

    1.  Log4cplus简单介绍

    log4cplusC++编写的开源的日志系统,前身是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*类型就可以。

     

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

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

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

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

    6- 安装: make install

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

    2.2.          win

     

    3.  主要类说明

    类名

    说明

    Filter

    过滤器,过滤输出消息。

    过滤器,解决哪些信息须要输出的问题,比方DEBUGWARR,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-简洁使用

    /*

     *简洁使用,仅实现步骤145

      */

    #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_XXXXLOG4CPLUS_XXXX_STR两种日志输出宏。 另外,日志输出宏LOG4CPLUS_TRACE_METHOD主要用来跟踪方法的调用轨迹。

    5.  输出格式控制(layout)

    log4cplus通过布局器(Layouts)来控制输出的格式,log4cplus提供了三种类型的Layouts,各自是SimpleLayoutPatternLayout、和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基础上发展的一种缺省的带格式输出的布局器,其格式由时间。线程IDLoggerNDC 组成(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.14.2.24.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          : 文件类型。可选择的文件类型包含appatebinaryinouttrunc,由于实际上仅仅是对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.logTest.log.1Test.log.2Test.log.3Test.log.4Test.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-03Test.log.2004-10-17-03-04Test.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, 直接调用宏就能够将信息发往loggerServerLOG4CPLUS_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 argcchar** 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 argcchar **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了,并且当出现异常时,可以确保pushpop的调用是匹配的。

    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设置自己的优先级。当某个loggerLogLevel设置成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

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

    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()) << ' ');

     

        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类实现了基于脚本配置的功能。通过脚本能够完毕对loggerappenderlayout的配置,因此能够解决如何输出,输出到哪里的问题。

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

    8.1.          基本配置

    基本配置语法主要针对包含rootLoggernon-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=chsen,其它參数详细见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,单位有(MBKB

    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 LogLevelMatchFilterLogLevelRangeFilter、和StringMatchFilter

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

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

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

    过滤条件包含LogLevelMinLogLevelMaxAcceptOnMatch,仅仅有当日志的LogLevelLogLevelMinLogLevelMax之间同一时候AcceptOnMatchtrue时才会匹配。

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

    过滤条件包括StringToMatchAcceptOnMatch。仅仅有当日志包括StringToMatch字符串 AcceptOnMatchtrue时会匹配。

    l  DenyAllFilter则过滤掉全部消息。

     

    过滤条件处理机制类似于LinuxIPTABLEResponsibility 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_STRINGreturn 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  ") )

    {

    }


  • 相关阅读:
    mac下如何全量删除短信内容
    git log --oneline --graph的读法
    nginx bind() to 0.0.0.0:**** failed (13: Permission denied)
    nginx安装和配置
    pycharm的插件pylint报错:java.lang.Throwable: Write-unsafe context! Model changes are allowed from write-safe contexts only. Please ensure you're using invokeLater/invokeAndWait with a correct modality stat
    python编码规范、js编码规范及IDE的检查插件pylint/eslint等
    Flask 在 Debug 模式下初始化2次
    python的globals()使用
    删除整张表数据但是空间没有减少
    DBCC DBREINDEX重建索引提高SQL Server性能
  • 原文地址:https://www.cnblogs.com/mfmdaoyou/p/6781123.html
Copyright © 2011-2022 走看看