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

浙公网安备 33010602011771号