log4cplus 使用方法 配置

http://my.oschina.net/lovecxx/blog/185951




目錄[-]

  • 1.  Log4cplus簡介
  • 2.  安裝方法
  • 2.1.          linux
  • 2.2.          win
  • 3.  主要類說明
  • 4.  基本使用
  • 4.1.          基本步驟
  • 4.2.          使用示例
  • 4.2.1.   例1-標準使用
  • 4.2.2.   例2-簡潔使用
  • 4.2.3.   例3-輸出日誌到控制檯
  • 4.2.4.   例4-輸出日誌到文件
  • 4.2.5.   例5-使用loglog輸出日誌
  • 4.3.          日誌輸出宏
  • 5.  輸出格式控制(layout)
  • 5.1.          SimpleLayout
  • 5.2.          PatternLayout
  • 5.2.1.   轉換標識符
  • 5.3.          TTCCLayout
  • 6.  輸出重定向(appender)
  • 6.1.          重定向到控制檯
  • 6.2.          重定向到文件
  • 6.2.1.   FileAppender
  • 6.2.2.   RollingFileAppender
  • 6.2.3.   DailyRollingFileAppender
  • 6.3.          重定向到遠程服務器
  • 6.3.1.   客戶端程序需要做的工作
  • 6.3.2.   服務器端程序需要做的工作
  • 6.3.3.   例6-重定向到遠程服務器
  • 6.4.          嵌入診斷上下文NDC
  • 7.  輸出過濾(filter)
  • 7.1.          利用日誌級別進行輸出過濾
  • 7.1.1.   日誌級別管理
  • 7.1.2.   利用日誌級別進行輸出過濾
  • 7.1.3.   例7-日誌的優先級
  • 7.1.4.   例8-運行時利用日誌級別進行輸出過濾
  • 7.2.          利用腳本配置進行輸出過濾
  • 7.3.          LogLog的輸出過濾
  • 8.  腳本配置
  • 8.1.          基本配置
  • 8.1.1.   根Logger的配置
  • 8.1.2.   非根Logger的配置
  • 8.2.          高級配置
  • 8.2.1.   Appender配置
  • 8.2.2.   Filter配置
  • 8.2.3.   Layout配置
  • 8.2.4.   例9-腳本配置
  • 8.3.          腳本配置的動態加載
  • 8.3.1.   例10-使用線程監控腳本的更新
  • 9.  定製Log4cplus
  • 9.1.          定製日誌級別
  • 9.2.          定製LogLog
  • Log4cplus使用指南

    1.  Log4cplus簡介

    log4cplusC++編寫的開源的日誌系統,前身是java編寫的log4j系統,受Apache Software License保護,作者是Tad E. Smith

    log4cplus具有線程安全、靈活、以及多粒度控制的特點,通過將日誌劃分優先級使其可以面向程序調試、運行、測試、和維護等全生命週期。你可以選擇將日誌輸出到屏幕、文件、NT event log、甚至是遠程服務器;通過指定策略對日誌進行定期備份等等。

    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.          重定向到遠程服務器

    log4cplus提供了SocketAppender,實現了C/S方式的日誌記錄,用於支持重定向到遠程服務器。

    6.3.1.   客戶端程序需要做的工作

    (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.   服務器端程序需要做的工作

    (1) 定義一個ServerSocket

    ServerSocket serverSocket(port);

    (2) 調用accept函數創建一個新的socket與客戶端連接

    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-重定向到遠程服務器

       以下是服務器端代碼。

    #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 = new loggingserver::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);

        }

    }

    以下是客戶端代碼。

    #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: " << (unsigned short)100)

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

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

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

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

            LOG4CPLUS_INFO(test, "This is a  unsigned long: " << (unsigned long)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系統而言,當輸入源可能不止一個,而只有一個輸出時,往往需要分辯所要輸出消息的來源,比如服務器處理來自不同客戶端的消息時就需要作此判斷,NDC可以爲交錯顯示的信息打上一個標記(stamp),使得辨認工作看起來比較容易些。這個標記是線程特有的,利用了線程局部存儲機制,稱爲線程私有數據(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()) << '\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類實現了基於腳本配置的功能。通過腳本可以完成對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

    網絡端口輸出

    文件通用選項:

    選項

    作用

    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-腳本配置

    腳本方式使用起來非常簡單,只要首先加載配置即可(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  ") )

    {

    }

     


    目錄[-]

  • 1.  Log4cplus簡介
  • 2.  安裝方法
  • 2.1.          linux
  • 2.2.          win
  • 3.  主要類說明
  • 4.  基本使用
  • 4.1.          基本步驟
  • 4.2.          使用示例
  • 4.2.1.   例1-標準使用
  • 4.2.2.   例2-簡潔使用
  • 4.2.3.   例3-輸出日誌到控制檯
  • 4.2.4.   例4-輸出日誌到文件
  • 4.2.5.   例5-使用loglog輸出日誌
  • 4.3.          日誌輸出宏
  • 5.  輸出格式控制(layout)
  • 5.1.          SimpleLayout
  • 5.2.          PatternLayout
  • 5.2.1.   轉換標識符
  • 5.3.          TTCCLayout
  • 6.  輸出重定向(appender)
  • 6.1.          重定向到控制檯
  • 6.2.          重定向到文件
  • 6.2.1.   FileAppender
  • 6.2.2.   RollingFileAppender
  • 6.2.3.   DailyRollingFileAppender
  • 6.3.          重定向到遠程服務器
  • 6.3.1.   客戶端程序需要做的工作
  • 6.3.2.   服務器端程序需要做的工作
  • 6.3.3.   例6-重定向到遠程服務器
  • 6.4.          嵌入診斷上下文NDC
  • 7.  輸出過濾(filter)
  • 7.1.          利用日誌級別進行輸出過濾
  • 7.1.1.   日誌級別管理
  • 7.1.2.   利用日誌級別進行輸出過濾
  • 7.1.3.   例7-日誌的優先級
  • 7.1.4.   例8-運行時利用日誌級別進行輸出過濾
  • 7.2.          利用腳本配置進行輸出過濾
  • 7.3.          LogLog的輸出過濾
  • 8.  腳本配置
  • 8.1.          基本配置
  • 8.1.1.   根Logger的配置
  • 8.1.2.   非根Logger的配置
  • 8.2.          高級配置
  • 8.2.1.   Appender配置
  • 8.2.2.   Filter配置
  • 8.2.3.   Layout配置
  • 8.2.4.   例9-腳本配置
  • 8.3.          腳本配置的動態加載
  • 8.3.1.   例10-使用線程監控腳本的更新
  • 9.  定製Log4cplus
  • 9.1.          定製日誌級別
  • 9.2.          定製LogLog
  • Log4cplus使用指南

    1.  Log4cplus簡介

    log4cplusC++編寫的開源的日誌系統,前身是java編寫的log4j系統,受Apache Software License保護,作者是Tad E. Smith

    log4cplus具有線程安全、靈活、以及多粒度控制的特點,通過將日誌劃分優先級使其可以面向程序調試、運行、測試、和維護等全生命週期。你可以選擇將日誌輸出到屏幕、文件、NT event log、甚至是遠程服務器;通過指定策略對日誌進行定期備份等等。

    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.          重定向到遠程服務器

    log4cplus提供了SocketAppender,實現了C/S方式的日誌記錄,用於支持重定向到遠程服務器。

    6.3.1.   客戶端程序需要做的工作

    (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.   服務器端程序需要做的工作

    (1) 定義一個ServerSocket

    ServerSocket serverSocket(port);

    (2) 調用accept函數創建一個新的socket與客戶端連接

    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-重定向到遠程服務器

       以下是服務器端代碼。

    #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 = new loggingserver::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);

        }

    }

    以下是客戶端代碼。

    #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: " << (unsigned short)100)

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

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

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

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

            LOG4CPLUS_INFO(test, "This is a  unsigned long: " << (unsigned long)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系統而言,當輸入源可能不止一個,而只有一個輸出時,往往需要分辯所要輸出消息的來源,比如服務器處理來自不同客戶端的消息時就需要作此判斷,NDC可以爲交錯顯示的信息打上一個標記(stamp),使得辨認工作看起來比較容易些。這個標記是線程特有的,利用了線程局部存儲機制,稱爲線程私有數據(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()) << '\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類實現了基於腳本配置的功能。通過腳本可以完成對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

    網絡端口輸出

    文件通用選項:

    選項

    作用

    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-腳本配置

    腳本方式使用起來非常簡單,只要首先加載配置即可(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  ") )

    {

    }

     

    發表評論
    所有評論
    還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
    相關文章