log4cpp 學習過程(一) 概述
學習目的:通過學習開源框架,仔細研讀原始碼來提高C++的水平,並在最後通過Windows 和 Linux平臺編譯和test來增加對兩個平臺的熟悉;
從http://log4cpp.sourceforge.net/下載到log4cpp-1.0.tar和log4cpp-docs-1.0.tar,其實就是0.3.5版本;
下文引自:http://www.ibm.com/developerworks/cn/linux/l-log4cpp/index.html
log4cpp是個基於LGPL的開源專案,是基於優秀的日誌處理跟蹤專案Java語言的log4j移植過來的。log4j介紹的文件很多,在java領域使用的也比較廣泛,而這個功能強大的庫對國內的
提供應用程式執行上下文,方便跟蹤除錯;
可擴充套件的、多種方式記錄日誌,包括命令列、檔案、回捲檔案、記憶體、syslog伺服器、Win事件日誌等;
可以動態控制日誌記錄級別,在效率和功能中進行調整;
所有配置可以通過配置檔案進行動態調整;
多語言支援,包括Java(log4j),C++(log4cpp、log4cplus),C(log4c),python(log4p)等;
1. 原理
log4cpp有3個主要的元件:categories(類別)、appenders(附加目的地)、和 layouts(佈局)。(為了方便大家理解,文中儘量使用英文原詞)
layout
log4cpp::BasicLayout // 以“時間戳優先順序(priority,下文介紹) // 類別(category,下文介紹) // NDC標籤(nested diagnostic contexts 下文介紹): 日誌資訊”。 // 如:1056638652 INFO main : This is some info log4cpp::PatternLayout // 讓使用者根據類似於 C 語言 printf 函式的轉換模式來指定輸出格式。格式定義見程式碼附帶文件。 log4cpp::SimpleLayout // |
appender類用來輸出日誌(被layout格式化後的)到一些裝置上。比如檔案、syslog服務、某個socket等。可以定義自己的appender類輸出日誌資訊到別的裝置上,比如應用自身的日子處理程序、資料庫等。appender和layout的關係是layout附在appender上,appender類呼叫layout處理完日誌訊息後,記錄到某個裝置上。log4cpp當前提供以下appender:
log4cpp::IdsaAppender // 傳送到IDS或者logger, 詳細見 http://jade.cs.uct.ac.za/idsa/ log4cpp::FileAppender // 輸出到檔案 log4cpp::RollingFileAppender // 輸出到回捲檔案,即當檔案到達某個大小後回捲 log4cpp::OstreamAppender // 輸出到一個ostream類 log4cpp::RemoteSyslogAppender // 輸出到遠端syslog伺服器 log4cpp::StringQueueAppender // 記憶體佇列 log4cpp::SyslogAppender // 本地syslog log4cpp::Win32DebugAppender // 傳送到預設系統偵錯程式 log4cpp::NTEventLogAppender // 傳送到win 事件日誌 |
category 類真正完成記錄日誌功能,兩個主要組成部分是appenders和priority(優先順序)。優先順序控制哪類日誌資訊可以被這個category記錄,當前優先順序分為:NOTSET, DEBUG, INFO, NOTICE, WARN, ERROR, CRIT, ALERT 或 FATAL/EMERG 。每個日誌資訊有個優先順序,每個category有個優先順序,當訊息的優先順序大於等於category的優先順序時,這個訊息才會被category記錄,否則被忽略。優先順序的關係如下。category類和appender的關係是,多個appender附在category上,這樣一個日誌訊息可以同時輸出到多個裝置上。
NOTSET < DEBUG < INFO < NOTICE < WARN < ERROR < CRIT < ALERT < FATAL = EMERG
category被組織成一個樹,子category建立時優先順序預設NOTSET,category預設會繼承父category的appender。而如果不希望這種appender的繼承關係,log4cpp允許使用additivity 標籤,為false時新的appender取代category的appender列表。
為了更好的理解上面的概念下面以手動使用方式舉例。
|
2. 手動使用步驟
手動使用log4cpp的基本步驟如下:
例項化一個layout 物件;
初始化一個appender 物件;
把layout物件附著在appender物件上;
呼叫log4cpp::Category::getInstance("name"). 例項化一個category物件;
把appender物件附到category上(根據additivity的值取代其他appender或者附加在其他appender後)。
設定category的優先順序;
// FileName: test_log4cpp1.cpp // Test log4cpp by manual operation. // Announce: use as your own risk. // Compile : g++ -otest1 -llog4cpp test_log4cpp1.cpp // Run: ./test1 // Tested: RedHat 7.2 log4cpp0.3.4b // Author: liqun ([email protected]) // Data: 2003-6-27 #include"log4cpp/Category.hh" #include"log4cpp/FileAppender.hh" #include"log4cpp/BasicLayout.hh" int main(int argc, char* argv[]) { // 1例項化一個layout 物件 log4cpp::Layout* layout = new log4cpp::BasicLayout(); // 2. 初始化一個appender 物件 log4cpp::Appender* appender = new log4cpp::FileAppender("FileAppender", "./test_log4cpp1.log"); // 3. 把layout物件附著在appender物件上 appender->setLayout(layout); // 4. 例項化一個category物件 log4cpp::Category& warn_log = log4cpp::Category::getInstance("mywarn"); // 5. 設定additivity為false,替換已有的appender warn_log.setAdditivity(false); // 5. 把appender物件附到category上 warn_log.setAppender(appender); // 6. 設定category的優先順序,低於此優先順序的日誌不被記錄 warn_log.setPriority(log4cpp::Priority::WARN); // 記錄一些日誌 warn_log.info("Program info which cannot be wirten"); warn_log.debug("This debug message will fail to write"); warn_log.alert("Alert info"); // 其他記錄日誌方式 warn_log.log(log4cpp::Priority::WARN, "This will be a logged warning"); log4cpp::Priority::PriorityLevel priority; bool this_is_critical = true; if(this_is_critical) priority = log4cpp::Priority::CRIT; else priority = log4cpp::Priority::DEBUG; warn_log.log(priority,"Importance depends on context"); warn_log.critStream() << "This will show up << as " << 1 << " critical message" << log4cpp::CategoryStream::ENDLINE; // clean up and flush all appenders log4cpp::Category::shutdown(); return 0; } |
|
3. 配置檔案驅動方式使用步驟
另一個非常優秀的特徵就是通過讀取配置檔案,確定category、appender、layout等物件。也是我們非常推薦的使用方式,可以靈活地通過配置檔案定義所有地物件及其屬性,不用重新編碼,動態更改日誌記錄的策略。
Log4cpp主要提供了 log4cpp::PropertyConfigurator 和log4cpp::SimpleConfigurator兩種機制(檔案格式),但 log4cpp::SimpleConfigurator將來不再支援了,而且格式非常簡單,這裡就不多說明,自己看原始碼吧。
配置檔案的格式和log4j的配置檔案一樣,是標準的java屬性檔案格式。下面是附帶的例子配置檔案:
# a simple test config #定義了3個category sub1, sub2, sub1.sub2 log4j.rootCategory=DEBUG, rootAppender log4j.category.sub1=,A1 log4j.category.sub2=INFO log4j.category.sub1.sub2=ERROR, A2 # 設定sub1.sub2 的additivity屬性 log4j.additivity.sub1.sub2=false #定義rootAppender型別和layout屬性 log4j.appender.rootAppender=org.apache.log4j.ConsoleAppender log4j.appender.rootAppender.layout=org.apache.log4j.BasicLayout #定義A1的屬性 log4j.appender.A1=org.apache.log4j.FileAppender log4j.appender.A1.fileName=A1.log log4j.appender.A1.layout=org.apache.log4j.SimpleLayout #定義A2的屬性 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 |
配置檔案語法如下,不是很規範,結合上面的例子,應該可以看懂。
log4j / log4cpp . [category / appender].[category or appender 's name].[category or appender 's property] = [Appender / Layout / property's value / Priority, appender name1 [appender name2 ...]] [appender] {ConsoleAppender} {FileAppender}// 當appender的型別是FileAppender時,可以定義它下面的屬性。 [fileName]stringfoobar// 格式是:屬性名值的型別預設值 [append]booltrue {RollingFileAppender} [fileName] stringfoobar [maxFileSize]num10*1024*1024 [maxBackupIndex]num1 [append]booltrue {SyslogAppender} [syslogName]stringsyslog [syslogHost]stringlocalhost [facility]num-1// * 8 to get LOG_KERN, etc. compatible values. [portNumber]num-1 {IdsaAppender} [idsaName]stringfoobar {Win32DebugAppender} {NTEventLogAppender} [source]stringfoobar [threshold]string ""// 全部 // 如果此型別appender需要layout,必須定義此appender< |