现在的位置: 首页 > 综合 > 正文

服务器设计系列:日志模块

2013年02月08日 ⁄ 综合 ⁄ 共 4940字 ⁄ 字号 评论关闭

      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的强大与美妙。

参考文献:
技术系列之log:http://www.cppblog.com/CppExplore/MyPosts.html

抱歉!评论已关闭.