作者:CppExplore 網址:http://www.shnenglu.com/CppExplore/
log模塊是一個小模塊,卻是每個系統必備的模塊。優秀的系統一定會有優秀的log信息,也可以說全面到位的log信息在一定程度上決定了一個系統的健壯性。在linux上,log模塊是跟蹤程序運行,驗證業務邏輯正確的唯一方法。
一、功能
一個優秀的log系統應該包含以下功能:
(1)支持打印到屏幕、文件、socket、syslog
(2)支持分級別打印
(3)支持分模塊打印
(4)支持多線程
(5)支持文件轉儲:按時間、按大小。
二、使用原則
方便說明,這里定義8個log級別:

typedef enum
{
XLOG_CRITICAL=0x1,
XLOG_ERROR=0x2,
XLOG_WARNING=0x4,
XLOG_NOTICE=0x8,
XLOG_INFO=0x10,
XLOG_DEBUG=0x20,
XLOG_TRACE=0x40,
XLOG_ALL=0x80
}XLogLevel;
使用方式舉例如下:
X_LOG(XLOG_NOTICE,"message[%s:%d]\n",char_value,int_value);
打印log的原則:
(1)重要的函數(業務處理)入口處打印XLOG_DEBUG級別log,打印出函數名稱、入口參數。
(2)函數有多個執行支路,在異常退出函數的支路上,打印XLOG_WARNING級別log,表明退出原因。
(3)系統調用發生異常,甚至造成程序退出的地方,打印XLOG_ERROR級別log,表明發生該錯誤的文件、行數、錯誤號
(4)為所有的類對象實現dump方法,該方法打印該類中的所有私有屬性信息,以XLOG_NOTICE級別打印,當類對象中含有自定義的類屬性時,該類的dump中打印屬性類信息可以直接調用屬性類的dump。運行期間,可以給用戶提供輸入接口:telnet、交互式shell命令行、或者簡單的getchar,根據用戶要求,執行頂級類對象的dump,以運行期間查看系統內所有數據的內部信息。
(5)該系統與外在系統的交互信息,往來數據包使用XLOG_INFO級別打印。
(6)為了調試系統,更為細微的查看系統的運行狀況而加入的log,使用XLOG_TRACE級別。
三、log模塊框架
可選的開源log很多:ace_log/Log4c/log4c**/log4c++/Pantheios/Log4cplus。依據開源項目活躍程度、庫本身的獨立性以及參考文檔的數量,個人選擇的開源庫是Log4cplus。個人測試,未發現該庫(v1.02)有bug或者內存泄漏現象,大力推薦。網上有關該庫的文檔的也相當多,我就不再羅唆了。
下面是我的log框架,不依賴于具體的log模塊,相信你會喜歡:
#ifndef _X_LOG_H_
#define _X_LOG_H_
#include <stdio.h>
#include <errno.h>

#ifdef USE_LOG4CPLUS
#include <log4cplus/configurator.h>
#include <string>
static log4cplus::Logger logger= log4cplus::Logger::getInstance("Log");
static void init_log(const std::string & path)

{
log4cplus::PropertyConfigurator::doConfigure(path);
}
#define XLOG_ALL log4cplus::TRACE_LOG_LEVEL
#define XLOG_TRACE log4cplus::TRACE_LOG_LEVEL
#define XLOG_DEBUG log4cplus::DEBUG_LOG_LEVEL
#define XLOG_INFO log4cplus::INFO_LOG_LEVEL
#define XLOG_NOTICE log4cplus::INFO_LOG_LEVEL
#define XLOG_WARNING log4cplus::WARN_LOG_LEVEL
#define XLOG_ERROR log4cplus::ERROR_LOG_LEVEL
#define XLOG_CRITICAL log4cplus::FATAL_LOG_LEVEL

#define X_LOG(l,
) \

do
{ \

if(logger.isEnabledFor(l))
{ \

char __buf__internal__[2046]=
{0}; \
snprintf(__buf__internal__,2045,__VA_ARGS__); \
logger.forcedLog(l, __buf__internal__, __FILE__,

__LINE__); \
} \
} while(0);
#elif define USE_ACE_LOG
#include "ace/Log_Msg.h"
#include "ace/Trace.h"
#define XLOG_ALL LM_TRACE
#define XLOG_TRACE LM_TRACE
#define XLOG_DEBUG LM_DEBUG
#define XLOG_INFO LM_INFO
#define XLOG_NOTICE LM_NOTICE
#define XLOG_WARNING LM_WARNING
#define XLOG_ERROR LM_ERROR
#define XLOG_CRITICAL LM_CRITICAL

#define X_LOG(l,
) do
{ \
ACE_DEBUG((l,"[%T|%t] %s-%s:%

d",__FILE__,__FUNCTION__,__LINE__)); \
ACE_DEBUG((l,__VA_ARGS__)); \
}while(0)
#else
#include <pthread.h>
#include <time.h>
#include <sys/time.h>
#define XLOG_LEVEL 0xFF

typedef enum
{
XLOG_CRITICAL=0x1,
XLOG_ERROR=0x2,
XLOG_WARNING=0x4,
XLOG_NOTICE=0x8,
XLOG_INFO=0x10,
XLOG_DEBUG=0x20,
XLOG_TRACE=0x40,
XLOG_ALL=0x80
}XLogLevel;

#define X_LOG(l,
) do
{ \

if(XLOG_LEVEL&l)
{ \
struct timeval now;\
gettimeofday(&now,0); \
struct tm *ptm=localtime(&(now.tv_sec)); \
printf("[%d|%d:%d:%d.%d] [%s/%s/%d]

",pthread_self(),ptm->tm_hour,ptm->tm_min,ptm-

>tm_sec,now.tv_usec,__FILE__,__FUNCTION__,__LINE__); \
printf( __VA_ARGS__); \
} \
}while(0)
#endif


#define die(str)
{X_LOG(XLOG_WARNING,str); return;}


#define die_0(str)
{X_LOG(XLOG_WARNING,str); return 0; }


#define die_1(str)
{X_LOG(XLOG_WARNING,str); return -1; }


#define die_ns(str)
{X_LOG(XLOG_WARNING,str); return ""; }


/**//*safe func return empty,0,-1*/
#define SAFE_FUNC(func) if((func)<0) \

{ \
X_LOG(XLOG_ERROR,"[%s:%d]error!error[%d:%s]

\n",__FILE__,__LINE__,errno,strerror(errno)); \
exit(-1); \
}


/**//*safe func but 1 err return empty,0,-1*/
#define SAFE_FUNC_BUT_ERR1(func,ERR1) do \

{ \

if((func)<0)
{ \
X_LOG(XLOG_ERROR,"[%s:%d]error!error[%d:%s]

\n",__FILE__,__LINE__,errno,strerror(errno)); \
if(errno!=ERR1) exit(-1); \
} \
else break; \
}while(1)


/**//*safe func but 2 err return empty,0,-1*/
#define SAFE_FUNC_BUT_ERR2(func,ERR1,ERR2) do \

{ \

if((func)<0)
{ \
X_LOG(XLOG_ERROR,"[%s:%d]error!error[%d:%s]

\n",__FILE__,__LINE__,errno,strerror(errno)); \
if(errno!=ERR1&&errno!=ERR2) exit(-1); \
} \
else break; \
}while(1)
#endif
當前的XLog.h文件實現了使用log4cplus、ace、printf三種方式,當然可以隨意擴展。die則是XLOG_WARNING的打印方式,SAFE_FUNC是XLOG_ERROR的打印方式。
如果要使用log4cplus,請定義USE_LOG4CPLUS宏,使用的時候在進程開始處,
#ifdef USE_LOG4CPLUS
init_log("log.properties");
#endif
以X_LOG的方式使用log4cplus,你可以對log4cplus一無所知。執行你編譯好的程序前,在可執行程序的目錄下建立log.properties文件,內容你可以這樣寫:
# Define the root logger
log4cplus.rootLogger=TRACE, consoleAppender, fileAppender

# Define a file appender named "consoleAppender"
log4cplus.appender.consoleAppender=log4cplus::ConsoleAppender
log4cplus.appender.consoleAppender.layout=log4cplus::PatternLayout

log4cplus.appender.consoleAppender.layout.ConversionPattern=%-5p-[%t][%D
{%H:%M:%S %Q}]%m

# Define a file appender named "fileAppender"
log4cplus.appender.fileAppender=log4cplus::RollingFileAppender
log4cplus.appender.fileAppender.MaxFileSize=200KB
log4cplus.appender.fileAppender.File=./log.log
log4cplus.appender.fileAppender.MaxBackupIndex=3
log4cplus.appender.fileAppender.layout=log4cplus::PatternLayout

log4cplus.appender.fileAppender.layout.ConversionPattern=%-5p-[%t][%D
{%H:%M:%S %Q}]%m
有關log.properties文件的配置,可以自行去查找有關log4cplus的文章。如果你沒使用過log4cplus,ok,那么下載一個log4cplus,編譯,依據本文的XLog.h文件構建一個系統,嘗試以下,你一定會驚嘆log4cplus的強大與美妙。