02.webserver源码阅读--log

00.webserver源码阅读--buffer - DavidJIAN - 博客园 (cnblogs.com)

01.webserver源码阅读--BlockQueue - DavidJIAN - 博客园 (cnblogs.com)

log

本项目中,使用单例模式创建日志系统,对服务器运行状态、错误信息和访问数据进行记录,该系统可以实现按天分类,超行分类功能,可以根据实际情况分别使用同步和异步写入两种方式。

其中异步写入方式,将生产者-消费者模型封装为阻塞队列,创建一个写线程,工作线程将要写的内容push进队列,写线程从队列中取出内容,写入日志文件。

日志系统大致可以分成两部分,其一是单例模式与阻塞队列的定义,其二是日志类的定义与使用。

成员变量

  • 静态常量:
    • LOG_PATH_LEN、LOG_NAME_LEN、。顾名思义。
  • m_path
    • 日志文件所在路径
  • m_suffix
    • 日志文件的文件名后缀,本项目为.log
  • m_MAX_LINES
    • 一个日志文件的最大行数,超过这个数,就新建一个文件继续写日志
  • line_count
    • 记录当前日志文件写入的行数,如等于MAX_LINES,则另起一个文件
  • to_day
    • 表示当前写着的日志文件的文件名中的天数。本项目中日志文件名格式: year-month-day.log,如2022_12_31.log
  • is_open
    • 日志是否关闭
  • buf
    • 缓存区,自定义的buffer类型
  • m_level
    • 日志级别,有DEBUG、INFO、WARNING、ERROR
  • is_async
    • 日志是否为异步写入
  • fp
    • 指向当前日志写向的文件的指针
  • m_deque
    • 缓冲队列。std::unique_ptr< blockQueue< std::string > >
  • write_thread
    • 写线程。std::unique_ptr< std::thread >
  • m_mutex

成员函数

  • 构造函数

    • 初始化一些成员变量
  • 析构函数

    • flush阻塞队列,直至为空(将队列中的日志全部写到日志文件)。
    • 关闭阻塞队列
    • 等待写线程结束,join
    • close日志文件指针fp
  • init:日志初始化

    • 当传入阻塞队列容量大于0,为异步写入方式,否则为同步写入方式
    • 初始化写线程和消息阻塞队列的智能指针unique_ptr
    • 初始化日志文件后缀和日志文件目录
    • 根据当前时间(年月日)来生产即将写入的日志文件名。用到snprintf函数:C 库函数 – snprintf() | 菜鸟教程 (runoob.com)。若fp为空则先创建目录,再创建文件。
  • instance

    • 获取log类型的指针,与其他的单例模式的instance函数一样
  • flush_log_thread

    • 调用async_write函数
  • write

    • LOG_BASE宏中主要函数。将日志写入文件(根据is_async来采取同步写入或是异步写入),下面是主要流程:
    • 判断是否需要新建文件,并且更改fp指针的值,两种情况:(1)日期的day与to_day不等 ;(2)行数已满
    • 上锁,在buf上构造即将写入的一行日志的内容:时间 [日志级别] : 可变参数内容 。关于可变参数的读取:C 库宏 – va_start() | 菜鸟教程 (runoob.com)
    va_list va_l;
    va_start(va_l, format);
            vsnprintf(buf.begin_write(), buf.writable_bytes(), format, va_l);
    va_end(va_l);
    
    • 根据is_async决定是同步写入(将buf写入fp)或者是异步写入(将buf内容转为string传到阻塞队列),最后清空buf
  • flush:英文单词意思为“冲走”

    • 如果是异步写,就调用阻塞队列的flush函数,通知消费者。
  • get_level

    • 获取当前日志级别
  • set_level

    • 设置日志级别
  • is_still_open

    • 返回is_open
  • append_log_level_title

    • 根据日志级别往buf缓冲区加上title,有四种:[debug]: 、[info]: 、[warn]: 、[error]:
  • async_write

    • 异步写函数,从阻塞队列取出一个string,上锁,通过fputs函数将日志写到日志文件。while循环。

日志的相关宏的定义

#define LOG_BASE(level, format, ...) \
    do {\
        web::log* log = web::log::instance();\
        if (log->is_still_open() && log->get_level() <= level) {\
            log->write(level, format, ##__VA_ARGS__); \
            log->flush();\
        }\
    } while(0);

#define LOG_DEBUG(format, ...) do {LOG_BASE(0, format, ##__VA_ARGS__)} while(0);
#define LOG_INFO(format, ...) do {LOG_BASE(1, format, ##__VA_ARGS__)} while(0);
#define LOG_WARN(format, ...) do {LOG_BASE(2, format, ##__VA_ARGS__)} while(0);
#define LOG_ERROR(format, ...) do {LOG_BASE(3, format, ##__VA_ARGS__)} while(0);

本项目中需要日志的地方用的都是LOG_XXXX。

有关可变参数:(219条消息) #、##、__VA_ARGS__和##_VA_ARGS__的作用_侵蚀昨天的博客-CSDN博客##x-1bzbeqxybvvi9i##

日志文件内容展示

2023-01-02 18:00:53.049871 [info] : ========== Server init ==========
2023-01-02 18:00:53.049916 [info] : Port:1316, OpenLinger: false
2023-01-02 18:00:53.049973 [info] : Listen Mode: ET, OpenConn Mode: ET
2023-01-02 18:00:53.050048 [info] : LogSys level: 1
2023-01-02 18:05:44.916466 [info] : ========== Server init ==========
2023-01-02 18:05:44.916508 [info] : Port:9999, OpenLinger: false
2023-01-02 18:05:44.916515 [info] : Listen Mode: ET, OpenConn Mode: ET
2023-01-02 18:05:44.916518 [info] : LogSys level: 1
2023-01-02 18:05:44.916541 [info] : srcDir: /root/WebServer-master/bin/resources/
2023-01-02 18:05:44.916548 [info] : SqlConnPool num: 12, ThreadPool num: 6
2023-01-02 18:05:44.916589 [info] : ========== Server start ==========
2023-01-02 18:06:20.527402 [info] : Client[18](192.168.217.1:6173) in, userCount:1
2023-01-02 18:06:20.527552 [info] : Client[18] in!
2023-01-02 18:06:20.527578 [info] : Client[19](192.168.217.1:6429) in, userCount:2
2023-01-02 18:06:20.527588 [info] : Client[19] in!
2023-01-02 18:07:20.531224 [info] : Client[19] quit!
2023-01-02 18:07:20.531409 [info] : Client[19](192.168.217.1:6429) quit, UserCount:1
2023-01-02 18:07:30.534721 [info] : Client[19](192.168.217.1:40477) in, userCount:2
2023-01-02 18:08:32.206878 [info] : ========== Server init ==========
2023-01-02 18:08:32.206910 [info] : Port:1316, OpenLinger: false
2023-01-02 18:08:32.206925 [info] : Listen Mode: ET, OpenConn Mode: ET
2023-01-02 18:08:32.206928 [info] : LogSys level: 1
2023-01-02 18:08:32.206931 [info] : srcDir: /root/WebServer-master/bin/resources/
2023-01-02 18:08:32.206936 [info] : SqlConnPool num: 12, ThreadPool num: 6
2023-01-02 18:08:32.206938 [info] : ========== Server start ==========
2023-01-02 18:08:53.933861 [info] : Client[18](192.168.217.1:10782) in, userCount:1
2023-01-02 18:08:53.934192 [info] : Client[18] in!
2023-01-02 18:08:53.934237 [info] : Client[19](192.168.217.1:11038) in, userCount:2
2023-01-02 18:08:53.934271 [info] : Client[19] in!
2023-01-02 18:09:53.936395 [info] : Client[19] quit!
2023-01-02 18:09:53.936575 [info] : Client[19](192.168.217.1:11038) quit, UserCount:1
2023-01-02 18:09:57.645446 [info] : Client[19](192.168.217.1:56094) in, userCount:2

posted @ 2023-01-08 11:38  DavidJIAN  阅读(26)  评论(0)    收藏  举报