C++:日誌庫log4cplus 2.0的使用說明
以前在做java開發時一直都在用log4j,它配置靈活,功能強大。如果C++中也存在類似配置的日誌庫,則可以省去不少學習的時間。在C++中的確有這樣的一些庫,本文就拿其中用的最多的log4cplus來講講如何使用它。
可以從以上兩個地址中下載最新的檔案,本文使用的最新版本是log4cplus-2.0.2。下載完成並解壓後,可以在log4cplus-2.0.2目錄下找到msvc14目錄,進入後找到log4cplus.sln檔案。先在確認已Visual Studio 2015以上版本,然後雙擊開啟此檔案,就會看到如下內容:
其中,log4cplus可以生成動態庫,log4cplusS可以生成靜態庫。本文要在64位系統中生成測試用的靜態庫,所以配置成Debug x64,字符集設定成Unicode。然後編譯log4cplusS,會在msvc14\x64\bin.Debug下生成log4cplusSD.lib檔案。
下面是測試程式碼:
#include <vector> #include <thread> #include <chrono> #include <string> #include <memory> #include <ctime> #include <iomanip> #include <log4cplus/logger.h> #include <log4cplus/loggingmacros.h> #include <log4cplus/configurator.h> #include <log4cplus/initializer.h> #include <log4cplus/loglevel.h> #include <log4cplus/ndc.h> using namespace std; using std::chrono::system_clock; using namespace log4cplus; using namespace log4cplus::helpers; string getTime() { system_clock::time_point tp = system_clock::now(); time_t raw_time = system_clock::to_time_t(tp); struct tm *timeinfo = std::localtime(&raw_time); std::stringstream ss; ss << std::put_time(timeinfo, "%Y-%m-%d %H:%M:%S"); return ss.str(); } void doTestRun(int i) { static log4cplus::Logger logger = log4cplus::Logger::getInstance(LOG4CPLUS_TEXT("main")); string threadName = "doRun-" + to_string(i); // 使用NDC給執行緒設定名稱 log4cplus::NDCContextCreator _ndc(LOG4CPLUS_STRING_TO_TSTRING(threadName)); while (true) { this_thread::sleep_for(3s); // 如果不加u8,日誌檔案會是GB2312格式 string info = u8"你好:" + getTime(); LOG4CPLUS_WARN(logger, LOG4CPLUS_STRING_TO_TSTRING(info)); } } int main() { log4cplus::Initializer initializer; PropertyConfigurator pc(LOG4CPLUS_TEXT("log4cplus.properties")); pc.configure(); vector<std::thread> threadVector; for (int i = 0; i < 5; i++) { threadVector.emplace_back(doTestRun, i); } for (vector<std::thread>::iterator itr = threadVector.begin(); itr != threadVector.end(); itr++) { itr->join(); } return 0; }
配置檔案log4cplus.properties中的內容:
log4cplus.rootLogger=DEBUG, STDOUT
log4cplus.appender.STDOUT=log4cplus::ConsoleAppender
log4cplus.appender.STDOUT.layout=log4cplus::TTCCLayout# 對ALL_MSGS使用非同步Appender
log4cplus.appender.ALL_MSGS=log4cplus::AsyncAppender
# 非同步Appender的佇列大小
log4cplus.appender.ALL_MSGS.QueueLimit=10000
# 非同步Appender中具體使用RollingFileAppender作為寫檔案的FileAppender
log4cplus.appender.ALL_MSGS.Appender=log4cplus::DailyRollingFileAppender
# 應用重新啟動後是要清空日誌檔案再寫入,還是要接在日誌檔案後面接著寫入
log4cplus.appender.ALL_MSGS.Appender.Append=false
# 設定FileAppender的快取大小
log4cplus.appender.ALL_MSGS.Appender.BufferSize=10000
# 達到快取上限後是否立即寫入
log4cplus.appender.ALL_MSGS.Appender.ImmediateFlush=true
# 寫的檔案路徑和檔名
log4cplus.appender.ALL_MSGS.Appender.File=d:/Temp/test.log
# 設定每個日誌檔案的最大容量
log4cplus.appender.ALL_MSGS.Appender.MaxFileSize=250KB
# 日誌檔案達到最大容量後,重新命名檔案以備份,設定最大備份日誌檔案數
log4cplus.appender.ALL_MSGS.Appender.MaxBackupIndex=10
# 指定日誌檔案回滾週期
log4cplus.appender.ALL_MSGS.Appender.Schedule=MINUTELY
# 當日志文件達到回滾週期時,則重新生成新的日誌檔案,舊的日誌檔案會加上.%Y%m%d_%H%M字尾
log4cplus.appender.ALL_MSGS.Appender.DatePattern=%Y%m%d_%H%M
# 設定輸出使用的locale
# log4cplus.appender.ALL_MSGS.Appender.Locale=en_US.UTF-8
# 自定義FileAppender的輸出格式
log4cplus.appender.ALL_MSGS.Appender.layout=log4cplus::PatternLayout
# 自定義FileAppender的輸出格式的樣式
log4cplus.appender.ALL_MSGS.Appender.layout.ConversionPattern=%D{%Y-%m-%d %H:%M:%S.%q}%5p[%5t|%x][%l][%c]- %m%n
# category為main的日誌
log4cplus.logger.main=DEBUG, ALL_MSGS
log4cplus.additivity.main=false
程式碼執行結果儲存為UTF-8格式:
2018-10-18 18:41:00.898 WARN[29816|doRun-3][d:\vc_projects\log4cplus.cpp:45][main]- 你好:2018-10-18 18:41:00
2018-10-18 18:41:00.902 WARN[18180|doRun-4][d:\vc_projects\log4cplus.cpp:45][main]- 你好:2018-10-18 18:41:00
2018-10-18 18:41:00.902 WARN[17704|doRun-0][d:\vc_projects\log4cplus.cpp:45][main]- 你好:2018-10-18 18:41:00
2018-10-18 18:41:00.904 WARN[28388|doRun-2][d:\vc_projects\log4cplus.cpp:45][main]- 你好:2018-10-18 18:41:00
2018-10-18 18:41:00.905 WARN[ 5164|doRun-1][d:\vc_projects\log4cplus.cpp:45][main]- 你好:2018-10-18 18:41:00
在程式碼中通過NDC給每個新建立的執行緒設定了執行緒名,這樣通過%x和%t可以在日誌中同時打印出執行緒名和執行緒編號。
log4cplus是通過如下的巨集生成日誌的:
LOG4CPLUS_TRACE (logger, "printMessages()");
LOG4CPLUS_DEBUG (logger, "This is a DEBUG message");
LOG4CPLUS_INFO (logger, "This is a INFO message");
LOG4CPLUS_WARN (logger, "This is a WARN message");
LOG4CPLUS_ERROR (logger, "This is a ERROR message");
LOG4CPLUS_FATAL (logger, "This is a FATAL message");
另外,需要注意才下幾點:
1.列印字串常量要使用LOG4CPLUS_TEXT,列印string要使用LOG4CPLUS_STRING_TO_TSTRING。
2.編譯程式碼時要使用Unicode字符集。
3.使用thread建立的執行緒只有執行緒編號,沒有執行緒名,可以使用NDC給執行緒設定一個名字,這樣檢視日誌時方便。