muduo网络库剖析——日志Log类

本文详细介绍了muduo网络库中的Log类,涉及日志级别、单例模式的应用以及如何通过预处理器宏实现统一的日志格式。作者分享了项目实践中的经验和心得,鼓励读者养成写博客的习惯以提升技术水平。
摘要由CSDN通过智能技术生成

前情

从muduo到my_muduo

作为一个宏大的、功能健全的muduo库,考虑的肯定是众多情况是否可以高效满足;而作为学习者,我们需要抽取其中的精华进行简要实现,这要求我们足够了解muduo库。

做项目 = 模仿 + 修改,不要担心自己学了也不会写怎么办,重要的是积累,学到了这些方法,如果下次在遇到通用需求的时候你能够回想起之前的解决方法就够了。送上一段话!

在这里插入图片描述

概要

日志

日志是用来记录重大事件的工具。
日志文件是重要的系统信息文件,其中记录了很多重要的系统事件。包括用户的登录信息,系统的启动信息,系统的安全信息,邮件相关信息,各种服务相关信息。
日志对于安全来说也很重要,它记录了每天系统发生的各种事情,通过日志来检查错误发生的原因,或者受到攻击时攻击者留下的痕迹。

日志级别

在这里插入图片描述
上面是muduo库的主要日志级别。
在这里插入图片描述
上面是我搜索到的日志级别解释。

框架与细节

成员

  1. 日志级别划分

    我们这里主要用到INFO、DEBUG、WARN、ERROR、FATAL作为我们小规模的日志库日志级别划分。

函数

  1. 日志级别设置

    在这里插入图片描述

    static修饰类成员函数则该成员函数属于整个类,而非类对象,调用需要加类域,初始化要在类外。

  2. 日志实例创建——单例模式

    我们通过返回静态变量能够获得唯一的日志实例,使用的是懒汉式单例模式。有关单例模式,想要了解复习的uu可以跳转到

  3. 写日志

    • 关于写日志,我们需要确定统一的写的格式,muduo库选择使用宏定义的方式来统一我们写单条日志的格式。
      在这里插入图片描述 这里使用到了是将宏定义做成流对象进行传输,类似于c++中的cout。我们同样可以使用类似于printf的格式类型来实现我们的日志输出格式化。比如:

       #define LOG_INFO(logmsgformat, ...)                             \
           do {                                                        \
               Log& lp = Log::getInstance();                           \
               lp.setLogLevel(INFO);                                   \
               char buf[64] = {0};                                     \
               snprintf(buf, sizeof buf, logmsgformat, ##__VA_ARGS__); \
               lp.writeLog(buf);                                       \
           } while (0)
       
       #define LOG_DEBUG(logmsgformat, ...)                            \
           do {                                                        \
               Log& lp = Log::getInstance();                           \
               lp.setLogLevel(DEBUG);                                  \
               char buf[64] = {0};                                     \
               snprintf(buf, sizeof buf, logmsgformat, ##__VA_ARGS__); \
               lp.writeLog(buf);                                       \
           } while (0)
       
       #define LOG_WARN(logmsgformat, ...)                             \
           do {                                                        \
               Log& lp = Log::getInstance();                           \
               lp.setLogLevel(WARN);                                   \
               char buf[64] = {0};                                     \
               snprintf(buf, sizeof buf, logmsgformat, ##__VA_ARGS__); \
               lp.writeLog(buf);                                       \
           } while (0)
       
       #define LOG_ERROR(logmsgformat, ...)                            \
           do {                                                        \
               Log& lp = Log::getInstance();                           \
               lp.setLogLevel(ERROR);                                  \
               char buf[64] = {0};                                     \
               snprintf(buf, sizeof buf, logmsgformat, ##__VA_ARGS__); \
               lp.writeLog(buf);                                       \
           } while (0)
       
       #define LOG_FATAL(logmsgformat, ...)                            \
           do {                                                        \
               Log& lp = Log::getInstance();                           \
               lp.setLogLevel(FATAL);                                  \
               char buf[64] = {0};                                     \
               snprintf(buf, sizeof buf, logmsgformat, ##__VA_ARGS__); \
               lp.writeLog(buf);                                       \
               exit(-1);                                               \
           } while (0)
      
    • VA_ARGS 是一个预处理宏,用于可变参数宏中。当你在一个宏定义中使用可变参数时,VA_ARGS 允许你捕获那些参数。它常用于宏定义的可变参数列表。

    • Log& lp = Log::getInstance();注意这行细节,我们使用引用可以避免赋值运算符。另外,我们也可以修改getInstance返回值,返回一个指针,这样也是可以实现功能的。

    • 因为FATAL定义为出现不可逆转的错误,所以采用程序结束的方式,exit(-1);

    • 对于writeLog函数的实现,我进行了规范的定义,[] : time, msg。输出结果应该如下:在这里插入图片描述
      后面将对时间功能进行重写。

    • 关于日志msg的格式输出,应该统一标准,至少需要达到这样的标准,才可以更好地在后期进行调试。
      在这里插入图片描述
      在此还要注意,buf的长度要大于我们输出的长度!!!

    源码

//Log.h
#pragma once 

#include <string>
#include <iostream>
#include <unistd.h>

#include "noncopyable.h"

enum LogLevel {
    INFO,
    ERROR,
    WARN,
    FATAL,
    DEBUG,
};

#define LOG_INFO(logmsgformat, ...)                             \
    do {                                                        \
        Log& lp = Log::getInstance();                           \
        lp.setLogLevel(INFO);                                   \
        char buf[128] = {0};                                     \
        snprintf(buf, sizeof buf, logmsgformat, ##__VA_ARGS__); \
        lp.writeLog(buf);                                       \
    } while (0)

#define LOG_DEBUG(logmsgformat, ...)                            \
    do {                                                        \
        Log& lp = Log::getInstance();                           \
        lp.setLogLevel(DEBUG);                                  \
        char buf[128] = {0};                                     \
        snprintf(buf, sizeof buf, logmsgformat, ##__VA_ARGS__); \
        lp.writeLog(buf);                                       \
    } while (0)

#define LOG_WARN(logmsgformat, ...)                             \
    do {                                                        \
        Log& lp = Log::getInstance();                           \
        lp.setLogLevel(WARN);                                   \
        char buf[128] = {0};                                     \
        snprintf(buf, sizeof buf, logmsgformat, ##__VA_ARGS__); \
        lp.writeLog(buf);                                       \
    } while (0)

#define LOG_ERROR(logmsgformat, ...)                            \
    do {                                                        \
        Log& lp = Log::getInstance();                           \
        lp.setLogLevel(ERROR);                                  \
        char buf[128] = {0};                                     \
        snprintf(buf, sizeof buf, logmsgformat, ##__VA_ARGS__); \
        lp.writeLog(buf);                                       \
    } while (0)

#define LOG_FATAL(logmsgformat, ...)                            \
    do {                                                        \
        Log& lp = Log::getInstance();                           \
        lp.setLogLevel(FATAL);                                  \
        char buf[128] = {0};                                     \
        snprintf(buf, sizeof buf, logmsgformat, ##__VA_ARGS__); \
        lp.writeLog(buf);                                       \
        exit(-1);                                               \
    } while (0)

class Log : noncopyable {
public:
    
    static Log& getInstance(); 
    void writeLog(const char* s);
    void setLogLevel(LogLevel logLevel) {
        logLevel_ = logLevel;
    }
private:
    //Log() {};
    LogLevel logLevel_;
    
};

//Log.cc
#include "Log.h"

Log& Log::getInstance() {
    static Log log;
    return log;
}


// [] : time, msg
void Log::writeLog(const char* s) {
    std::string ss;
    switch (logLevel_)
    {
    case INFO:
        ss += "[INFO] : ";
        break;
    case DEBUG:
        ss += "[DEBUG] : ";
        break;
    case ERROR:
        ss += "[ERROR] : ";
        break;
    case FATAL:
        ss += "[FATAL] : ";
        break;
    case WARN:
        ss += "[WARN] : ";
        break;
    default:
        break;
    }
    std::cout << ss << "time, " << s << std::endl;
}

结尾

以上就是日志Log类的相关介绍,以及我在进行项目重写的时候遇到的一些问题,和我自己的一些心得体会。发现写博客真的会记录好多你的成长,而且对于一个好的项目,写博客也是证明你确实有过深度思考,并且在之后面试或者工作时遇到同样的问题能够进行复盘的一种有效的手段。所以,希望uu们也可以像我一样,养成写博客的习惯,逐渐脱离菜鸡队列,向大佬前进!!!加油!!!

也希望我能够完成muduo网络库项目的深度学习与重写,并在功能上能够拓展。也希望在完成这个博客系列之后,能够引导想要学习muduo网络库源码的人,更好地探索这篇美丽繁华的土壤。致敬chenshuo大神!!!

鉴于博主只是一名平平无奇的大三学生,没什么项目经验,所以可能很多东西有所疏漏,如果有大神发现了,还劳烦您在评论区留言,我会努力尝试解决问题!

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值