Easylogging的封装使用一

来源:互联网 发布:js 中splice方法 编辑:程序博客网 时间:2024/06/03 16:47

一.封装的目的和使用范围
在上一篇文章中介绍了Easylogging的简单使用:http://blog.csdn.net/woshichenweixian/article/details/77018452 ,一般情况下,在自己的项目中使用时,可以再对其封装一下,使其适合自己的使用习惯。这博文章主要介绍一下我在最近的一个项目中对Easylogging的封装使用,该项目是一个C++后台服务器,对log系统的使用要求如下:
(1)能区分log等级:debug,trace,info,warn,err等等级
(2)能方便控制某个等级的log输出与否
(3)能方便输出:char buf[len] , int buf[lend]等数组,而无需区分数组元素是字符类型还是整数类型
(4)能方便输出数据包

二.初始化和配置
首先是对Easylogging初始化用一个宏进行封装,若后期需要添加其他初始化代码,则只需修改该宏就可以:
#define LogSysInit   _INITIALIZE_EASYLOGGINGPP

接着是对Easylogging进行配置,Easylogging的配置和我们最终要使用的log等级有很大关系,所以先介绍一下在该封装系统中对log等级的定义和使用方式:
对log等级进行封装和控制,我个人一般对log等级区分如下:
Debug等级:只在在开发阶段输出的log,用于跟踪开发过程中的调试输出;
Info等级:输出程序运行相关的信息,可在上线后选择是否输出该等级的log;
Trace等级:输出一些程序状态数据,用于跟踪程序运行状态,一般在上线后应该一直让该等级的log输出,但也可关掉该log。
Warn等级:输出影响到程序正常运行,但还能继续运行的数据信息。在上线后也应该一直让该等级的log输出。
Error等级:输出导致程序不能继续运行,必须马上终止程序的错误信息。在上线后也应该一直让该等级log输出。

几个比较容易混淆的log等级的使用情景如下:
Trace:跟踪程序的运行分支,例如:
if(condition 1){Log(Trace) << "in condition 1" ;}else if(condition 2){Log(Trace) << "in condition 2" ;}

Warn:不会导致程序必须马上终止的错误:
if(valus == InvalidValus){log(warn) << "valus is invalid:" << valus ;return ;} DoSomeThing() ;

Error:导致程序必须马上终止的错误:
char *buf = new(nothrow) char ; if(buf == NULL){log(Error) << "new is failed" ;ExitProcess() ;}DoSomeThing() ;

为了达成上面所说的log等级配置,可以抽象出一个配置接口出来:
#define LogSysCfg(cfgInfo , debugSwitch)   LogCfg::initLog(cfgInfo,debugSwitch) ;
  LogSysCfg宏传入两个配置参数,一个是cfgInfo,用来控制Info和Trace等级的log输出;一个是debugSwitch,用来控制Debug等级的输出。
真正实现配置的地方在LogCfg类的静态方法中:
class LogCfg{public:LogCfg(){}/*@param cfgInfo,控制trace,info等级的log输出:err和warn等级任何情况下都输出,trace和info等级的根据配置信息开启:0:不开启trace,info1:开启trace,不开info2:开启trace和info@param debugSwitch,控制debug等级的log输出*/ static bool initLog(int cfgInfo,int debugSwitch){easyloggingpp::Configurations cfg;cfg.setToDefault();std::string cfgStr = GetCfgStr(cfgInfo,debugSwitch) ;cfg.parseFromText(cfgStr.c_str()) ;easyloggingpp::Loggers::reconfigureAllLoggers(cfg) ;cfg.clear() ;return true ;}static bool reCfgLog(){return true ;}private:static std::string GetCfgStr(int cfgInfo,int debugSwitch){std::string cfgStr("*ALL:\n                                                     \  FORMAT = [%datetime] :%log\n\  ENABLED = false \n                                                \  TO_FILE = true \n                                                 \  TO_STANDARD_OUTPUT = false \n                                     \  ROLL_OUT_SIZE = 2097152    \n                                     \  FILENAME = logs/ErrWarnLog.log \n                                 \  *ERROR:\n                                                         \  ENABLED = true\n                                                  \  *WARNING:\n                                                       \  ENABLED = true\n                                                  \  *TRACE:\n                                                         \  FILENAME = logs/TraceLog.log \n                                   \  ROLL_OUT_SIZE = 10485760 \n                                       \  ");if((1 == cfgInfo) || (2== cfgInfo))cfgStr += "ENABLED = true\n" ;cfgStr += " *INFO:\n                                                      \  FILENAME = logs/InfoLog.log \n                                  \  ROLL_OUT_SIZE = 10485760 \n                                     \  " ;if(2 == cfgInfo)cfgStr += "ENABLED = true \n" ;cfgStr += " *DEBUG:\n                                                       \  FILENAME = logs/DebugLog.log \n                                   \  ROLL_OUT_SIZE = 10485760 \n                                       \  " ;if(1 == debugSwitch)cfgStr += "ENABLED = true" ;return cfgStr ;}};  

经过上面的配置后,Debug,Info,Trace等级可配置,而Warn和Error等级的log会一直输出。log文件在当前目录下的logs文件夹里面,每个等级的log存放在各自的文件里面。

三.对log输出的封装
我个人的习惯是不直接使用Easylogging给出的宏,而是自己再封一层,因为若以后需要改动的时候,直接改自己封的宏就好了。一些常见的封装:
//普通log输出#define LogInfoLINFO#define LogTraceLTRACE#define LogWarnLWARNING#define LogError    LERROR#define LogBreak(fmt)                                                                                             \    {                                                                                                            \LogWarn<<fmt;                                                                                        \break ;                                                                                                  \}                                                                                                            \//如果断言失败,则把该log打印出来,不会结束程序#define LogAssert(condition)  LWARNING_IF(!(condition))<<"[Log Assert]:"//用于服务端发给客户端时的log输出#define LogSTC    LogDebug<<"[S To C]:  "//用于客户端发给服务端端时的log输出#define LogCTS    LogDebug<<"[C To S]:  " 

如果之后不想用Easylogging的LINFO,则只需修改宏就好,例如,把它改成用Easylogging的BINFO。
LogBreak宏可以方便的用来跳出循环之前打印一条log;
LogAssert宏则实现类似于断言的功能;
LogSTC和LogCTS适用于CS架构中区分服务器发给客户端huo客户端发给服务器的消息。

接着是输出数组的一个封装:
enum LEVEL{MY_ERR = 0 ,MY_Warn  ,MY_Debug ,MY_Trace ,MY_Info };#define LogInfoDump(info , size,buff)             logDump(info , buff , size , LEVEL::MY_Info)       #define LogTraceDump(info , size,buff)            logDump(info , buff , size , LEVEL::MY_Trace)#define LogWarnDump(info , size,buff)             logDump(info , buff , size , LEVEL::MY_Warn)#define LogErrorDump(info , size,buff)            logDump(info , buff , size , LEVEL::MY_ERR)#define LogDebugDump(info , size,buff)            logDump(info , buff , size , LEVEL::MY_Debug)template<class _TYPE>void logDump(char *info,_TYPE *buff ,int size,LEVEL logLevel)                                                                                       {                                                                                                                             std::string str(info) ;                                                                                                        str += ": " ;                                                                                                             if(buff == NULL || size <=0)                                                                                                                                                                                                                     str+="buff is null!" ;                                                                                                                                                                                                                        else                                                                                                                      {                                                                                                                         std::stringstream ss ;                                                                                                     for(int _dumpArrSize = 0; _dumpArrSize < size ; ++_dumpArrSize)                                                                                                                                                                           ss << buff[_dumpArrSize] << "," ;                                                                                                                                                                                    str += ss.str() ;                                                                                                     }                                                                                                                         logStrOut(size , str ,logLevel) ;                                     }void logStrOut(int size , std::string str , LEVEL logLevel){switch(logLevel){case MY_ERR:LogError<<"[Arr Count:"<<size <<"]" <<str ; break;case MY_Debug:LogDebug<<"[Arr Count:"<<size <<"]" <<str ;break;case MY_Info:LogInfo<<"[Arr Count:"<<size <<"]" <<str ;break;case MY_Trace:LogTrace<<"[Arr Count:"<<size <<"]" <<str ;break;case MY_Warn:LogWarn<<"[Arr Count:"<<size <<"]" <<str ;break;default:break ;}}

在上面的封装中,存在一个问题,即:当输出char类型或者char数组时,可能出现乱码。例如输出:
char aa =1 ;        char arr[3] = {1,2,3} ;
char aa = 1 ;LogDebug<<"logDebug:" << aa ;char buf[3] = {1,2,3} ;LogDebugDump("logdebugdump:",3,buf) ;
本意是要输出1和1,2,3的,但因为在easylogging中,log是通过标准输出流输出的,所以如果输出一个char类型数据,是其字符,而不是数值来的。而ASSCII码的1,2,3对应的字符都是乱码来的。
下一篇文章《Easylogging的封装使用二》将讲讲如何解决这个问题,并将一下如何封装自己的数据包(struct ,class类型)进行输出。













原创粉丝点击