【日志系统】

公共头文件

定义了一个枚举类 LOG_LEVEL 用于表示日志级别,并创建了两个字符串数组 IndToStr 和 LLTOSTR 来将这些级别转换为对应的字符串表示

enum class LOG_LEVEL
    {
        TRACE = 0,
        DEBUG,
        INFO,
        WARN,
        ERROR,
        FATAL,
        SYSERR,
        SYSFATAL,
        NUM_LOG_LEVELS
    };
    static const char *IndToStr[] =
    {
        "TRACE", // 0
        "DEBUG", // 1
        "INFO",  // 2
        "WARN",  // 3
        "ERROR", // 4
        "FATAL", // 5
        "SYSERR",
        "SYSFATAL",
        "NUM_LOG_LEVELS" // 6
};
static const char *LLTOSTR[] = {
        "TRACE", // 0
        "DEBUG", // 1
        "INFO",  // 2
        "WARN",  // 3
        "ERROR", // 4
        "FATAL", // 5
        "SYSERR",
        "SYSFATAL",
        "NUM_LOG_LEVELS"};
}


TRACE            最详细的日志,用于调试内部流程    
DEBUG            开发调试信息,生产环境通常关闭    
INFO                关键业务流程的运行状态信息        
WARN              潜在问题或非关键错误              
ERROR            功能异常,但系统仍可继续运行      
FATAL               严重错误,可能导致当前操作失败    
SYSERR          系统级错误,如资源耗尽            
SYSFATAL       系统无法继续运行的致命错误        

日志流对象  LogMessage

功能:1. 构造日志消息流 2. 添加正文信息 3. 获取完整的日志字段信息字符串

成员变量

    private:
        std::string header_;   //Timestamp + level + filie.cpp + line
        std::string text_;     //正文
        tulun::LOG_LEVEL level_;

主要成员方法

  • 构造函数
public:
        LogMessage(const tulun::LOG_LEVEL &level,
                   const std::string &filename,
                   const std::string &funcname,
                   const int line):header_{},text_{},level_(level)
    {
        std::stringstream ss;
        ss << tulun::Timestamp::Now().toFormattedString()<<" ";
        ss << tulun::IndexToStr[static_cast<int>(level_)] << " ";
        
        const size_t pos = filename.rfind('/');
        const std::string fname = filename.substr(pos + 1);
        ss << fname << " " << funcname << " " << line << " ";
        
        header_ = ss.str();
    }

 注意:我们传入的文件名一般用 __FILE__宏表示,但此展开是标准文件名,即前面会加具体的路径,这个我们是不需要的,有些冗余,所以传入的文件名我们需要做一些改动,删除具体路径信息。

  • 重载运算符
LogMessage &operator<<(const _Ty &text)
        {
            std::stringstream ss;
            ss << " : " << text;
            text_ += ss.str();
            return *this;
        }

日志对象 Logger

是一个基于 RAII 技术的日志系统

作用:

1. 设置日志等级
2. 设置打印回调函数,默认打印到终端
3. 设置刷新回调函数
4. 获取日志流对象
5. 一个日志对象对应一条完整的日志信息,析构函数负责将日志信息写入终端或文件

成员变量

tulun::LogMessage impl_;   //日志消息对象


//当前日志级别,控制哪些级别的日志可以被输出 
static tulun::LOG_LEVEL s_level_;    //=InitLogLevel()

 

输出与刷新机制

//定义输出函数类型,将日志输出到目标位置
using OutputFun = std::function<void(const std::string &)>;
//定义刷新函数类型,确保缓冲区日志被立即输出
using FlushFun = std::function<void(void)>;

static OutputFun s_output_;
static FlushFun s_flush_;


static void SetOuput(OutputFun fun)// 设置自定义输出函数
 {
    s_output_=fun;
 }
static void SetFlush(FlushFun fun)//设置自定义刷新函数
 {
    s_flush_=fun;
 }


void defaultOutput(const string&msg)  //默认输出函数,日志输出到stdout
 {
    //使用fwrite写入到终端
    size_t n=fwrite(msg.c_str(),sizeof(char),msg.size(),stdout);
    
 }

void defaultFlush()
 {
    fflush(stdout);
 }
  • 通过函数对象实现策略模式,允许动态替换日志输出行为


构造与析构函数 

        Logger(const tulun::LOG_LEVEL &level,
               const string &filename,
               const string &funcname,
               const int line)
               :impl_(level,filename,funcname,line){}
           
  • __FILE__:当前源文件名(预定义宏)
  • __func__:当前函数名(预定义宏)
  • __LINE__:当前行号(预定义宏)
 ~Logger()
        {
	        //添加换行符,并且使完整日志输出
	        impl_<<'\n';  
	        s_output_(impl_.toString());
	        //确保所有日志消息被立即输出
	        s_flush_();

			//如果是FATAL级别的日志,中止运行程序
			if(impl_.getLogLevel()==LOG_LEVEL::FATAL){
				frpintf(stderr,"Process exit\n");
				exit(EXIT_FAILURE);
			}
        }

使用到了RAII思想

  • 构造时准备资源(记录上下文)
  • 析构时释放资源(输出并刷新日志)

宏定义

// 日志宏定义 - 用于在代码中方便地记录不同级别的日志
// 每个宏都会检查当前日志级别,只有级别足够高时才会生成日志
// 使用方式示例:LOG_INFO << "This is an info message";
//  \ 称为宏的续行符 ,此符号后面直接跟回车,不要出现任何字符

#define LOG_TRACE                                                \
    if (Logger::getLogLevel() <= LOG_LEVEL::TRACE) \
    Logger(LOG_LEVEL::TRACE, __FILE__, __func__, __LINE__).stream()

#define LOG_DEBUG                                                 \
if (Logger::getLogLevel() <= LOG_LEVEL::DEBUG) \
    Logger(LOG_LEVEL::DEBUG, __FILE__, __func__, __LINE__).stream()

#define LOG_INFO                                                 \
    if (Logger::getLogLevel() <= LOG_LEVEL::INFO) \
    Logger(LOG_LEVEL::INFO, __FILE__, __func__, __LINE__).stream()

#define LOG_WARN \
    Logger(LOG_LEVEL::WARN, __FILE__, __func__, __LINE__).stream()

#define LOG_ERROR \
    Logger(LOG_LEVEL::ERROR, __FILE__, __func__, __LINE__).stream()

#define LOG_FATAL \
    Logger(LOG_LEVEL::FATAL, __FILE__, __func__, __LINE__).stream()

#define LOG_SYSERR \
    Logger(LOG_LEVEL::ERROR, __FILE__, __func__, __LINE__).stream()

#define LOG_SYSFATAL \
    Logger(LOG_LEVEL::FATAL, __FILE__, __func__, __LINE__).stream()
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值