技术系列之 必备外围功能-log

来源:互联网 发布:sql视频课程 编辑:程序博客网 时间:2024/04/28 21:06

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:%%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:%%Q}]%m

有关log.properties文件的配置,可以自行去查找有关log4cplus的文章。如果你没使用过log4cplus,ok,那么下载一个log4cplus,编译,依据本文的XLog.h文件构建一个系统,尝试以下,你一定会惊叹log4cplus的强大与美妙。

(本文首次发表于http://www.cppblog.com/CppExplore/archive/2008/06/05/52216.html)