博主最近在实习,对于日志,应该是每个项目不可缺少的环节,虽然有很多封装好的日志接口可以使用,但是最近主播想重新回顾之前学习过的muduo网络库,并简单写一个网络库,因此我们从日志模块开始讲解。
github链接:wangt610/muduo-internet: muduo网络库的仿写
https://github.com/wangt610/muduo-internet
这个日志模块是C++ 高性能网络库 muduo 的精简实现,核心目标:线程安全、高性能、零拷贝、支持日志分级、自动打印时间戳 / 文件名 / 行号。
我会按文件功能 → 核心代码 → 运行原理一步步拆解,你可以直接对照源码看。
整套日志系统分为七大核心模块:
-
Timestamp 高精度时间戳模块
-
LogLevel 日志等级过滤模块
-
LogMessage 日志消息结构体模块
-
日志流式拼接操作模块
-
多类型日志写入模块(控制台/文件/滚动日志)
-
日志刷盘持久化模块
-
异步无阻塞刷盘模块(核心高性能)
一、Timestamp 高精度时间戳模块
1. 模块作用
为每一条日志生成唯一、高精度、可格式化的时间标识,是日志排序、线上问题定位、性能复盘的核心依据。
区别于普通时间获取,该模块专为高并发日志优化,兼顾精度 与性能。
2. 核心设计思路
-
存储优化 :不直接存储字符串时间,而是用
int64_t存储微秒级时间戳(1970年至今的微秒数),内存占用小、运算速度快,避免频繁字符串拼接开销。 -
高精度采集 :基于Linux系统调用
gettimeofday(),精度可达微秒级,远超秒级、毫秒级普通日志。 -
延迟格式化 :仅在日志最终输出时,才将时间戳整数格式化为
年-月-日 时:分:秒.微秒字符串,极大提升高并发写入性能。
3. 代码对应文件
Timestamp.hpp、Timestamp.cpp
4. 核心能力
统一输出规范时间格式,作为每条日志的首部固定字段,保证日志时序绝对准确。
二、LogLevel 日志等级过滤模块
1. 模块作用
对日志进行分级管控、动态过滤,区分日志重要程度,适配开发、测试、生产不同环境。
核心价值:屏蔽无效日志,减少IO压力,提升服务性能。
2. 等级规范(优先级递增)
DEBUG < INFO < WARN < ERROR < FATAL
-
DEBUG:调试日志,仅开发环境开启,用于代码逻辑排查
-
INFO:正常业务流程日志,记录服务正常运行状态
-
WARN:警告日志,非致命异常,不影响服务运行
-
ERROR:业务错误日志,接口、逻辑执行失败
-
FATAL:致命错误,服务无法继续运行,触发程序终止
3. 核心设计思路
-
通过枚举
enum LogLevel定义等级,语义清晰、比对高效 -
设置全局静态日志阈值,程序运行中可动态修改
-
日志写入前先做等级判断:低于阈值的日志直接丢弃,不执行任何拼接、IO操作
4. 代码对应文件
LogLevel.hpp
三、LogMessage 日志消息组成模块
1. 模块作用
定义一条标准日志的完整数据结构 ,封装所有日志元数据与业务内容,是日志系统的数据载体核心。
2. 完整日志组成字段
工业级标准日志 = 6大核心字段,缺一不可,精准定位问题:
-
高精度时间戳:记录日志生成时刻
-
日志等级:区分日志严重程度
-
线程ID:定位多线程并发问题
-
源文件名+行号:精准定位代码报错位置
-
自定义日志内容:业务自定义输出信息
-
日志标识字符串:标准化展示等级标签([INFO]/[ERROR])
3. 标准日志输出示例
2026-05-24 14:20:30.123456 [INFO] Thread-1 main.cpp:88 - 服务器监听端口8080成功
4. 核心设计思路
每条日志对应一个独立 LogMessage 对象,构造时自动采集时间、文件、行号、等级信息,无需用户手动传入,开箱即用。
5. 代码对应文件
LogMessage.hpp
四、日志流式操作模块
1. 模块作用
实现极简、优雅、通用的日志写入语法,支持C++流式链式拼接,兼容所有基础数据类型与自定义类型。
2. 使用效果
LOG_INFO << "服务启动成功,端口:" << port << " 最大连接数:" << max_conn;
3. 核心设计原理(Muduo经典核心)
-
基于
std::stringstream构建内存缓冲区,承接所有流式写入数据 -
利用C++临时对象生命周期机制:
-
代码行执行时,临时
Logger对象创建 -
通过
<<运算符拼接所有日志内容到内存流 -
代码行结束,临时对象自动析构,析构函数统一完成日志格式化与输出
-
-
通过宏封装
__FILE__、__LINE__编译器内置宏,自动获取文件、行号
4. 核心优势
语法统一、零冗余代码、类型自动适配,彻底摒弃 printf 繁琐的格式符写法,安全性更高。
5. 代码对应文件
Logger.hpp、Logger.cpp
五、多类型日志写入模块
1. 模块作用
适配不同业务场景,提供多样化日志输出渠道,支持灵活扩展,满足开发调试与线上部署双重需求。
2. 支持的写入类型
-
标准控制台输出:开发调试阶段,日志直接打印终端
-
普通文本文件输出:基础文件落盘,统一存储所有日志
-
滚动日志文件:按时间/文件大小自动切分日志,避免单文件过大
-
错误流输出:ERROR/FATAL日志单独输出到stderr,区分普通日志
3. 设计思路
采用接口化、可扩展设计,统一日志输出入口,底层可动态切换输出方式,无需修改上层业务日志代码。线上环境自动开启文件落盘,开发环境默认控制台输出。
六、日志文件刷盘持久化模块
1. 模块作用
解决日志内存缓存丢失问题,将内核缓冲区、用户缓冲区的日志数据,持久化写入物理磁盘,保证服务崩溃、断电场景下日志不丢失。
2. 核心刷盘策略(平衡性能与安全性)
-
定时刷盘:后台线程固定间隔(1s/5s)主动刷盘,避免数据长期滞留内存
-
阈值刷盘:缓冲区数据达到设定大小,自动触发落盘
-
强制刷盘:遇到ERROR/FATAL致命日志,立即调用系统调用强制落盘,优先保证错误日志留存
3. 底层系统调用
-
fwrite:数据写入内核缓冲区 -
fflush:刷新用户态缓冲区到内核态 -
fsync:强制内核缓冲区数据落地磁盘(最高安全级别)
七、异步刷盘模块(核心高性能)
1. 模块作用
解决服务器最大痛点:磁盘IO阻塞主线程。
磁盘读写是慢速IO操作,同步写日志会严重阻塞业务主线程,降低服务并发能力。异步模块实现业务线程无阻塞写日志。
2. 核心实现方案:双缓冲机制(Muduo精髓)
设计两块独立内存缓冲区(A/B缓冲区),分工协作:
-
业务主线程 :只负责向当前活跃缓冲区写入日志,纯内存操作,无IO阻塞
-
缓冲区切换:当活跃缓冲区写满/到达定时时间,瞬间交换A、B缓冲区指针
-
后台落盘线程:负责将交换后的满缓冲区数据,异步写入磁盘
-
循环复用:落盘完成的缓冲区重新空闲,等待下一次写入
3. 核心优势
-
零阻塞:主线程无任何磁盘IO操作,并发性能拉满
-
低锁开销:双缓冲设计极大减少线程锁竞争
-
批量落盘:单次IO写入大量日志,减少系统调用次数,提升IO效率
4. 适用场景
高并发网关、TCP服务器、后端微服务等对延迟、吞吐要求极高的场景。