最近因為項目的原因,開始研究log4cplus這個日志庫。主要是把新版中增加的異步模式log用起來。異步log目前很少有人用,網上說明的資料比較少。看了很多源碼,做了很多測試,走了些許彎路。因此打算把一點心得記錄下來,為后面要用此功能的人增加一點參考資料。借此機會,正式開啟我的技術博客之旅:)。
log4cplus通常有三種使用形式:stdout(打印到屏幕),文件日志和網絡日志。最常用的是文件日志。本文主要介紹本地文件日志的用法。
1. 一個簡單的例子
首先來看一個簡單的例子:
int main(int argc, char* argv[]) { log4cplus::initialize(); log4cplus::PropertyConfigurator::doConfigure(LOG4CPLUS_TEXT("log4cplus.properties")); log4cplus::Logger logger = log4cplus::Logger::getInstance("global"); LOG4CPLUS_DEBUG(logger, LOG4CPLUS_TEXT("DEBUG LOG TEST")); LOG4CPLUS_INFO(logger, LOG4CPLUS_TEXT("INFO LOG TEST")); LOG4CPLUS_WARN(logger, LOG4CPLUS_TEXT("WARN LOG TEST")); LOG4CPLUS_ERROR(logger, LOG4CPLUS_TEXT("ERROR LOG TEST")); log4cplus::Logger::shutdown(); return 0; }
這個程序啟動以后,首先執行initialize函數,做一些初始化工作:初始化線程本地變量及其清理函數,注冊各種類型的Appender(最終打日志的類)。然后通過 doConfigure 去讀取該程序所在目錄下的日志的配置文件log4cplus.properties。
getInstance函數會通過global這個名字,從log4cplus.properties讀取起對應的log選項中,返回一個log4cplus::Logger實例。該實例底層是一個共享指針,指向一個真正的log實例。此時,所有的log相關的初始化工作完成了,可以開始打log了。
程序使用了log4cplus提供的宏來打log。打完log,需要調用shutdown函數關閉log實例,以確保log被flush到磁盤上。
2. log的不同方式及其特點
log4cplus是通過不同的Appender來決定怎樣打log的:
ConsoleAppender:stdout日志
FileAppender:普通文件日志
RollingFileAppender:滾動的文件日志
DailyRollingFileAppender:按天滾動的文件日志
AsyncAppender:異步日志
Log4jUdpAppender:網絡日志
除了ConsoleAppender、AsyncAppender和Log4jUdpAppender,剩下的都是文件日志。這些Appender打的日志都是同步的,即打log的語句會等到log打完(log被發送到文件系統的緩沖區)才返回。如果某個時刻,系統突然打了非常大量的log,以至於
超過了系統磁盤的最大讀寫速度,這個時刻以后的打log的線程都會被阻塞。這會極大地減緩系統響應速度。
為了緩解這樣的問題,通常有三種做法:減少線上系統的log量(甚至線上系統關閉log),打網絡日志,使用log4cplus提供的異步日志。但是,對與有些比較重要的需要對賬的線上系統,通常需要打很詳細的log。為了不讓log影響系統的響應速度,通常會打
網絡log。而網絡log需要額外的服務器來接收log,同時會占用一定的帶寬。因此如果log不是特別重要的系統,通常可以使用異步log來緩解這個問題。
log4cplus的AsyncAppender是log4cplus-1.2.0版本庫開始支持的一個新功能。AsyncAppender可以讓你的系統以異步的方式來打log,從而提高系統的響應速度。在系統啟動后,所有的系統log首先會發送到AsyncAppender的一個隊列中去,
AsyncAppender會在系統啟動時專門開一個線程來寫程序發過來的log。通過這種方式將log的生產和落地放到不同的線程來完成。
但是,AsyncAppender並不是萬靈葯。如果系統生產日志的速度超過了寫日志線程的消費日志的速度,AsyncApender的隊列會被填滿。如果隊列滿了,生產日志的線程的打log時候會被阻塞住,直到隊列有空間放新的日志。因此,要想萬無一失,最后還是打
網絡log。
2.1 log4cplus的同步日志的配置
## synchronous log properties. log4cplus.logger.global = INFO, SA log4cplus.appender.SA=log4cplus::DailyRollingFileAppender log4cplus.appender.SA.Schedule=HOURLY log4cplus.appender.SA.DatePattern=%Y-%m-%d:%H log4cplus.appender.SA.File=/home/work/log/imserv/imserv.log log4cplus.appender.SA.MaxBackupIndex=100 log4cplus.appender.SA.BufferSize=131072 log4cplus.appender.SA.Append=true log4cplus.appender.SA.layout=log4cplus::PatternLayout log4cplus.appender.SA.layout.ConversionPattern=%D{%Y-%m-%d %H:%M:%S,%Q} [%t] %-5p %m%n
2.2 log4cplus的異步log的配置
## asynchronous log properties. log4cplus.logger.global = INFO, AA log4cplus.appender.AA=log4cplus::AsyncAppender log4cplus.appender.AA.QueueLimit=10000 log4cplus.appender.AA.Appender=log4cplus::DailyRollingFileAppender log4cplus.appender.AA.Appender.Schedule=HOURLY log4cplus.appender.AA.Appender.Threshold = INFO log4cplus.appender.AA.Appender.DatePattern=%Y-%m-%d-%H log4cplus.appender.AA.Appender.File=./logger_test.log log4cplus.appender.AA.Appender.ImmediateFlush=false log4cplus.appender.AA.Appender.MaxFileSize=1000MB log4cplus.appender.AA.Appender.MaxBackupIndex=100 log4cplus.appender.AA.Appender.Append=true log4cplus.appender.AA.Appender.layout=log4cplus::PatternLayout log4cplus.appender.AA.Appender.layout.ConversionPattern=%D{%Y-%m-%d %H:%M:%S,%Q} [%t] %-5p %m%n
2.3 log4cplus異步日志使用過程中需要注意的地方
程序退出前記得調用shutdown函數將所有的log flush到磁盤上。
1.2.0版本的log4cplus異步日志有BUG,會導致丟日志,下一個版本會修復。解決辦法見:https://sourceforge.net/p/log4cplus/bugs/333/