1. 程式人生 > >c++日誌工具之——log4cplus

c++日誌工具之——log4cplus

http://blog.csdn.net/hmalloc/article/details/8443291

1 日誌簡介

程式都不可避免地會出現錯誤輸出或崩潰的情況,這種情況往往在開發階段很難發現,需要在特定的環境下才會出現,一旦出現這種情況,我們需要快速地定位到問題。很顯然,當程式出現這種問題時,如果程式自己能夠將當時出現該問題的原因記錄下來,則能給我們帶來莫大的效率,正是因為有了這種需求,所以就有了日誌系統。所謂日誌,就是程式執行時自動記錄每日執行狀態的一種行為,這跟我們傳統說的打debug的方法有點區別,我們在剛開始學習C/C++語言的時候,接觸到的只是類似於printf/cout的一些標準輸入輸出的東西,我們通常利用這些函式來輔助除錯程式,當時也完全沒有日誌的概念。實際上到了真正做專案你會發現,這種傳統的打debug的方式有明顯的不足,不但輸出的資訊不美觀,也不能做到實時記錄,更不方便根據需求隨意控制輸出,這一切在日誌系統中得到解決。

2 log4cplus簡介

log4cplus移植於Java中的日誌系統log4j,使用上也和log4j大同小異,這是一個很優秀的日誌系統。log4j由三個元件構成——佈局元件(Layouts)、追加元件(Appends)及真正實現日誌功能的日誌元件(Loggers)。佈局元件用來控制日誌輸出的格式。追加元件定義日誌輸出的裝置,如控制檯、檔案、socket、共享記憶體等,都可以成為追加元件,我們通常使用控制檯和檔案作為日誌輸出裝置,在除錯時我們將日誌定位到控制檯,而實際釋出執行時將其定位到檔案。日誌元件提供對日誌級別的控制,級別從高到低依次為FATAL_LOG_LEVEL、 ERROR_LOG_LEVEL、 WARN_LOG_LEVEL、 INFO_LOG_LEVEL 、DEBUG_LOG_LEVEL、 TRACE_LOG_LEVEL、 NOT_SET_LOG_LEVEL。

3 log4cplus的安裝

log4cplus是開源的,原始碼可在這裡找到。下載原始碼壓縮包後解壓,進入主目錄。和大多數autotools工程一樣,順序執行以下命令即可完成安裝。

./configure  
make  
make install  

安裝檔案將預設安裝到/usr/local,庫檔案置於/usr/local/lib,標頭檔案置於/usr/local/include。

是的,這裡介紹的安裝及下面介紹的應用都是基於linux系統。

4 log4cplus的使用

以下是官方提供的“hello, world”的示例程式:

#include <log4cplus/logger.h>  
#include <log4cplus/loggingmacros.h>  
#include <log4cplus/configurator.h>  
#include <iomanip>  
using namespace log4cplus;  
  
int main()  
{  
    BasicConfigurator config;  
    config.configure();  
      
    Logger logger = Logger::getInstance(LOG4CPLUS_TEXT("main"));  
    LOG4CPLUS_WARN(logger, LOG4CPLUS_TEXT("Hello, World!"));  
    return 0;  
}


程式包含了一些必要的標頭檔案,編譯時需要連結log4cplus庫,將這段程式碼儲存為 test.cpp,執行以下命令編譯:

g++ test.cpp -o test -llog4cplus  

編譯後生成 test 可執行檔案,執行./test,得到如下輸出:
WARN - Hello, World!  

這個程式使用的是log4cplus內建的預設配置選項,實際使用中一般要自己配置選項,接下來你會看到。

5 log4cplus配置

log4cplus配置就是定義appender, 定義輸出的格式即 layout。以下列出兩種常用配置,以供參考。

配置輸出到控制檯(通常用於前臺程式):

log4cplus.logger.logmain = TRACE, console  
log4cplus.appender.console = log4cplus::ConsoleAppender  
log4cplus.appender.console.layout = log4cplus::PatternLayout  
log4cplus.appender.console.layout.ConversionPattern = [%D{%m/%d/%y %H:%M:%S,%q} %-5p] - %m%n  

配置輸出到檔案(通常用於後臺程式):
log4cplus.logger.logmain = INFO, file  
log4cplus.appender.file = log4cplus::FileAppender  
log4cplus.appender.file.File = /var/log/myapp.log  
log4cplus.appender.file.MaxFileSize = 10M  
log4cplus.appender.file.Append = true  
log4cplus.appender.file.layout = log4cplus::PatternLayout  
log4cplus.appender.file.layout.ConversionPattern = [%D{%m/%d/%y %H:%M:%S,%q} %-5p] - %m%n

簡單說明一下,配置檔案中log4cplus.logger.logmain即定義一個logmain物件,後面跟的兩個欄位前一個表示log級別,後一個指定使用的appender,即日誌輸出物件。log級別按嚴重程度從低到高依次為TRACE、DEBUG、INFO、WARN、ERROR、FATAL。log4cplus.appender.xxx定義具體的appender屬性,如是控制檯還是檔案,進一步配置檔名、檔案大小等。

將配置儲存到一個配置檔案中(如log4cplus.conf),以下你將看到如何使用配置檔案。有關更詳細的配置,讀者可自行摸索。

6 log4cplus運用於專案

以上“hello, world”程式只是大概演示log4cplus的用法,實際專案使用要有系統觀念,就是怎樣用才更方便,我們可以再做點封裝。我們可以定義一個全域性logger物件,將log4cplus初始化配置放到一個原始檔中,重新定義一些簡化的巨集置於標頭檔案,比如筆者就定義了Log.h/Log.cpp兩個檔案,程式碼如下:

Log.h檔案:

#pragma once  
#include <log4cplus/logger.h>  
#include <log4cplus/loggingmacros.h>  
using namespace log4cplus;  
using namespace log4cplus::helpers;  
// global object  
extern Logger logger;  
// define some macros for simplicity  
#define LOG_TRACE(logEvent)         LOG4CPLUS_TRACE(logger, logEvent)  
#define LOG_DEBUG(logEvent)         LOG4CPLUS_DEBUG(logger, logEvent)  
#define LOG_INFO(logEvent)          LOG4CPLUS_INFO(logger, logEvent)  
#define LOG_WARN(logEvent)          LOG4CPLUS_WARN(logger, logEvent)  
#define LOG_ERROR(logEvent)         LOG4CPLUS_ERROR(logger, logEvent)  
#define LOG_FATAL(logEvent)         LOG4CPLUS_FATAL(logger, logEvent)  
  
extern void InitLogger(bool daemonized); 

Log.cpp檔案:

#include <log4cplus/logger.h>  
#include <log4cplus/consoleappender.h>  
#include <log4cplus/fileappender.h>  
#include <log4cplus/layout.h>  
#include <log4cplus/configurator.h>  
  
#include "Log.h"  
  
Logger logger = Logger::getInstance(LOG4CPLUS_TEXT("logmain"));  
  
void InitLogger(bool daemonized)  
{  
    if (daemonized)  
        PropertyConfigurator::doConfigure(LOG4CPLUS_TEXT("/your/path/log4cplusd.conf"));  
    else  
        PropertyConfigurator::doConfigure(LOG4CPLUS_TEXT("/your/path/log4cplus.conf"));  
}  

將這兩個檔案置於你的專案中,然後在 main 函式中呼叫 InitLogger() 初始化 log4cplus,再在需要加log的檔案中包含Log.h即可。注意InitLogger函式的引數daemonized,該引數表示應用程式是否是守護程序(後臺執行),一般我們開發的應用程式大多是守護程序(linux後臺服務大多是守護程序),但除錯的時候會前臺執行,對於守護程序,我們只需要把日誌記錄到某個檔案中就行了,而對於前臺除錯執行,我們就只需要將日誌輸出到控制檯,所以這裡是一點使用技巧。做到這點我們只需分別提供兩個配置檔案即可,"/your/path"就是你放置配置檔案的地方,一般可以設為你應用程式部署的目錄下的etc目錄。

至此我們可以使用log4cplus了!以下是實際的日誌輸出效果:

[11/05/12 10:28:36,002 INFO ] - TCPDomain - TCPDomain()  
[11/05/12 10:28:36,002 INFO ] - TCPDomain - Connect server success!  
[11/05/12 10:28:36,002 TRACE] - Session - Thread run.  
[11/05/12 10:28:46,006 ERROR] - TCPDomain - SelectRead time out!  
[11/05/12 10:28:56,016 ERROR] - TCPDomain - SelectRead time out!  

7 log4cplus交叉編譯

對於嵌入式應用 ,有交叉編譯這麼一說。以上的介紹是基於PC的,如果你的平臺是嵌入式平臺如arm,則只需編譯連結arm平臺的log4cplus庫即可,其它都一樣。對於大多數autotools工程,其交叉編譯方法大致如下:

./configure --prefix=/your/install/path --host=arm-linux CXX=your-toolkit-g++  
make  
make install  

其中--prefix即指定你的安裝目錄,如/opt/log4cplus,--host指定目標平臺,CXX指定你的交叉編譯工具(確保shell環境能找到該工具)。編譯安裝完後可在安裝目錄找到arm版本的庫檔案。

8 總結

日誌固然好,但也不建議隨意使用,用多了會導致程式效能有所下降,且程式碼size增加不少。以上是筆者運用log4cplus的些許經驗,更深一步的原理機制有待進一步探究。