高性能C++ 日志实战:spdlog 核心架构解析与最佳实践指南
一、spdlog 介绍
spdlog 是一个高性能、超快速、零配置的 C++ 日志库,它旨在提供简洁的 API 和丰富的功能,同时保持高性能的日志记录。它支持多种输出目标、格式化选项、线程安全以及异步日志记录。
特点:
- 高性能: spdlog 专为速度而设计,即使在高负载情况下也能保持良好的性能。
- 零配置: 无需复杂的配置,只需包含头文件即可在项目中使用。
- 异步日志: 支持异步日志记录,减少对主线程的影响。
- 格式化: 支持自定义日志消息的格式化,包括时间戳、线程 ID、日志级别等。
- 多平台: 跨平台兼容,支持 Windows、Linux、macOS 等操作系统。
- 丰富的 API: 提供丰富的日志级别和操作符重载,方便记录各种类型的日志。
二、spdlog 安装
1. 直接命令安装(适用于 Ubuntu/Debian 系统)
(1)步骤:
|
1 2 |
|
(2)特点:
- 简单快捷: 适合快速部署,无需手动编译。
- 版本受限: 依赖系统仓库的版本,可能非最新(如 Ubuntu 20.04 默认版本较旧)。
(3)验证安装:
- 检查头文件: ls /usr/include/spdlog/
- 检查库文件: ls /usr/lib/x86_64-linux-gnu/libspdlog*

2. 源码编译安装
|
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
三、spdlog 的重要组成结构
1. 日志输出等级枚举
- 日志输出等级枚举:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
在 spdlog/include/spdlog/common.h 头文件中,其宏定义如下:
#define SPDLOG_LEVEL_TRACE 0
#define SPDLOG_LEVEL_DEBUG 1
#define SPDLOG_LEVEL_INFO 2
#define SPDLOG_LEVEL_WARN 3
#define SPDLOG_LEVEL_ERROR 4
#define SPDLOG_LEVEL_CRITICAL 5
#define SPDLOG_LEVEL_OFF 6
2. (同步)日志记录器类(含 自定义日志输出格式 接口的使用介绍 )
- (同步)日志记录器类:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
|
- logger类内,set_pattern接口的使用:
假设Log 是logger类对象的智能指针
|
1 2 3 4 5 6 7 8 9 10 11 |
|
3. 线程池类(含 单例模式管理全局线程池实例 的介绍 )
- spdlog中只有一种线程池实现,即spdlog::details::thread_pool类
|
1 2 3 4 5 6 7 8 9 10 11 |
|
- 单例模式的实现
通过registry类(单例)持有 全局线程池实例:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
|
- 通过spdlog库中的 spdlog::init_thread_pool() 和 spdlog::thread_pool() 函数 来使用 registry类(单例)持有的 全局线程池实例
|
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
- 注意: spdlog::init_thread_pool() 重置全局线程池时,如果 static registry s_instance(registry类单例,静态对象)的 _tp已经指向了一个线程池实例,_tp会销毁指向的线程池实例,然后指向新创建的线程池实例

4. 异步日志记录器类(与 日志记录器类 对比)
- async_logger 是异步日志的核心实现类,继承自 logger 基类。它通过线程池和任务队列实现异步日志记录:
|
1 2 3 4 5 6 7 8 9 |
|
| 类型 | 日志写入流程 | 线程模型 |
|---|---|---|
| (同步)日志记录器 | 主线程直接调用I/O操作(如文件写入、控制台输出) • 日志生成 → 立即执行磁盘/网络I/O → 主线程阻塞等待完成 | 单线程模型:日志I/O占用主线程时间片 |
| 异步日志记录器 | 主线程将日志存入内存队列(任务队列) • 日志生成 → 存入队列 → 立即返回主线程 • 后台线程池消费队列并执行I/O | 生产者-消费者模型:主线程与I/O线程分离 |
关键区别:异步日志通过内存队列缓冲和线程池异步刷盘,避免主线程因I/O等待被阻塞
5. 日志记录器工厂类
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
|
日志记录器工厂类:封装了 日志记录器类对象 的构建 和 配置过程
有了日志记录器工厂类,我们不需要关心 日志记录器类对象 的构建 和 配置过程,可以通过API接口一键构造 日志记录器类对象
spdlog::basic_logger_mt()接口 的 第三个参数 truncate 的功能:
| 值 | 行为 | 适用场景 |
|---|---|---|
| true | 若日志文件已存在,清空文件内容,从头开始写入新日志。 | 需要覆盖旧日志的场景(如临时调试) |
| false (默认) | 若日志文件已存在,追加新日志到文件末尾;若文件不存在则创建新文件。 | 长期运行的程序需保留历史日志的场景 |
- 创建 同步日志记录器对象
采用默认工厂,创建的都是 同步日志记录器对象
(1)创建 向标准输出写入日志 的同步日志记录器对象
|
1 2 3 |
|
(2)创建 向指定文件写入日志 的同步日志记录器对象
|
1 2 3 |
|
- 创建 异步日志记录器对象
要创建异步日志记录器对象,需要显式指定 工厂类型(spdlog::async_factory)
(1)创建 向标准输出写入日志 的异步日志记录器对象
|
1 |
|
(2)创建 向指定文件写入日志 的异步日志记录器对象
|
1 |
|
6. 全局接口
|
1 2 3 4 5 6 7 8 9 10 |
|
注:全局配置的 优先级低于 日志记录器对象的专属配置!
spdlog 采用作用域逐级覆盖的配置策略:
- 全局配置(spdlog::set_level()、spdlog::flush_on()、spdlog::set_pattern())
影响所有未单独配置的日志记录器,作为默认值存在。
- 日志记录器专属配置 (logger->set_level()、logger->flush_on()、logger->set_pattern())
每个日志器对象独立配置,优先级高于全局配置。
四、spdlog 的使用
1. 通过全局接口配置,创建同步日志器 (向标准输出写日志)
要使用spdlog库,在你的 C++ 源文件中必须包含 spdlog 的头文件:
|
1 |
|
- 通过全局接口配置,创建同步日志器 (向标准输出写日志)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
|
注:spdlog库依赖 fmt库,所以链接时,还需要显式指定fmt库


2. 创建同步日志器 (向指定文件写日志),并使用同步日志器的专用配置接口
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
|


3. 创建异步日志器 (向指定文件写日志)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
|

到此这篇关于高性能C++ 日志实战:spdlog 核心架构解析与最佳实践指南的文章就介绍到这了
openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构
更多推荐


所有评论(0)