1. <nobr id="easjo"><address id="easjo"></address></nobr>

      <track id="easjo"><source id="easjo"></source></track>
      1. 
        

      2. <bdo id="easjo"><optgroup id="easjo"></optgroup></bdo>
      3. <track id="easjo"><source id="easjo"><em id="easjo"></em></source></track><option id="easjo"><span id="easjo"><em id="easjo"></em></span></option>
          貴州做網站公司
          貴州做網站公司~專業!靠譜!
          10年網站模板開發經驗,熟悉國內外開源網站程序,包括DEDECMS,WordPress,ZBlog,Discuz! 等網站程序,可為您提供網站建設,網站克隆,仿站,網頁設計,網站制作,網站推廣優化等服務。我們專注高端營銷型網站,企業官網,集團官網,自適應網站,手機網站,網絡營銷,網站優化,網站服務器環境搭建以及托管運維等。為客戶提供一站式網站解決方案?。?!

          Log4cpp介紹及使用

          來源:互聯網轉載 時間:2024-01-29 07:57:01

          大家好,又見面了,我是全棧君,祝每個程序員都可以多學幾門語言。

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

          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(文檔壓縮包)。

            2.2在VC6中編譯Log4cpp

            進入D:log4cpp-0.3.5rc3msvc6文件夾,打開VC6的工作區msvc6.dsw,將當中的project都刪除,僅僅保留log4cpp和log4cppDLL兩個project。分別編譯它們的Debug和Release版本號。

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

          static const int MESSAGE_SIZE = 8;

          改為:

          staticconst intMESSAGE_SIZE;

          并在Priority.cpp中的全部include語句后加上:

          constint log4cpp::Priority::MESSAGE_SIZE =8;

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

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

            將D:log4cpp-0.3.5rc3lib添?系統的Path路徑中。

            2.3樣例程序

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

          3、Log4cpp演示樣例

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

          #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 =newlog4cpp::OstreamAppender(“osAppender”,&cout);

          osAppender->setLayout(newlog4cpp::BasicLayout());

          log4cpp::Category& root =log4cpp::Category::getRoot();

          root.addAppender(osAppender);

          root.setPriority(log4cpp::Priority::DEBUG);

          root.error(“Hello log4cpp in aError Message!”);

          root.warn(“Hello log4cpp in aWarning Message!”);

          log4cpp::Category::shutdown();

          return 0;

          }

            要順利編譯執行還有兩個地方須要設置,其一是引入的庫中加上log4cppD.lib(debug版dll庫的引入文件);其二是將C/C++的CodeGeneration中的Use Runtimelibrary設置為“DebugMultithreaded DLL”。

            設置完畢后編譯執行結果例如以下:

          1248337987ERROR : Hello log4cppin a Error Message! 1248337987 WARN : Hello log4cppin a Warning Message!

            以上兩條日志格式非常簡陋,要設置合乎心意的日志格式,請參考興許的PatternLayout章節。

          4、Log4cpp概念

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

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

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

          typedefenum {

          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的順序來依次介紹這些概念并給出樣例。

          4.1Layout(布局)

          layout類控制輸出日志消息的顯示樣式(看起來像什么)。log4cpp當前提供下面layout格式:

               log4cpp::BasicLayout         // 以“時間戳 優先級(priority,下文介紹)
                                            // 類別(category,下文介紹)

          //NDC標簽(nested diagnostic contexts 下文介紹): 日志信息”。

          //如:1056638652 INFO main : This is someinfo

          log4cpp::PatternLayout // 讓用戶依據類似于C 語言 printf 函數的轉換模式

          //來指定輸出格式。格式定義見代碼附帶文檔。

          log4cpp::SimpleLayout // 以“優先級(priority) – 日志信息”格式顯示。

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

          1248337987 ERROR : Hello log4cppin a Error Message!

          1248337987 WARN : Hello log4cppin a Warning Message!

            上面的日志格式還能夠,但顯然不是很多程序猿心中理想的格式,很多人理想的格式應該是這種:

          2009-07-24 15:59:55,703:INFO infoCategory : system isrunning

          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 beshutdown

          2009-07-24 15:59:55,718:INFO infoCategory : system shutdown, you can find some informationin system log

            要獲得上面的格式,必須使用比BasicLayout復雜的PatternLayout,并且要花一個小時來熟悉一下PatternLayout的格式定義方式,假設你覺得值得的話。

            4.1.1PatternLayout

            在介紹PatternLayout曾經,首先來看看log4cpp中全部的Layout子類(Layout本身是個虛類),一共三個:BasicLayout、PatternLayout和SimpleLayout,當中SimapleLayout并不建議使用,而BaiscLayout過于簡單,因此假設程序猿不自己擴展Layout的話,就僅僅能使用PatternLayout了,值得慶幸的是,PatternLayout還是比較好用的。

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

          void log4cpp::PatternLayout::setConversionPattern (conststd::string& conversionPattern) throw(ConfigureFailure) [virtual]

            當中參數類型為std::string,類似于C語言中的printf,使用格式化字符串來描寫敘述輸出格式,其詳細含義例如以下:

          u %c category;

          u %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,表示毫秒,占三個十進制位。

          u %m 消息;

          u %n 換行符,會依據平臺的不同而不同,但對于用戶透明;

          u %p 優先級;

          u %r 自從layout被創建后的毫秒數;

          u %R 從1970年1月1日0時開始到眼下為止的秒數;

          u %u 進程開始到眼下為止的時鐘周期數;

          u %x NDC。

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

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

          infoCategory.warn(“system has awarning”);

          infoCategory.error(“system hasa error, can’t find a file”);

          infoCategory.fatal(“system hasa fatal error,must be shutdown”);

          infoCategory.info(“systemshutdown,you can find some information in systemlog”);

          log4cpp::Category::shutdown();

          return 0;

          }

          其執行結果即例如以下所看到的:

          2009-07-2415:59:55,703: INFO infoCategory : system is running

          2009-07-2415:59:55,703: WARN infoCategory : system has a warning

          2009-07-2415:59:55,703: ERROR infoCategory : system has a error, can’t find afile

          2009-07-2415:59:55,718: FATAL infoCategory : system has a fatal error, mustbe shutdown

          2009-07-2415:59:55,718: INFO infoCategory : system shutdown, you can findsome information in system log

          4.2 Appender

            筆者覺得Appender是log4cpp中最精彩的一個部分。我細致閱讀了大部分Appender的源碼并對設計者感到很仰慕。

            Log4cpp中全部可直接使用的Appender列表例如以下:

          ? log4cpp::IdsaAppender // 發送到IDS或者

          ? log4cpp::FileAppender // 輸出到文件

          ? log4cpp::RollingFileAppender // 輸出到回卷文件,即當文件到達某個大小后回卷

          ? log4cpp::OstreamAppender // 輸出到一個ostream類

          ? log4cpp::RemoteSyslogAppender // 輸出到遠程syslogserver

          ? log4cpp::StringQueueAppender // 內存隊列

          ? log4cpp::SyslogAppender // 本地syslog

          ? log4cpp::Win32DebugAppender // 發送到缺省系統調試器

          ? log4cpp::NTEventLogAppender // 發送到win事件日志

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

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

          log4cpp::FileAppender // 輸出到文件

          log4cpp::RollingFileAppender // 輸出到回卷文件,即當文件到達某個大小后回卷

          log4cpp::OstreamAppender // 輸出到一個ostream類

          log4cpp::StringQueueAppender // 內存隊列

          log4cpp::Win32DebugAppender // 發送到缺省系統調試器

          log4cpp::NTEventLogAppender //發送到win事件日志

            4.2.1OstreamAppender

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

            OstreamAppender的使用很easy,在前面的HelloWorld程序中已經見過,創建一個OstreamAppender的詳細方法例如以下:

          log4cpp::OstreamAppender* osAppender = newlog4cpp::OstreamAppender(“osAppender”, &cout);

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

            4.2.2StringQueueAppender

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

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

          std::queue<std::string> _queue;

           _queue變量是StringQueueAppender類中用于詳細存儲日志的內存隊列。StringQueueAppender的用法與OstreamAppender類似,其創建函數僅僅接收一個參數“名稱”,記錄完畢后須要程序猿自己從隊列中取出每條日志,樣例程序StringQueueAppenderExam例如以下:

          #include<iostream>

          #include<log4cpp/Category.hh>

          #include<log4cpp/OstreamAppender.hh>

          #include<log4cpp/BasicLayout.hh>

          #include<log4cpp/Priority.hh>

          #include<log4cpp/StringQueueAppender.hh>

          using namespacestd;

          int main(int argc,char* argv[])

          {

          log4cpp::StringQueueAppender* strQAppender = newlog4cpp::StringQueueAppender(“strQAppender”);

          strQAppender->setLayout(newlog4cpp::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 WarningMessage!”);

          cout<<“Get message from MemoryQueue!”<<endl;

          cout<<“——————————————-“<<endl;

          queue<string>& myStrQ =strQAppender->getQueue();

          while(!myStrQ.empty())

          {

          cout<<myStrQ.front();

          myStrQ.pop();

          }

          log4cpp::Category::shutdown();

          return 0;

          }

            程序輸出為:

          Getmessage from Memory Queue!

          ——————————————-

          1248839389 ERROR : Hellolog4cpp in a Error Message!

          1248839389 WARN : Hellolog4cpp in a Warning Message!

            4.2.3FileAppender和RollingFileAppender

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

            FileAppender的創建函數例如以下:

          FileAppender(conststd::string& name, conststd::string& fileName, bool append = true, mode_tmode = 00644);

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

            RollingFileAppender的創建函數例如以下:

          RollingFileAppender(const std::string&name, const std::string&fileName,

          size_tmaxFileSize =10*1024*1024, unsigned intmaxBackupIndex = 1,

          boolappend = 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例如以下:

          #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 = newlog4cpp::PatternLayout();

          pLayout1->setConversionPattern(“%d: %p %c%x: %m%n”);

          log4cpp::PatternLayout* pLayout2 = newlog4cpp::PatternLayout();

          pLayout2->setConversionPattern(“%d: %p %c%x: %m%n”);

          log4cpp::Appender* fileAppender = newlog4cpp::FileAppender(“fileAppender”,”wxb.log”);

          fileAppender->setLayout(pLayout1);

          log4cpp::RollingFileAppender* rollfileAppender = newlog4cpp::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<<“:RootError 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條日志。

            4.2.4Win32DebugAppender

            Win32DebugAppender是一個用于調試的Appender,其功能是向Windows的調試器中寫入日志,眼下支持MSVC和Borland中的調試器。創建Win32DebugAppender僅須要一個參數“名稱”,其使用很easy,以下是樣例代碼DebugAppenderExam:

          #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 = newlog4cpp::PatternLayout();

          pLayout1->setConversionPattern(“%d: %p %c%x: %m%n”);

          log4cpp::Appender* debugAppender = newlog4cpp::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中調試該代碼會得到例如以下圖所看到的的調試信息,注意最下方的兩行調試信息:

            4.2.5NTEventLogAppender

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

            樣例程序NTAppenderExam例如以下:

          #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 = newlog4cpp::PatternLayout();

          pLayout1->setConversionPattern(“%d: %p %c%x: %m%n”);

          log4cpp::Appender* ntAppender = newlog4cpp::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;

          }

          4.3 Category

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

          #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(newlog4cpp::BasicLayout());

          log4cpp::OstreamAppender*osAppender2 = new log4cpp::OstreamAppender(“osAppender2”,&cout);

          osAppender2->setLayout(newlog4cpp::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(“suberror”);

          log4cpp::Category& sub2 =root.getInstance(“sub2”);

          sub2.addAppender(osAppender2);

          sub2.setPriority(101);

          sub2.warn(“sub2warning”);

          sub2.fatal(“sub2fatal”);

          sub2.alert(“sub2alert”);

          sub2.crit(“sub2crit”);

          log4cpp::Category::shutdown();

          return 0;

          }

          執行結果例如以下:

          1248869982 ERRORsub1 : sub error

          1248869982 FATALsub2 : sub2 fatal

          1248869982 ALERTsub2 : sub2 alert

           這個樣例中共同擁有三個Category,各自是根、sub1和sub2,當中sub1記錄了一條日志,sub2記錄了兩條日志。Sub2另外兩個日志因為優先級不夠未能記錄。

          4.4 NDC

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

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

            Push能夠讓當前線程進入一個NDC,假設該NDC不存在,則依據push的參數創建一個NDC并進入;假設再調用一次push,則進入子NDC;

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

            Clear能夠讓當前線程從全部嵌套的NDC中退出。

            Get能夠得到當前NDC的名字,假設有嵌套,則不同級別之間的名字用空格隔開。

            一個簡單的樣例NDCExam例如以下:

          #include<iostream>

          #include<log4cpp/NDC.hh>

          using namespacelog4cpp;

          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中得知當前線程的嵌套關系。

          5、Log4cpp的自己主動內存管理

            8.1 項目的多線程設置

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

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

          log4cpp::BasicLayout::`vector deleting destructor'(unsignedint 1) + 122 bytes

          log4cpp::LayoutAppender::~LayoutAppender() line 21 + 35bytes

          log4cpp::OstreamAppender::~OstreamAppender() line 28 + 15bytes

          log4cpp::OstreamAppender::`vector deletingdestructor'(unsigned int 1) + 103 bytes

          log4cpp::Category::removeAllAppenders() line 159 + 39bytes

          log4cpp::HierarchyMaintainer::shutdown() line 101 + 27bytes

          log4cpp::HierarchyMaintainer::~HierarchyMaintainer() line36

            8.2Log4cpp的內存對象管理

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

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

            從以下的代碼能夠看出這個特征:

          appender->setLayout(newlog4cpp::BasicLayout());

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

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

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

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

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

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

          #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 = newlog4cpp::OstreamAppender(“osAppender”, &cout);

          osAppender->setLayout(newlog4cpp::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;

          }

           執行后出現對話框:

          PointerErrorExam.exe 遇到問題須要關閉。我們對此引起的不便表示抱歉。

            其原因就是osAppender被同一時候添?了sub1和sub2這兩個Category。

            8.3log4cpp::Category::shutdown()

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

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

          如同log4j一樣,log4cpp也能夠讀取配置文件來定制Category、Appender和Layout對象。其配置文件格式基本類似于log4j,一個簡單的配置文件log4cpp.ini樣例例如以下:

          #log4cpp配置文件

          #定義Root category的屬性

          log4cpp.rootCategory=DEBUG, RootLog

          #定義RootLog屬性

          log4cpp.appender.RootLog=ConsoleAppender

          log4cpp.appender.RootLog.layout=PatternLayout

          log4cpp.appender.RootLog.layout.ConversionPattern=%d [%p] -%m%n

          #定義sample category的屬性

          log4cpp.category.sample=DEBUG, sample

          #定義sample屬性

          log4cpp.appender.sample=FileAppender

          log4cpp.appender.sample.fileName=sample.log

          log4cpp.appender.sample.layout=PatternLayout

          log4cpp.appender.sample.layout.ConversionPattern=%d [%p] -%m%n

          #定義sample.soncategory的屬性

          log4cpp.category.sample.son=DEBUG, son

          #定義son的屬性

          log4cpp.appender.son=FileAppender

          log4cpp.appender.son.fileName=son.log

          log4cpp.appender.son.layout=PatternLayout

          log4cpp.appender.son.layout.ConversionPattern=%d[%p] – %m%n

          #定義sample.daughtercategory的屬性

          log4cpp.category.sample.daughter=DEBUG,daughter

          #定義daughter屬性

          log4cpp.appender.daughter=FileAppender

          log4cpp.appender.daughter.fileName=daughter.log

          log4cpp.appender.daughter.layout=PatternLayout

          log4cpp.appender.daughter.layout.ConversionPattern=%d [%p]- %m%n

          相應category 和 appender 的配置方式,能夠發現

          category 是”log4cpp.category.” + “categoryname”

          category 名字能夠用”.”分隔,以標識包括關系

          appender 是”log4cpp.appender.” + “appendername”

          appender 名字 不能用 “.” 分隔,即是說 appender 是沒有包括關系的

          讀取配置文件要依賴PropertyConfigurator和SimpleConfigurator類。這里僅介紹PropertyConfigurator,其用法代碼ConfigFileExam所看到的(該代碼來自《便利的開發工具-log4cpp高速使用指南》一文):

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

          sub1.alert(“Awarning”);

          // sub3 only have A2 appender.

          sub3.debug(“This debug messagewill fail to write”);

          sub3.alert(“All hands abandonship”);

          sub3.critStream() <<“This will show up<< as “<< 1 <<” critical message”<<log4cpp::CategoryStream::ENDLINE;

          sub3<<log4cpp::Priority::ERROR<<“And this will be anerror” <<log4cpp::CategoryStream::ENDLINE;

          sub3.log(log4cpp::Priority::WARN, “This will be a logged warning”);

          return0;

          }

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

          1248875649 INFO sub1 : This is some info

          1248875649 ALERT sub1 : A warning

          The message All hands abandon ship at time 2009-07-2921:54:09,515

          1248875649 ALERT sub1.sub2 : All hands abandonship

          The message This will show up<< as 1 critical message at time2009-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-2921:54:09,531

          1248875649 ERROR sub1.sub2 : And this will be anerror

          7、DLL的版本號問題

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

          問題:因為log4cpp-0.3.5rc3僅提供了vc6的project文件,因此,使用vs2005打開后,須要進行轉換??墒寝D換后,不能正確編譯,提示Custom Build Step時出現了錯誤。

          分 析:由于log4cpp在生成NTEventLogAppender.dll時,須要連接NTEventLogCategories.mc文件。所以,項目設置了自己定義的生成步驟去生成NTEventLogAppender.dll。但從vc6的project文件轉換時,這些步驟卻沒有正確的轉換過來。從而出現上述問題。

          解決方法:又一次填寫Custom BuildStep項。當中,CommandLine填寫下面內容:

          if not exist $(OutDir) md$(OutDir)

          “mc.exe” -h $(OutDir) -r $(OutDir)$(ProjectDir)..$(InputName).mc

          “RC.exe” -r -fo$(OutDir)$(InputName).res $(OutDir)$(InputName).rc

          “link.exe” /MACHINE:IX86 -dll-noentry -out:$(OutDir)NTEventLogAppender.dll$(OutDir)$(InputName).res

          適用范圍:log4cpp項目、log4cppDLL項目的Debug和Release配置。同一時候,該方法適用于vs2003(vc7.1)。

          問題:log4cppDLL項目編譯時會報8個連接錯誤,提示符號std::_Tree找不到

          解決方式:

          將includelog4cppFactoryParams.hh文件里的

          const_iterator find(conststd::string& t) const;

          改動為:

          const_iterator find(conststd::string& t) const { return storage_.find(t);}

          后又一次編譯問題:

          log4cppDLL項目編譯時會報1個連接錯誤,提示符號log4cpp::localtime找不到

          解決方式:

          將srclocaltime.cpp文件加入?到項目中又一次編譯

          8、小結

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

          118777.html

          標簽:log4cpp-

          網絡推廣與網站優化公司(網絡優化與推廣專家)作為數字營銷領域的核心服務提供方,其價值在于通過技術手段與策略規劃幫助企業提升線上曝光度、用戶轉化率及品牌影響力。這...

          在當今數字化時代,公司網站已成為企業展示形象、傳遞信息和開展業務的重要平臺。然而,對于許多公司來說,網站建設的價格是一個關鍵考量因素。本文將圍繞“公司網站建設價...

          在當今的數字化時代,企業網站已成為企業展示形象、吸引客戶和開展業務的重要平臺。然而,對于許多中小企業來說,高昂的網站建設費用可能會成為其發展的瓶頸。幸運的是,隨...

          北京到廈門高鐵途徑什么站?京廈高鐵G355從北京南站始發,途經滄州西站、德州東站、濟南西站、曲阜東站、徐州東站、蚌埠南站、淮南東站、合肥南站、巢湖東站、武威站、南嶺站、績溪北站、黃山北站、婺源站、上饒站、五福山站、武夷山站、古田站、福州站、福清站、莆田站北京至廈門高鐵票價多少?北京至廈門票價:元,882元至2942元不等。北京至廈門鐵路距離2025公里,北京南至廈門北有G321、G323、G325...

          蚌埠電大的文憑有用嗎?有用。安徽廣播電視大學蚌埠分校于1979年1月1日在蚌埠成立。學校地址位于皖北中心城市張公山路126號(郵政編碼:233000)(行政區代碼:3403)。我校建校43年,培養了大批優秀人才。我們學校以教書育人為主,學校符合體制,人文。蚌埠電大的文憑有用嗎?答:蚌埠電大的有用,基層公務員有電大就可以考。...

          保定地區郵編?保定郵政編碼:071000保定市新市區郵政編碼:071000保定市北市區郵政編碼:071000保定市南市區郵政編碼:071000保定市滿城縣郵政編碼:072150保定市清苑縣郵政編碼:071100保定市淶水縣郵政編碼:074100保定市阜平縣郵政編碼:073200保定市徐水縣郵政編碼:072550保定市定興縣郵政編碼:072650保定唐縣郵政編碼:072350保定市高陽縣郵政編碼:0...

          TOP
          国产初高中生视频在线观看|亚洲一区中文|久久亚洲欧美国产精品|黄色网站入口免费进人
          1. <nobr id="easjo"><address id="easjo"></address></nobr>

              <track id="easjo"><source id="easjo"></source></track>
              1. 
                

              2. <bdo id="easjo"><optgroup id="easjo"></optgroup></bdo>
              3. <track id="easjo"><source id="easjo"><em id="easjo"></em></source></track><option id="easjo"><span id="easjo"><em id="easjo"></em></span></option>