作者:CppExplore 网址:http://www.cppblog.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的强大与美妙。