青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

colorful

zc qq:1337220912

 

基于LGPL開源項目 Log4cpp安裝與使用

  【IT168 專稿】Log4cpp是一個開源的C++類庫,它提供了在C++程序中使用日志和跟蹤調試的功能。使用log4cpp,可以很便利地將日志或者跟蹤調試信息寫入字符流、內存字符串隊列、文件、回滾文件、調試器、Windows日志、syslog和遠程syslog服務器中。

  1、Log4cpp簡介

  Log4cpp是個基于LGPL的開源項目,移植自Java的日志處理跟蹤項目log4j,并保持了API上的一致。其類似的支持庫還包括Java(log4j),C++(log4cpp、log4cplus),C(log4c),python(log4p)等。

  Log4cpp有如下優點:

    • 提供了可擴展的多種日志記錄方式;
    • 提供了NDC(嵌套診斷上下文),可用于多線程、多場景的跟蹤調試;
    • 提供了完整的日志動態優先級控制,可隨時調整需要記錄的日志優先級;
    • 可通過配置文件完成所有配置并動態加載;
    • 性能優秀,內存占用小,經過編譯后的log4cpp.dll大小僅有160kb;
    • 代碼級的平臺無關性,Log4cpp源代碼經過編譯后,適用于大多數主流的操作系統和開發工具;
    • 概念清晰,學習和使用方便,熟練程序員一天之內即可很好地應用log4cpp進行開發。

  2、下載和安裝

  2.1 下載

  Log4cpp的主頁為:http://sourceforge.net/projects/log4cpp/

  下載版本0.3.5rc3,這個版本目前是最穩定的,版本1.0在VC中表現不穩定。下載后的包名字為:log4cpp-0.3.5rc3.tar.gz(源代碼包)和log4cpp-docs-0.3.5rc3.tar.gz(文檔壓縮包)。將它們解壓后放入D盤。

  2.2 在VC6中編譯Log4cpp

  進入D:\log4cpp-0.3.5rc3\msvc6目錄,打開VC6的工作區msvc6.dsw,將其中的工程都刪除,只保留log4cpp和log4cppDLL兩個工程。分別編譯它們的Debug和Release版本。

  在VC6中編譯Log4cpp會報錯,其實只有一個錯誤,即不能在頭文件中定義變量,同時給變量賦默認值。修改方法如下:將頭文件Priority.hh中的這一行:

#div_code img{border:0px;}
static const int MESSAGE_SIZE = 8;

  改為:

#div_code img{border:0px;}
static const int MESSAGE_SIZE;

  并在Priority.cpp中的所有include語句后加上:

#div_code img{border:0px;}
const int log4cpp::Priority::MESSAGE_SIZE = 8;

  編譯鏈接成功后會得到log4cppD.dll、log4cppD.lib(Debug版的dll和lib文件)和log4cpp.dll、log4cpp.lib(Release版的dll和lib文件)。新建目錄D:\log4cpp-0.3.5rc3\lib,將以上四個文件拷貝到該目錄下。

  在VC中添加設置lib和include路徑。

  將D:\log4cpp-0.3.5rc3\lib加入系統的Path路徑中。

  2.3 例子程序

  本文包含了大量的例子程序,這些程序被組織為多個工程,并放入了一個名為WxbLogDsw的VC工作區。所有代碼被打包為一個名為WxbLogDsw.rar的壓縮文件,解壓后可在VC6以上版本中打開此工程并進行編譯運行。


  3、Log4cpp的HelloWorld

  讓我們從一個簡單的例子開始,該例子將兩條日志信息寫入字符串流,該流會在標準控制臺cout上輸出,項目的名稱是HelloLog4Cpp:

#div_code img{border:0px;}
#include <iostream>
#include
"log4cpp/Category.hh"
#include
"log4cpp/OstreamAppender.hh"
#include
"log4cpp/BasicLayout.hh"
#include
"log4cpp/Priority.hh"
using namespace std;

int main(int argc, char* argv[])
{
    log4cpp::OstreamAppender
* osAppender = new log4cpp::OstreamAppender("osAppender", &cout);
    osAppender
->setLayout(new log4cpp::BasicLayout());
    
    log4cpp::Category
& root = log4cpp::Category::getRoot();
    root.addAppender(osAppender);
    root.setPriority(log4cpp::Priority::DEBUG);
    
    root.error(
"Hello log4cpp in a Error Message!");
    root.warn(
"Hello log4cpp in a Warning Message!");
    
    log4cpp::Category::shutdown();    
    
return 0;
}

  要順利編譯運行還有兩個地方需要設置,其一是引入的庫中加上log4cppD.lib(debug版dll庫的引入文件);其二是將C/C++的Code Generation中的Use Runtime library設置為“Debug Multithreaded DLL”。

  設置完成后編譯運行結果如下:

#div_code img{border:0px;}
1248337987 ERROR : Hello log4cpp in a Error Message!
1248337987 WARN : Hello log4cpp in a Warning Message!

  以上兩條日志格式很簡陋,要設置合乎心意的日志格式,請參考后續的PatternLayout章節。

  4、概念

  Log4cpp中的概念繼承自log4j,最重要的是Category(種類)、Appender(附加目的地)和Layout(布局)三個概念,此外還有Priority(優先級)和NDC(嵌套的診斷上下文)等。

  簡言之,Category負責向日志中寫入信息,Appender負責指定日志的目的地,Layout負責設定日志的格式,Priority被用來指定Category的優先級和日志的優先級, NDC則是一種用來區分不同場景中交替出現的日志的手段。

  Log4cpp記錄日志的原理如下:每個Category都有一個優先級,該優先級可以由setPriority方法設置,或者從其父Category中繼承而來。每條日志也有一個優先級,當Category記錄該條日志時,若日志優先級高于Category的優先級時,該日志被記錄,否則被忽略。系統中默認的優先級等級如下:

#div_code img{border:0px;}
        typedef enum {EMERG  = 0,
              FATAL  
= 0,
                      ALERT  
= 100,
                      CRIT  
= 200,
                      ERROR  
= 300,
                      WARN  
= 400,
                      NOTICE
= 500,
                      INFO  
= 600,
                      DEBUG  
= 700,
                      NOTSET
= 800
        }
PriorityLevel;

  注意:取值越小,優先級越高。例如一個Category的優先級為101,則所有EMERG、FATAL、ALERT日志都可以記錄下來,而其他則不能。

  Category、Appender和Layout三者的關系如下:系統中可以有多個Category,它們都是繼承自同一個根,每個Category負責記錄自己的日志;每個Category可以添加多個Appender,每個Appender指定了一個日志的目的地,例如文件、字符流或者Windows日志,當Category記錄一條日志時,該日志被寫入所有附加到此Category的Appender;每個Append都包含一個Layout,該Layout定義了這個Appender上日志的格式。

  現在重溫前面的HelloWorld程序,可以發現其流程如下:

    1. 創建一個Appender,并指定其包含的Layout;
    2. 從系統中得到Category的根,將Appender添加到該Category中;
    3. 設置Category的優先級;
    4. 記錄日志;
    5. 關閉Category。

  下面,我們按照Layout、Appender、Category、NDC的順序來依次介紹這些概念并給出例子。

  5、Layout(布局)

  首先回顧一下HelloWorld的日志格式,它使用了最簡單的BasicLayout:

#div_code img{border:0px;}
1248337987 ERROR  : Hello log4cpp in a Error Message!
1248337987 WARN  : Hello log4cpp in a Warning Message!

  上面的日志格式還可以,但顯然不是許多程序員心中理想的格式,許多人理想的格式應該是這樣的:

#div_code img{border:0px;}
2009-07-24 15:59:55,703: INFO infoCategory : system is running
2009-07-24 15:59:55,703: WARN infoCategory : system has a warning
2009-07-24 15:59:55,703: ERROR infoCategory : system has a error, can't find a file
2009-07-24 15:59:55,718: FATAL infoCategory : system has a fatal error, must be shutdown
2009-07-24 15:59:55,718: INFO infoCategory : system shutdown, you can find some information in system log

  要獲得上面的格式,必須使用比BasicLayout復雜的PatternLayout,而且要花一個小時來熟悉一下PatternLayout的格式定義方式,如果你認為值得的話。

  5.1 PatternLayout

  在介紹PatternLayout以前,首先來看看log4cpp中所有的Layout子類(Layout本身是個虛類),一共三個:BasicLayout、PatternLayout和SimpleLayout,其中SimapleLayout并不建議使用,而BaiscLayout過于簡單,因此如果程序員不自己擴展Layout的話,就只能使用PatternLayout了,值得慶幸的是,PatternLayout還是比較好用的。

  PatternLayout使用setConversionPattern函數來設置日志的輸出格式。該函數的聲明如下:

#div_code img{border:0px;}
void log4cpp::PatternLayout::setConversionPattern  (  const std::string &  conversionPattern   )  throw (ConfigureFailure) [virtual]

  其中參數類型為std::string,類似于C語言中的printf,使用格式化字符串來描述輸出格式,其具體含義如下:

#div_code img{border:0px;}
%c category;
%d 日期;日期可以進一步的設置格式,用花括號包圍,例如%d{%H:%M:%S,%l} 或者 %d{%d %m %Y %H:%M:%S,%l}。如果不設置具體日期格式,則如下默認格式被使用“Wed Jan 02 02:03:55 1980”。日期的格式符號與ANSI C函數strftime中的一致。但增加了一個格式符號%l,表示毫秒,占三個十進制位。
%m 消息;
%n 換行符,會根據平臺的不同而不同,但對于用戶透明;
%p 優先級;
%r 自從layout被創建后的毫秒數;
%R 從1970年1月1日0時開始到目前為止的秒數;
%u 進程開始到目前為止的時鐘周期數;
%x NDC。

  因此,要得到上述的理想格式,可以將setConversionPattern的參數設置為“%d: %p %c %x: %m%n”,其具體含義是“時間: 優先級 Category NDC: 消息 換行”。使用PatternLayout的例子程序如下,項目名稱是LayoutExam:

#div_code img{border:0px;}
#include <iostream>
#include
<log4cpp/Category.hh>
#include
<log4cpp/OstreamAppender.hh>
#include
<log4cpp/Priority.hh>
#include
<log4cpp/PatternLayout.hh>
using namespace std;

int main(int argc, char* argv[])
{
    log4cpp::OstreamAppender
* osAppender = new log4cpp::OstreamAppender("osAppender", &cout);
    
    log4cpp::PatternLayout
* pLayout = new log4cpp::PatternLayout();
    pLayout
->setConversionPattern("%d: %p %c %x: %m%n");
    osAppender
->setLayout(pLayout);
        
    log4cpp::Category
& root = log4cpp::Category::getRoot();
    log4cpp::Category
& infoCategory = root.getInstance("infoCategory");
    infoCategory.addAppender(osAppender);
    infoCategory.setPriority(log4cpp::Priority::INFO);

    infoCategory.info(
"system is running");
    infoCategory.warn(
"system has a warning");
    infoCategory.error(
"system has a error, can't find a file");
    infoCategory.fatal(
"system has a fatal error,must be shutdown");
    infoCategory.info(
"system shutdown,you can find some information in system log");

    log4cpp::Category::shutdown();
    
    
return 0;
}

  其運行結果即如下所示:

#div_code img{border:0px;}
2009-07-24 15:59:55,703: INFO infoCategory : system is running
2009-07-24 15:59:55,703: WARN infoCategory : system has a warning
2009-07-24 15:59:55,703: ERROR infoCategory : system has a error, can't find a file
2009-07-24 15:59:55,718: FATAL infoCategory : system has a fatal error, must be shutdown
2009-07-24 15:59:55,718: INFO infoCategory : system shutdown, you can find some information in system log

  6、Appender

  筆者認為Appender是log4cpp中最精彩的一個部分。我仔細閱讀了大部分Appender的源代碼并對設計者感到非常敬仰。

  Log4cpp中所有可直接使用的Appender列表如下:

#div_code img{border:0px;}
log4cpp::IdsaAppender             // 發送到IDS或者
log4cpp::FileAppender             // 輸出到文件
log4cpp::RollingFileAppender     // 輸出到回卷文件,即當文件到達某個大小后回卷
log4cpp::OstreamAppender         // 輸出到一個ostream類
log4cpp::RemoteSyslogAppender     // 輸出到遠程syslog服務器
log4cpp::StringQueueAppender     // 內存隊列
log4cpp::SyslogAppender         // 本地syslog
log4cpp::Win32DebugAppender     // 發送到缺省系統調試器
log4cpp::NTEventLogAppender     // 發送到win 事件日志

  其中SyslogAppender和RemoteSyslogAppender需要與Syslog配合使用,因此這里不介紹。順便提一句,Syslog是類Unix系統的一個核心服務,用來提供日志服務,在Windows系統中并沒有直接提供支持,當然可以用相關工具提供Windows系統中的syslog服務。

  IdsaAppender的功能是將日志寫入Idsa服務,這里也不介紹。因此主要介紹以下Appender:

#div_code img{border:0px;}
log4cpp::FileAppender             // 輸出到文件
log4cpp::RollingFileAppender     // 輸出到回卷文件,即當文件到達某個大小后回卷
log4cpp::OstreamAppender         // 輸出到一個ostream類
log4cpp::StringQueueAppender     // 內存隊列
log4cpp::Win32DebugAppender     // 發送到缺省系統調試器
log4cpp::NTEventLogAppender     // 發送到win 事件日志

  6.1 OstreamAppender

  在我剛剛學習C/C++編程時,一位老師告訴我,如果沒有好用的調試工具,就在代碼中加入printf語句,將調試信息打印出來(當時在linux下面,確實沒有什么易用的c++調試工具)。現在有了OstreamAppender,一切都好辦了,它可以將日志記入一個流,如果該流恰好是cout,則會在標準控制臺上輸出。比printf優越的是,除了輸出消息外,還可以輕松的輸出時間、時鐘數、優先級等大量有用信息。

  OstreamAppender的使用非常簡單,在前面的HelloWorld程序中已經見過,創建一個OstreamAppender的具體方法如下:

#div_code img{border:0px;}
log4cpp::OstreamAppender* osAppender = new log4cpp::OstreamAppender("osAppender", &cout);

  第一個參數指定OstreamAppender的名稱,第二個參數指定它關聯的流的指針。

  6.2 StringQueueAppender

  后來一位高手又告訴我“在調試多線程程序時,不能隨意使用printf”。因為printf導致IO中斷,會使得本線程掛起,其花費的時間比一條普通指令多數千倍,若多個線程同時運行,則嚴重干擾了線程間的運行方式。所以調試多線程程序時,最好是將所有調試信息按順序記入內存中,程序結束時依次打印出來。為此當時我們還寫了一個小工具,沒想到時隔多年,我碰上了StringQueueAppender。

  我很懷疑StringQueueAppender被設計出來就是用于記錄多線程程序或者實時程序的日志,雖然log4cpp的文檔中并沒有明確指出這一點。StringQueueAppender的功能是將日志記錄到一個字符串隊列中,該字符串隊列使用了STL中的兩個容器,即字符串容器std::string和隊列容器std::queue,具體如下:

#div_code img{border:0px;}
std::queue<std::string> _queue;

   _queue變量是StringQueueAppender類中用于具體存儲日志的內存隊列。StringQueueAppender的使用方法與OstreamAppender類似,其創建函數只接收一個參數“名稱”,記錄完成后需要程序員自己從隊列中取出每條日志,例子程序StringQueueAppenderExam如下:

#div_code img{border:0px;}
#include <iostream>
#include
<log4cpp/Category.hh>
#include
<log4cpp/OstreamAppender.hh>
#include
<log4cpp/BasicLayout.hh>
#include
<log4cpp/Priority.hh>
#include
<log4cpp/StringQueueAppender.hh>
using namespace std;

int main(int argc, char* argv[])
{
    log4cpp::StringQueueAppender* strQAppender = new log4cpp::StringQueueAppender("strQAppender");
    strQAppender->setLayout(new log4cpp::BasicLayout());
    
    log4cpp::Category& root = log4cpp::Category::getRoot();
    root.addAppender(strQAppender);
    root.setPriority(log4cpp::Priority::DEBUG);
    
    root.error("Hello log4cpp in a Error Message!");
    root.warn("Hello log4cpp in a Warning Message!");
    
    cout
<<"Get message from Memory Queue!"<<endl;
    cout<<"-------------------------------------------"<<endl;
    queue<string
>& myStrQ = strQAppender->getQueue();
    while(!myStrQ.empty())
    {
        cout
<<myStrQ.front();
        myStrQ.pop();
    }

    log4cpp::Category::shutdown();    
    return 0;
}

  程序輸出為:

#div_code img{border:0px;}
Get message from Memory Queue!
-------------------------------------------
1248839389 ERROR  : Hello log4cpp in a Error Message!
1248839389 WARN  : Hello log4cpp in a Warning Message!

  6.3 FileAppender和RollingFileAppender

  FileAppender和RollingFileAppender是log4cpp中最常用的兩個Appender,其功能是將日志寫入文件中。它們之間唯一的區別就是前者會一直在文件中記錄日志(直到操作系統承受不了為止),而后者會在文件長度到達指定值時循環記錄日志,文件長度不會超過指定值(默認的指定值是10M byte)。

  FileAppender的創建函數如下:

#div_code img{border:0px;}
        /**
           Constructs a FileAppender.
           @param name the name of the Appender.
           @param fileName the name of the file to which the Appender has
           to log.
           @param append whether the Appender has to truncate the file or
           just append to it if it already exists. Defaults to 'true'.
           @param mode file mode to open the logfile with. Defaults to 00644.
        **/  
        FileAppender(const std::string& name, const std::string& fileName,
                     bool append = true, mode_t mode = 00644);

  一般僅使用前兩個參數,即“名稱”和“日志文件名”。第三個參數指示是否在日志文件后繼續記入日志,還是清空原日志文件再記錄。第四個參數說明文件的打開方式。

  RollingFileAppender的創建函數如下:

#div_code img{border:0px;}
        RollingFileAppender(const std::string& name,
                            const std::string& fileName,
                            size_t maxFileSize = 10*1024*1024,
                            unsigned int maxBackupIndex = 1,
                            bool append = true,
                            mode_t mode = 00644);

  它與FileAppender的創建函數很類似,但是多了兩個參數:maxFileSize指出了回滾文件的最大值;maxBackupIndex指出了回滾文件所用的備份文件的最大個數。所謂備份文件,是用來保存回滾文件中因為空間不足未能記錄的日志,備份文件的大小僅比回滾文件的最大值大1kb。所以如果maxBackupIndex取值為3,則回滾文件(假設其名稱是rollwxb.log,大小為100kb)會有三個備份文件,其名稱分別是rollwxb.log.1,rollwxb.log.2和rollwxb.log.3,大小為101kb。另外要注意:如果maxBackupIndex取值為0或者小于0,則回滾文件功能會失效,其表現如同FileAppender一樣,不會有大小的限制。這也許是一個bug。

  例子程序FileAppenderExam如下:

#div_code img{border:0px;}
#include <iostream>
#include
<log4cpp/Category.hh>
#include
<log4cpp/Appender.hh>
#include
<log4cpp/FileAppender.hh>
#include
<log4cpp/Priority.hh>
#include
<log4cpp/PatternLayout.hh>
#include
<log4cpp/RollingFileAppender.hh>
using namespace std;

int main(int argc, char* argv[])
{
    log4cpp::PatternLayout* pLayout1 = new log4cpp::PatternLayout();
    pLayout1->setConversionPattern("%d: %p %c %x: %m%n");

    log4cpp::PatternLayout* pLayout2 = new log4cpp::PatternLayout();
    pLayout2->setConversionPattern("%d: %p %c %x: %m%n");
    
    log4cpp::Appender* fileAppender = new log4cpp::FileAppender("fileAppender","wxb.log");
    fileAppender->setLayout(pLayout1);

    log4cpp::RollingFileAppender* rollfileAppender = new log4cpp::RollingFileAppender(
        "rollfileAppender","rollwxb.log",5*1024,1);
    rollfileAppender->setLayout(pLayout2);
    
    log4cpp::Category& root = log4cpp::Category::getRoot().getInstance("RootName");
    root.addAppender(fileAppender);
    root.addAppender(rollfileAppender);
    root.setPriority(log4cpp::Priority::DEBUG);

    for (int i = 0; i
< 100; i++)
    {
        string strError;
        ostringstream oss;
        oss<<i<<":Root Error Message!";
        strError
= oss.str();
        
root.error(strError);
    }
    
    log4cpp::Category::shutdown();
    return 0;
}

  程序運行后會產生兩個日志文件wxb.log和rollwxb.log,以及一個備份文件rollwxb.log.1。wxb.log的大小為7kb,記錄了所有100條日志;rollwxb.log大小為2kb,記錄了最新的22條日志;rollwxb.log.1大小為6kb,記錄了舊的78條日志。

  6.4 Win32DebugAppender

  Win32DebugAppender是一個用于調試的Appender,其功能是向Windows的調試器中寫入日志,目前支持MSVC和Borland中的調試器。創建Win32DebugAppender僅需要一個參數“名稱”,其使用非常簡單,下面是例子代碼DebugAppenderExam:

#div_code img{border:0px;}
#include <iostream>
#include
<log4cpp/Category.hh>
#include
<log4cpp/Appender.hh>
#include
<log4cpp/Win32DebugAppender.hh>
#include
<log4cpp/Priority.hh>
#include
<log4cpp/PatternLayout.hh>
using namespace std;

int main(int argc, char* argv[])
{
    log4cpp::PatternLayout* pLayout1 = new log4cpp::PatternLayout();
    pLayout1->setConversionPattern("%d: %p %c %x: %m%n");
    
    log4cpp::Appender* debugAppender = new log4cpp::Win32DebugAppender("debugAppender");
    debugAppender->setLayout(pLayout1);
    
    log4cpp::Category& root = log4cpp::Category::getRoot().getInstance("RootName");
    root.addAppender(debugAppender);
    root.setPriority(log4cpp::Priority::DEBUG);
    
    root.error("Root Error Message!");
    root.warn("Root Warning Message!");
    
    log4cpp::Category::shutdown();
    return 0;
}

  在VC6中調試該代碼會得到如下圖所示的調試信息,注意最下方的兩行調試信息:

Appender 

  6.5 NTEventLogAppender

   該Appender可以將日志發送到windows的日志,在運行程序后可以打開windows的計算機管理?系統工具?事件查看器?應用程序,可以看到下圖,注意圖中第一行和第二行的兩個日志。

Appender 

  例子程序NTAppenderExam如下:

#div_code img{border:0px;}
#include <iostream>
#include
<log4cpp/Category.hh>
#include
<log4cpp/Appender.hh>
#include
<log4cpp/NTEventLogAppender.hh>
#include
<log4cpp/Priority.hh>
#include
<log4cpp/PatternLayout.hh>
using namespace std;

int main(int argc, char* argv[])
{
    log4cpp::PatternLayout* pLayout1 = new log4cpp::PatternLayout();
    pLayout1->setConversionPattern("%d: %p %c %x: %m%n");
    
    log4cpp::Appender* ntAppender = new log4cpp::NTEventLogAppender("debugAppender","wxb_ntlog");
    ntAppender->setLayout(pLayout1);
    
    log4cpp::Category& root = log4cpp::Category::getRoot().getInstance("RootName");
    root.addAppender(ntAppender);
    root.setPriority(log4cpp::Priority::DEBUG);
    
    root.error("Root Error Message!");
    root.warn("Root Warning Message!");
    
    log4cpp::Category::shutdown();
    return 0;
}

  7、Category

  Log4cpp中有一個總是可用并實例化好的Category,即根Category。使用log4cpp::Category::getRoot()可以得到根Category。在大多數情況下,一個應用程序只需要一個日志種類(Category),但是有時也會用到多個Category,此時可以使用根Category的getInstance方法來得到子Category。不同的子Category用于不同的場合。一個簡單的例子CategoryExam如下所示:

#div_code img{border:0px;}
#include <iostream>
#include
<log4cpp/Category.hh>
#include
<log4cpp/OstreamAppender.hh>
#include
<log4cpp/FileAppender.hh>
#include
<log4cpp/BasicLayout.hh>
#include
<log4cpp/Priority.hh>
using namespace std;

int main(int argc, char* argv[])
{
    log4cpp::OstreamAppender* osAppender1 = new log4cpp::OstreamAppender("osAppender1",
&cout);
    osAppender1->setLayout(new log4cpp::BasicLayout());

    log4cpp::OstreamAppender* osAppender2 = new log4cpp::OstreamAppender("osAppender2",
&cout);
    osAppender2->setLayout(new log4cpp::BasicLayout());

    log4cpp::Category& root = log4cpp::Category::getRoot();
    root.setPriority(log4cpp::Priority::DEBUG);
    
    log4cpp::Category& sub1 = root.getInstance("sub1");
     sub1.addAppender(osAppender1);
     sub1.setPriority(log4cpp::Priority::DEBUG);
    sub1.error("sub error");

    log4cpp::Category& sub2 = root.getInstance("sub2");
    sub2.addAppender(osAppender2);
    sub2.setPriority(101);
    sub2.warn("sub2 warning");
    sub2.fatal("sub2 fatal");
    sub2.alert("sub2 alert");
    sub2.crit("sub2 crit");

    log4cpp::Category::shutdown();    
    return 0;
}

  運行結果如下:

#div_code img{border:0px;}
1248869982 ERROR sub1 : sub error
1248869982 FATAL sub2 : sub2 fatal
1248869982 ALERT sub2 : sub2 alert

   這個例子中共有三個Category,分別是根、sub1和sub2,其中sub1記錄了一條日志,sub2記錄了兩條日志。Sub2另外兩個日志由于優先級不夠未能記錄。

   8、NDC

   NDC是nested Diagnostic Context的縮寫,意思是“嵌套的診斷上下文”。NDC是一種用來區分不同源代碼中交替出現的日志的手段。當一個服務端程序同時記錄好幾個并行客戶時,輸出的日志會混雜在一起難以區分。但如果不同上下文的日志入口擁有一個特定的標識,則可以解決這個問題。NDC就是在這種情況下發揮作用。注意NDC是以線程為基礎的,每個線程擁有一個NDC,每個NDC的操作僅對執行該操作的線程有效。

  NDC的幾個有用的方法是:push、pop、get和clear。注意它們都是靜態函數:

  Push可以讓當前線程進入一個NDC,如果該NDC不存在,則根據push的參數創建一個NDC并進入;如果再調用一次push,則進入子NDC;

  Pop可以讓當前線程從上一級NDC中退出,但是一次只能退出一級。

  Clear可以讓當前線程從所有嵌套的NDC中退出。

  Get可以得到當前NDC的名字,如果有嵌套,則不同級別之間的名字用空格隔開。

  一個簡單的例子NDCExam如下:

#div_code img{border:0px;}
#include <iostream>
#include
<log4cpp/NDC.hh>

using namespace log4cpp;

int main(int argc, char** argv) {
    std::cout
<< "1. empty NDC: " << NDC::get() << std::endl;
    
    NDC::push(
"context1");
    std::cout
<< "2. push context1: " << NDC::get() << std::endl;
    
    NDC::push(
"context2");
    std::cout
<< "3. push context2: " << NDC::get() << std::endl;
    NDC::push(
"context3");
    std::cout
<< "4. push context3: " << NDC::get() << std::endl;
    std::cout
<< "5. get depth: " << NDC::getDepth() << std::endl;
    
    std::cout
<< "6. pop: " << NDC::pop() << std::endl;
    
    std::cout
<< "7. after pop:"<<NDC::get()<<std::endl;
    
    NDC::clear();
    std::cout
<< "8. clear: " << NDC::get() << std::endl;
    
    
return 0;
}

  該例子來自log4cpp的例子程序,我做了簡單的修改。在記錄日志的時候,可以從NDC中得知當前線程的嵌套關系。


  9、Log4cpp的自動內存管理

   9.1 項目的多線程設置

   VC中必須將項目設置為Debug MultiThreaded DLL,總之這個設置必須與你使用的Log4cpp庫一致。如果你使用的是Release版本的log4cpp.dll,則應該設置為MultiThreaded DLL。

  否則在程序結束時會報錯,報錯處的調用堆棧為:

#div_code img{border:0px;}
log4cpp::BasicLayout::`vector deleting destructor'(unsigned int 1) + 122 bytes
log4cpp::LayoutAppender::~LayoutAppender() line 21 + 35 bytes
log4cpp::OstreamAppender::~OstreamAppender() line 28 + 15 bytes
log4cpp::OstreamAppender::`vector deleting destructor'(unsigned int 1) + 103 bytes
log4cpp::Category::removeAllAppenders() line 159 + 39 bytes
log4cpp::HierarchyMaintainer::shutdown() line 101 + 27 bytes
log4cpp::HierarchyMaintainer::~HierarchyMaintainer() line 36

  9.2 Log4cpp的內存對象管理

  也許讀者已經注意到,在前面的所有代碼中,log4cpp中所有動態分配的對象都沒有手動釋放。

  Log4cpp中new出來的Category、Appender和Layout都不需要手動釋放,因為Log4cpp使用了一個內部類來管理這些對象。此類的名稱是HierarchyMaintainer,它負責管理Category的繼承關系,在程序結束時,HierarchyMaintainer會依次釋放所有Category,而Category則會依次釋放擁有的有效Appender,Appender則會釋放所有附屬的Layout。如果程序員手動釋放這些對象,則會造成內存報錯。

  從下面的代碼可以看出這個特征:

#div_code img{border:0px;}
appender->setLayout(new log4cpp::BasicLayout());

  這個new出來的BasicLayout根本就沒有保存其指針,所以它只能被log4cpp的內存管理類HierarchyMaintainer釋放。

  了解到HierarchyMaintainer的內存管理方法后,程序員在使用log4cpp時應該遵循以下幾個使用原則:

  1. 不要手動釋放Category、Appender和Layout;

  2. 同一個Appender不要加入多個Category,否則它會被釋放多次從而導致程序崩潰;

  3. 同一個Layout不要附著到多個Appender上,否則也會被釋放多次導致程序崩潰;

  下面這個簡單的程序PointerErrorExam會造成經典的崩潰:

#div_code img{border:0px;}
#include <iostream>
#include
<log4cpp/Category.hh>
#include
<log4cpp/OstreamAppender.hh>
#include
<log4cpp/BasicLayout.hh>
#include
<log4cpp/Priority.hh>
using namespace std;

int main(int argc, char* argv[])
{
    log4cpp::OstreamAppender* osAppender = new log4cpp::OstreamAppender("osAppender",
&cout);
    osAppender->setLayout(new log4cpp::BasicLayout());
    
    log4cpp::Category& root = log4cpp::Category::getRoot();
    root.setPriority(log4cpp::Priority::DEBUG);
    
    log4cpp::Category& sub1 = root.getInstance("sub1");
    sub1.addAppender(osAppender);
    sub1.error("sub1 error");
    
    log4cpp::Category& sub2 = root.getInstance("sub2");
    sub2.addAppender(osAppender);
    sub2.warn("sub2 warning");

    log4cpp::Category::shutdown();    
    return 0;
}

  運行后出現對話框:

#div_code img{border:0px;}
PointerErrorExam.exe 遇到問題需要關閉。我們對此引起的不便表示抱歉。

  其原因就是osAppender被同時加入了sub1和sub2這兩個Category。

  9.3 log4cpp::Category::shutdown()

  在不使用log4cpp時可調用log4cpp::Category::shutdown(),其功能如同HierarchyMaintainer的內存清理。但如果不手動調用,在程序結束時HierarchyMaintainer會調用Category的析構函數來釋放所有Appender。

  10、利用配置文件定制日志

  如同log4j一樣,log4cpp也可以讀取配置文件來定制Category、Appender和Layout對象。其配置文件格式基本類似于log4j,一個簡單的配置文件log4cpp.conf例子如下(來自log4cpp的API手冊):

#div_code img{border:0px;}
# a simple test config
       log4j.rootCategory=DEBUG, rootAppender
       log4j.category.sub1=A1
       log4j.category.sub2=INFO
       log4j.category.sub1.sub2=ERROR, A2
       log4j.appender.rootAppender=org.apache.log4j.ConsoleAppender
       log4j.appender.rootAppender.layout=org.apache.log4j.BasicLayout
       log4j.appender.A1=org.apache.log4j.FileAppender
       log4j.appender.A1.fileName=A1.log
       log4j.appender.A1.layout=org.apache.log4j.BasicLayout
       log4j.appender.A2=org.apache.log4j.ConsoleAppender
       log4j.appender.A2.layout=org.apache.log4j.PatternLayout
       log4j.appender.A2.layout.ConversionPattern=The message %m at time %d%n

  這是一個標準的java屬性文件。讀取配置文件要依賴PropertyConfigurator和SimpleConfigurator類。這里僅介紹PropertyConfigurator,其使用方法代碼ConfigFileExam所示(該代碼來自《便利的開發工具-log4cpp快速使用指南》一文):

#div_code img{border:0px;}
#include <iostream>
#include
<log4cpp/Category.hh>
#include
<log4cpp/PropertyConfigurator.hh>

int main(int argc, char* argv[])
{
    
try
    
{
        log4cpp::PropertyConfigurator::configure(
"./log4cpp.conf");
    }

    
catch(log4cpp::ConfigureFailure& f)
    
{
        std::cout
<< "Configure Problem " << f.what() << std::endl;
        
return -1;
    }

    
    log4cpp::Category
& root = log4cpp::Category::getRoot();
    
    log4cpp::Category
& sub1 = log4cpp::Category::getInstance(std::string("sub1"));
    log4cpp::Category
& sub3 = log4cpp::Category::getInstance(std::string("sub1.sub2"));

    sub1.info(
"This is some info");
    sub1.alert(
"A warning");
    
    
// sub3 only have A2 appender.
    sub3.debug("This debug message will fail to write");
    sub3.alert(
"All hands abandon ship");
    sub3.critStream()
<< "This will show up << as " << 1 << " critical message"
        
<< log4cpp::CategoryStream::ENDLINE;
    sub3
<< log4cpp::Priority::ERROR
        
<< "And this will be an error"  
        
<< log4cpp::CategoryStream::ENDLINE;
    sub3.log(log4cpp::Priority::WARN,
"This will be a logged warning");
    
    
return 0;
}

  該程序首先讀入了配置文件log4cpp.conf,從中得到了所有Category、Appender和Layout的優先級和相互附屬關系,然后輸出了一些日志,其運行結果如下:

#div_code img{border:0px;}
1248875649 INFO sub1 : This is some info
1248875649 ALERT sub1 : A warning
The message All hands abandon ship at time 2009-07-29 21:54:09,515
1248875649 ALERT sub1.sub2 : All hands abandon ship
The message This will show up
<< as 1 critical message at time 2009-07-29 21:54:
09,531
1248875649 CRIT sub1.sub2 : This will show up << as 1 critical message
The message And this will be an error at time 2009-07-29 21:54:09,531
1248875649 ERROR sub1.sub2 : And this will be an error

  11、DLL的版本問題

  若在VC6中使用Log4cpp的DLL,則必須使用VC6編譯鏈接生成的DLL,不能使用MSVS2008中生成的DLL,反之也是一樣。否則會在運行時報錯。

  為此專門提供了兩個版本的DLL,供大家使用。

  12、小結

  Log4cpp是一個小巧的c++庫,易于上手,使用方便,不依賴其他庫,具有跨平臺性,并可與log4j、log4c、log4p等語言族共享其概念與使用方法。實在是進行日志記錄、程序調試的利器。

posted on 2012-03-10 11:52 多彩人生 閱讀(3084) 評論(0)  編輯 收藏 引用

導航

統計

常用鏈接

留言簿(3)

隨筆分類

隨筆檔案

搜索

最新評論

閱讀排行榜

評論排行榜

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            亚洲国产视频一区| 亚洲亚洲精品三区日韩精品在线视频| 日韩午夜在线播放| 亚洲国语精品自产拍在线观看| 女人色偷偷aa久久天堂| 欧美成人69av| 欧美三区美女| 久久综合精品国产一区二区三区| 亚洲一区二区三区久久| 久久人人爽人人爽| 国产一区二区三区在线观看免费视频 | 国产精品久久久久久久久久三级 | 久久久久久久久久久久久9999| 一本大道av伊人久久综合| 欧美大秀在线观看| 日韩亚洲欧美在线观看| 最新69国产成人精品视频免费| 久久综合九色九九| 91久久精品一区| 亚洲高清不卡| 欧美精品首页| 亚洲在线观看视频网站| 亚洲图片在区色| 国产精一区二区三区| 亚洲欧美视频在线| 欧美在线视频免费观看| 精品不卡一区二区三区| 亚洲成人自拍视频| 欧美视频一区二区三区在线观看| 香蕉久久夜色精品| 久久精品中文| 99国产精品自拍| 亚洲一区自拍| 在线成人激情| 一区二区三区精密机械公司| 国产精品久久久久久久午夜| 久久久91精品| 欧美精品一区二| 欧美一区二区日韩| 欧美va亚洲va香蕉在线| 在线亚洲欧美视频| 亚洲欧美日韩综合一区| 性做久久久久久免费观看欧美| 国语自产偷拍精品视频偷| 欧美成人精品1314www| 欧美精品一区三区| 欧美在线高清| 欧美ab在线视频| 亚洲欧美在线另类| 欧美影院久久久| 亚洲国产日韩欧美在线99| 中文一区字幕| 在线成人激情黄色| 亚洲欧美精品在线| 亚洲老板91色精品久久| 校园春色综合网| 日韩香蕉视频| 久久九九国产精品| 亚洲免费一在线| 欧美承认网站| 久久全国免费视频| 国产精品久久一级| 亚洲精品一二三| 亚洲国产经典视频| 午夜国产精品影院在线观看| 亚洲久久在线| 免费久久久一本精品久久区| 午夜精品国产| 欧美日韩精品一本二本三本| 男人的天堂成人在线| 国产精品入口尤物| 日韩一区二区免费看| 亚洲第一区在线| 欧美一区二区三区四区在线| 亚洲伊人第一页| 欧美日韩人人澡狠狠躁视频| 欧美福利影院| 在线国产精品一区| 久久精品国产99精品国产亚洲性色 | 亚洲欧美日韩直播| 欧美区日韩区| 91久久久国产精品| 亚洲高清av在线| 久久精品国产99国产精品| 欧美有码在线视频| 国产精品亚发布| 亚洲欧美国产日韩中文字幕| 亚洲在线一区二区三区| 欧美日韩国产综合视频在线观看中文 | 尤物九九久久国产精品的分类| 亚洲综合精品| 欧美在线视频观看| 国产一区91精品张津瑜| 亚洲欧美中文字幕| 久久精品国产精品亚洲精品| 国产精品丝袜xxxxxxx| 亚洲视频网站在线观看| 午夜久久tv| 欧美激情二区三区| 久久久久久久综合| 狠狠综合久久av一区二区老牛| 香蕉乱码成人久久天堂爱免费 | 亚洲欧洲三级| 欧美成人一区二区三区在线观看 | 91久久在线视频| 亚洲深夜福利网站| 国产精品人人爽人人做我的可爱| 亚洲字幕一区二区| 免费成人激情视频| 99在线精品视频| 国产精品日韩欧美| 久久手机免费观看| 亚洲精品久久久久久下一站 | 午夜伦理片一区| 麻豆精品一区二区av白丝在线| 亚洲国产成人av在线 | 亚洲欧美日韩国产一区二区三区 | 在线看国产一区| 欧美日韩国产另类不卡| 亚洲欧美日本在线| 嫩草国产精品入口| 一区二区av在线| 国产在线国偷精品产拍免费yy| 免费观看欧美在线视频的网站| 亚洲免费电影在线观看| 欧美中文在线观看| 亚洲人精品午夜| 国产欧美日韩一区| 欧美韩日亚洲| 欧美在线观看视频在线| 亚洲国产一二三| 欧美影片第一页| 日韩视频在线观看一区二区| 国产精品最新自拍| 欧美区一区二区三区| 欧美一区二区三区免费视频| 亚洲经典视频在线观看| 欧美一区二区三区啪啪| 亚洲日本一区二区| 国产主播一区二区| 欧美网站在线观看| 欧美11—12娇小xxxx| 性久久久久久久| 99在线热播精品免费| 欧美黑人国产人伦爽爽爽| 欧美一区二区三区日韩| 99视频日韩| 亚洲高清123| 好吊妞这里只有精品| 国产精品vvv| 欧美日韩国产色站一区二区三区| 久久成人精品| 亚洲欧美日本日韩| 亚洲午夜三级在线| 亚洲欧洲一区二区在线观看| 狂野欧美性猛交xxxx巴西| 午夜精品在线看| 亚洲综合成人婷婷小说| 亚洲免费电影在线| 久久国产精品网站| 国产精品欧美久久久久无广告| 欧美在线啊v| 亚洲视频在线一区| 亚洲国产综合91精品麻豆| 久久久久久久999精品视频| 亚洲视频在线播放| 亚洲区欧美区| 韩国成人福利片在线播放| 国产精品国产馆在线真实露脸 | 亚洲午夜视频| 久久视频在线看| 久久久999精品免费| 欧美精品导航| 久久中文久久字幕| 最新国产精品拍自在线播放| 欧美激情亚洲自拍| 夜夜精品视频一区二区| 亚洲一区综合| 亚洲一区一卡| 野花国产精品入口| 欧美黄色免费| 久久精品中文字幕免费mv| 亚洲老司机av| 亚洲国产一区二区三区高清| 美女亚洲精品| 亚洲东热激情| 亚洲福利小视频| 亚洲另类自拍| 亚洲国产美女久久久久| 欧美成人dvd在线视频| 欧美xart系列高清| 欧美α欧美αv大片| 久久久精品国产免大香伊 | 99re8这里有精品热视频免费| 亚洲激情社区| 亚洲精品中文字幕女同| 亚洲精品亚洲人成人网| 亚洲视频一区二区| 午夜精品理论片| 久久久久国产精品人|