• <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>

            colorful

            zc qq:1337220912

             

            基于LGPL開源項(xiàng)目 Log4cpp安裝與使用

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

              1、Log4cpp簡(jiǎn)介

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

              Log4cpp有如下優(yōu)點(diǎn):

                • 提供了可擴(kuò)展的多種日志記錄方式;
                • 提供了NDC(嵌套診斷上下文),可用于多線程、多場(chǎng)景的跟蹤調(diào)試;
                • 提供了完整的日志動(dòng)態(tài)優(yōu)先級(jí)控制,可隨時(shí)調(diào)整需要記錄的日志優(yōu)先級(jí);
                • 可通過配置文件完成所有配置并動(dòng)態(tài)加載;
                • 性能優(yōu)秀,內(nèi)存占用小,經(jīng)過編譯后的log4cpp.dll大小僅有160kb;
                • 代碼級(jí)的平臺(tái)無(wú)關(guān)性,Log4cpp源代碼經(jīng)過編譯后,適用于大多數(shù)主流的操作系統(tǒng)和開發(fā)工具;
                • 概念清晰,學(xué)習(xí)和使用方便,熟練程序員一天之內(nèi)即可很好地應(yīng)用log4cpp進(jìn)行開發(fā)。

              2、下載和安裝

              2.1 下載

              Log4cpp的主頁(yè)為:http://sourceforge.net/projects/log4cpp/

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

              2.2 在VC6中編譯Log4cpp

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

              在VC6中編譯Log4cpp會(huì)報(bào)錯(cuò),其實(shí)只有一個(gè)錯(cuò)誤,即不能在頭文件中定義變量,同時(shí)給變量賦默認(rèn)值。修改方法如下:將頭文件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語(yǔ)句后加上:

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

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

              在VC中添加設(shè)置lib和include路徑。

              將D:\log4cpp-0.3.5rc3\lib加入系統(tǒng)的Path路徑中。

              2.3 例子程序

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


              3、Log4cpp的HelloWorld

              讓我們從一個(gè)簡(jiǎn)單的例子開始,該例子將兩條日志信息寫入字符串流,該流會(huì)在標(biāo)準(zhǔn)控制臺(tái)cout上輸出,項(xiàng)目的名稱是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;
            }

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

              設(shè)置完成后編譯運(yùn)行結(jié)果如下:

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

              以上兩條日志格式很簡(jiǎn)陋,要設(shè)置合乎心意的日志格式,請(qǐng)參考后續(xù)的PatternLayout章節(jié)。

              4、概念

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

              簡(jiǎn)言之,Category負(fù)責(zé)向日志中寫入信息,Appender負(fù)責(zé)指定日志的目的地,Layout負(fù)責(zé)設(shè)定日志的格式,Priority被用來(lái)指定Category的優(yōu)先級(jí)和日志的優(yōu)先級(jí), NDC則是一種用來(lái)區(qū)分不同場(chǎng)景中交替出現(xiàn)的日志的手段。

              Log4cpp記錄日志的原理如下:每個(gè)Category都有一個(gè)優(yōu)先級(jí),該優(yōu)先級(jí)可以由setPriority方法設(shè)置,或者從其父Category中繼承而來(lái)。每條日志也有一個(gè)優(yōu)先級(jí),當(dāng)Category記錄該條日志時(shí),若日志優(yōu)先級(jí)高于Category的優(yōu)先級(jí)時(shí),該日志被記錄,否則被忽略。系統(tǒng)中默認(rèn)的優(yōu)先級(jí)等級(jí)如下:

            #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;

              注意:取值越小,優(yōu)先級(jí)越高。例如一個(gè)Category的優(yōu)先級(jí)為101,則所有EMERG、FATAL、ALERT日志都可以記錄下來(lái),而其他則不能。

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

              現(xiàn)在重溫前面的HelloWorld程序,可以發(fā)現(xiàn)其流程如下:

                1. 創(chuàng)建一個(gè)Appender,并指定其包含的Layout;
                2. 從系統(tǒng)中得到Category的根,將Appender添加到該Category中;
                3. 設(shè)置Category的優(yōu)先級(jí);
                4. 記錄日志;
                5. 關(guān)閉Category。

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

              5、Layout(布局)

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

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

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

            #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復(fù)雜的PatternLayout,而且要花一個(gè)小時(shí)來(lái)熟悉一下PatternLayout的格式定義方式,如果你認(rèn)為值得的話。

              5.1 PatternLayout

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

              PatternLayout使用setConversionPattern函數(shù)來(lái)設(shè)置日志的輸出格式。該函數(shù)的聲明如下:

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

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

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

              因此,要得到上述的理想格式,可以將setConversionPattern的參數(shù)設(shè)置為“%d: %p %c %x: %m%n”,其具體含義是“時(shí)間: 優(yōu)先級(jí) Category NDC: 消息 換行”。使用PatternLayout的例子程序如下,項(xiàng)目名稱是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;
            }

              其運(yùn)行結(jié)果即如下所示:

            #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

              筆者認(rèn)為Appender是log4cpp中最精彩的一個(gè)部分。我仔細(xì)閱讀了大部分Appender的源代碼并對(duì)設(shè)計(jì)者感到非常敬仰。

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

            #div_code img{border:0px;}
            log4cpp::IdsaAppender             // 發(fā)送到IDS或者
            log4cpp::FileAppender             // 輸出到文件
            log4cpp::RollingFileAppender     // 輸出到回卷文件,即當(dāng)文件到達(dá)某個(gè)大小后回卷
            log4cpp::OstreamAppender         // 輸出到一個(gè)ostream類
            log4cpp::RemoteSyslogAppender     // 輸出到遠(yuǎn)程syslog服務(wù)器
            log4cpp::StringQueueAppender     // 內(nèi)存隊(duì)列
            log4cpp::SyslogAppender         // 本地syslog
            log4cpp::Win32DebugAppender     // 發(fā)送到缺省系統(tǒng)調(diào)試器
            log4cpp::NTEventLogAppender     // 發(fā)送到win 事件日志

              其中SyslogAppender和RemoteSyslogAppender需要與Syslog配合使用,因此這里不介紹。順便提一句,Syslog是類Unix系統(tǒng)的一個(gè)核心服務(wù),用來(lái)提供日志服務(wù),在Windows系統(tǒng)中并沒有直接提供支持,當(dāng)然可以用相關(guān)工具提供Windows系統(tǒng)中的syslog服務(wù)。

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

            #div_code img{border:0px;}
            log4cpp::FileAppender             // 輸出到文件
            log4cpp::RollingFileAppender     // 輸出到回卷文件,即當(dāng)文件到達(dá)某個(gè)大小后回卷
            log4cpp::OstreamAppender         // 輸出到一個(gè)ostream類
            log4cpp::StringQueueAppender     // 內(nèi)存隊(duì)列
            log4cpp::Win32DebugAppender     // 發(fā)送到缺省系統(tǒng)調(diào)試器
            log4cpp::NTEventLogAppender     // 發(fā)送到win 事件日志

              6.1 OstreamAppender

              在我剛剛學(xué)習(xí)C/C++編程時(shí),一位老師告訴我,如果沒有好用的調(diào)試工具,就在代碼中加入printf語(yǔ)句,將調(diào)試信息打印出來(lái)(當(dāng)時(shí)在linux下面,確實(shí)沒有什么易用的c++調(diào)試工具)。現(xiàn)在有了OstreamAppender,一切都好辦了,它可以將日志記入一個(gè)流,如果該流恰好是cout,則會(huì)在標(biāo)準(zhǔn)控制臺(tái)上輸出。比printf優(yōu)越的是,除了輸出消息外,還可以輕松的輸出時(shí)間、時(shí)鐘數(shù)、優(yōu)先級(jí)等大量有用信息。

              OstreamAppender的使用非常簡(jiǎn)單,在前面的HelloWorld程序中已經(jīng)見過,創(chuàng)建一個(gè)OstreamAppender的具體方法如下:

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

              第一個(gè)參數(shù)指定OstreamAppender的名稱,第二個(gè)參數(shù)指定它關(guān)聯(lián)的流的指針。

              6.2 StringQueueAppender

              后來(lái)一位高手又告訴我“在調(diào)試多線程程序時(shí),不能隨意使用printf”。因?yàn)閜rintf導(dǎo)致IO中斷,會(huì)使得本線程掛起,其花費(fèi)的時(shí)間比一條普通指令多數(shù)千倍,若多個(gè)線程同時(shí)運(yùn)行,則嚴(yán)重干擾了線程間的運(yùn)行方式。所以調(diào)試多線程程序時(shí),最好是將所有調(diào)試信息按順序記入內(nèi)存中,程序結(jié)束時(shí)依次打印出來(lái)。為此當(dāng)時(shí)我們還寫了一個(gè)小工具,沒想到時(shí)隔多年,我碰上了StringQueueAppender。

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

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

               _queue變量是StringQueueAppender類中用于具體存儲(chǔ)日志的內(nèi)存隊(duì)列。StringQueueAppender的使用方法與OstreamAppender類似,其創(chuàng)建函數(shù)只接收一個(gè)參數(shù)“名稱”,記錄完成后需要程序員自己從隊(duì)列中取出每條日志,例子程序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中最常用的兩個(gè)Appender,其功能是將日志寫入文件中。它們之間唯一的區(qū)別就是前者會(huì)一直在文件中記錄日志(直到操作系統(tǒng)承受不了為止),而后者會(huì)在文件長(zhǎng)度到達(dá)指定值時(shí)循環(huán)記錄日志,文件長(zhǎng)度不會(huì)超過指定值(默認(rèn)的指定值是10M byte)。

              FileAppender的創(chuàng)建函數(shù)如下:

            #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);

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

              RollingFileAppender的創(chuàng)建函數(shù)如下:

            #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的創(chuàng)建函數(shù)很類似,但是多了兩個(gè)參數(shù):maxFileSize指出了回滾文件的最大值;maxBackupIndex指出了回滾文件所用的備份文件的最大個(gè)數(shù)。所謂備份文件,是用來(lái)保存回滾文件中因?yàn)榭臻g不足未能記錄的日志,備份文件的大小僅比回滾文件的最大值大1kb。所以如果maxBackupIndex取值為3,則回滾文件(假設(shè)其名稱是rollwxb.log,大小為100kb)會(huì)有三個(gè)備份文件,其名稱分別是rollwxb.log.1,rollwxb.log.2和rollwxb.log.3,大小為101kb。另外要注意:如果maxBackupIndex取值為0或者小于0,則回滾文件功能會(huì)失效,其表現(xiàn)如同F(xiàn)ileAppender一樣,不會(huì)有大小的限制。這也許是一個(gè)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;
            }

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

              6.4 Win32DebugAppender

              Win32DebugAppender是一個(gè)用于調(diào)試的Appender,其功能是向Windows的調(diào)試器中寫入日志,目前支持MSVC和Borland中的調(diào)試器。創(chuàng)建Win32DebugAppender僅需要一個(gè)參數(shù)“名稱”,其使用非常簡(jiǎn)單,下面是例子代碼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中調(diào)試該代碼會(huì)得到如下圖所示的調(diào)試信息,注意最下方的兩行調(diào)試信息:

            Appender 

              6.5 NTEventLogAppender

               該Appender可以將日志發(fā)送到windows的日志,在運(yùn)行程序后可以打開windows的計(jì)算機(jī)管理?系統(tǒng)工具?事件查看器?應(yīng)用程序,可以看到下圖,注意圖中第一行和第二行的兩個(gè)日志。

            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中有一個(gè)總是可用并實(shí)例化好的Category,即根Category。使用log4cpp::Category::getRoot()可以得到根Category。在大多數(shù)情況下,一個(gè)應(yīng)用程序只需要一個(gè)日志種類(Category),但是有時(shí)也會(huì)用到多個(gè)Category,此時(shí)可以使用根Category的getInstance方法來(lái)得到子Category。不同的子Category用于不同的場(chǎng)合。一個(gè)簡(jiǎn)單的例子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;
            }

              運(yùn)行結(jié)果如下:

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

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

               8、NDC

               NDC是nested Diagnostic Context的縮寫,意思是“嵌套的診斷上下文”。NDC是一種用來(lái)區(qū)分不同源代碼中交替出現(xiàn)的日志的手段。當(dāng)一個(gè)服務(wù)端程序同時(shí)記錄好幾個(gè)并行客戶時(shí),輸出的日志會(huì)混雜在一起難以區(qū)分。但如果不同上下文的日志入口擁有一個(gè)特定的標(biāo)識(shí),則可以解決這個(gè)問題。NDC就是在這種情況下發(fā)揮作用。注意NDC是以線程為基礎(chǔ)的,每個(gè)線程擁有一個(gè)NDC,每個(gè)NDC的操作僅對(duì)執(zhí)行該操作的線程有效。

              NDC的幾個(gè)有用的方法是:push、pop、get和clear。注意它們都是靜態(tài)函數(shù):

              Push可以讓當(dāng)前線程進(jìn)入一個(gè)NDC,如果該NDC不存在,則根據(jù)push的參數(shù)創(chuàng)建一個(gè)NDC并進(jìn)入;如果再調(diào)用一次push,則進(jìn)入子NDC;

              Pop可以讓當(dāng)前線程從上一級(jí)NDC中退出,但是一次只能退出一級(jí)。

              Clear可以讓當(dāng)前線程從所有嵌套的NDC中退出。

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

              一個(gè)簡(jiǎn)單的例子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;
            }

              該例子來(lái)自log4cpp的例子程序,我做了簡(jiǎn)單的修改。在記錄日志的時(shí)候,可以從NDC中得知當(dāng)前線程的嵌套關(guān)系。


              9、Log4cpp的自動(dòng)內(nèi)存管理

               9.1 項(xiàng)目的多線程設(shè)置

               VC中必須將項(xiàng)目設(shè)置為Debug MultiThreaded DLL,總之這個(gè)設(shè)置必須與你使用的Log4cpp庫(kù)一致。如果你使用的是Release版本的log4cpp.dll,則應(yīng)該設(shè)置為MultiThreaded DLL。

              否則在程序結(jié)束時(shí)會(huì)報(bào)錯(cuò),報(bào)錯(cuò)處的調(diào)用堆棧為:

            #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的內(nèi)存對(duì)象管理

              也許讀者已經(jīng)注意到,在前面的所有代碼中,log4cpp中所有動(dòng)態(tài)分配的對(duì)象都沒有手動(dòng)釋放。

              Log4cpp中new出來(lái)的Category、Appender和Layout都不需要手動(dòng)釋放,因?yàn)長(zhǎng)og4cpp使用了一個(gè)內(nèi)部類來(lái)管理這些對(duì)象。此類的名稱是HierarchyMaintainer,它負(fù)責(zé)管理Category的繼承關(guān)系,在程序結(jié)束時(shí),HierarchyMaintainer會(huì)依次釋放所有Category,而Category則會(huì)依次釋放擁有的有效Appender,Appender則會(huì)釋放所有附屬的Layout。如果程序員手動(dòng)釋放這些對(duì)象,則會(huì)造成內(nèi)存報(bào)錯(cuò)。

              從下面的代碼可以看出這個(gè)特征:

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

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

              了解到HierarchyMaintainer的內(nèi)存管理方法后,程序員在使用log4cpp時(shí)應(yīng)該遵循以下幾個(gè)使用原則:

              1. 不要手動(dòng)釋放Category、Appender和Layout;

              2. 同一個(gè)Appender不要加入多個(gè)Category,否則它會(huì)被釋放多次從而導(dǎo)致程序崩潰;

              3. 同一個(gè)Layout不要附著到多個(gè)Appender上,否則也會(huì)被釋放多次導(dǎo)致程序崩潰;

              下面這個(gè)簡(jiǎn)單的程序PointerErrorExam會(huì)造成經(jīng)典的崩潰:

            #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;
            }

              運(yùn)行后出現(xiàn)對(duì)話框:

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

              其原因就是osAppender被同時(shí)加入了sub1和sub2這兩個(gè)Category。

              9.3 log4cpp::Category::shutdown()

              在不使用log4cpp時(shí)可調(diào)用log4cpp::Category::shutdown(),其功能如同HierarchyMaintainer的內(nèi)存清理。但如果不手動(dòng)調(diào)用,在程序結(jié)束時(shí)HierarchyMaintainer會(huì)調(diào)用Category的析構(gòu)函數(shù)來(lái)釋放所有Appender。

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

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

            #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

              這是一個(gè)標(biāo)準(zhǔn)的java屬性文件。讀取配置文件要依賴PropertyConfigurator和SimpleConfigurator類。這里僅介紹PropertyConfigurator,其使用方法代碼ConfigFileExam所示(該代碼來(lái)自《便利的開發(fā)工具-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的優(yōu)先級(jí)和相互附屬關(guān)系,然后輸出了一些日志,其運(yùn)行結(jié)果如下:

            #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,反之也是一樣。否則會(huì)在運(yùn)行時(shí)報(bào)錯(cuò)。

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

              12、小結(jié)

              Log4cpp是一個(gè)小巧的c++庫(kù),易于上手,使用方便,不依賴其他庫(kù),具有跨平臺(tái)性,并可與log4j、log4c、log4p等語(yǔ)言族共享其概念與使用方法。實(shí)在是進(jìn)行日志記錄、程序調(diào)試的利器。

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


            只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。
            網(wǎng)站導(dǎo)航: 博客園   IT新聞   BlogJava   博問   Chat2DB   管理


            導(dǎo)航

            統(tǒng)計(jì)

            常用鏈接

            留言簿(3)

            隨筆分類

            隨筆檔案

            搜索

            最新評(píng)論

            閱讀排行榜

            評(píng)論排行榜

            无码8090精品久久一区| 久久精品这里热有精品| 亚洲国产成人久久综合野外| 久久婷婷是五月综合色狠狠| 久久婷婷色综合一区二区| 国产成人无码久久久精品一| 国产精品久久久久一区二区三区| 久久露脸国产精品| 久久亚洲私人国产精品| 青青久久精品国产免费看 | 久久国产亚洲高清观看| 国产精久久一区二区三区| 久久久国产精华液| 国产精品欧美亚洲韩国日本久久| 亚洲AV无码久久精品蜜桃| 日韩中文久久| 国产成人精品久久亚洲| 久久久国产乱子伦精品作者| 亚洲国产精品无码久久久久久曰 | 日日狠狠久久偷偷色综合96蜜桃 | 国产精品久久久天天影视| 精品久久久中文字幕人妻| 国产成人综合久久精品尤物| 亚洲日韩中文无码久久| 综合久久精品色| 色综合久久天天综线观看| 国产精品一区二区久久精品无码| 久久精品国产99久久无毒不卡| 中文精品99久久国产| 性欧美大战久久久久久久 | 国产午夜电影久久| 天天综合久久久网| 免费观看久久精彩视频| 91视频国产91久久久| 久久国产高清字幕中文| 精品久久久久久久久中文字幕| 久久精品a亚洲国产v高清不卡| 精品乱码久久久久久久| 好属妞这里只有精品久久| 精品国产福利久久久| 美女写真久久影院|