【网络编程】muduo库——Logger日志类

日志类相对来说比较简单,在每个项目中 也都能经常用到。

其主要的函数就是三个

         1、因为日志对象在整个项目中是唯一的,所以采用单例模式,来获取日志对象

         2、设置日志级别,通常包括INFO   ERROR  FATAL   DEBUG这四大类

         3、设置日志信息

//定义日志级别 INFO ERROR FATAL DEBUG
enum LogLevel
{
    INFO,   //普通信息
    ERROR,  //错误信息
    FATAL,  //core信息
    DEBUG,  //调试信息
};

//输出一个日志类
class Logger:noncopyable
{
public:
     //获取日志唯一的实例对象
    static Logger& instance();
    //设置日志级别
    void setLogLevel(int level);
    //写日志
    void log(std::string msg);
private:
    int logLevel_;
};

 其内部实现如下所示,也是主打一个简单易懂,这里就不多说啥了

#include "Logger.h"
#include "Timestamp.h"   //该类是关于时间的类,在下一篇文章中有解释

#include 



//获取日志的唯一实例对象
Logger& Logger::instance()
{
    static Logger logger;
    return logger;
}

//设置日志级别
void Logger::setLogLevel(int level)
{
    logLevel_ = level;
}

//写日志 [级别信息] time : msg
void Logger::log(std::string msg)
{
   switch (logLevel_)
   {
   case INFO:
        std::cout<<"[INFO]";
        break;
   case ERROR:
        std::cout<<"[ERROR]";
        break;
    case FATAL:
        std::cout<<"[FATAL]";
        break;
    case DEBUG:
        std::cout<<"[DEBUG]";
        break;
    default:
        break;
   }

   //打印时间和msg   //这里和时间有关的函数 放在下一篇文章中实现
   std::cout<< Timestamp::now().toString() <<" : "<

其实设置日志级别 或者是获取单例等,对于调用者来说是不重要的,因为调用者只想简单的调用一个函数来完成日志的输出,如果我们直接将上述类交给调用者,他们用起来还是太复杂了。

我们可以在Logger.h文件中 采用宏定义来简化对接口的调用

//LOG_INFO("%s %d",arg1,arg2)
#define LOG_INFO(logmsgFormat, ...) \
    do\
    {\
        Logger &logger = Logger::instance(); \
        logger.setLogLevel(INFO); \
        char buf[1024] = {0};\
        snprintf(buf,1024,logmsgFormat,##__VA_ARGS__);\
        logger.log(buf);\
    }while (0)


#define LOG_ERROR(logmsgFormat, ...) \
    do\
    {\
        Logger &logger = Logger::instance(); \
        logger.setLogLevel(ERROR); \
        char buf[1024] = {0};\
        snprintf(buf,1024,logmsgFormat,##__VA_ARGS__);\
        logger.log(buf);\
    }while (0)

#define LOG_FATAL(logmsgFormat, ...) \
    do\
    {\
        Logger &logger = Logger::instance(); \
        logger.setLogLevel(FATAL); \
        char buf[1024] = {0};\
        snprintf(buf,1024,logmsgFormat,##__VA_ARGS__);\
        logger.log(buf);\
    }while (0)

#ifdef MUDEBUG   //DEBUG信息可能时常会过长,从而输出过多其实我们并不太需要的调试信息,可以适时屏蔽
#define LOG_DEBUG(logmsgFormat, ...) \
    do\
    {\
        Logger &logger = Logger::instance(); \
        logger.setLogLevel(DEBUG); \
        char buf[1024] = {0};\
        snprintf(buf,1024,logmsgFormat,##__VA_ARGS__);\
        logger.log(buf);\
    }while (0)
#else
    #define LOG_DEBUG(logmsgFormat, ...)
#endif

这里的宏定义为什么使用do……while(0)呢,可参考下面的博客,总之就是 
辅助定义复杂的宏,避免引用的时候出错,提高代码健壮性

do while(0)的作用以及原因_康来个程的博客-CSDN博客

可变参数宏...和_ _VA_ARGS_ _

  …和_ _VA_ARGS_ _是组合使用的,用在不确定参数个数的场合中。

你可能感兴趣的:(网络编程,c++)