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的强大与美妙。
(本文首次发表于http://www.cppblog.com/CppExplore/archive/2008/06/05/52216.html)