C++中集成spdlog实现高性能异步日志需正确引入header-only库、初始化线程池(如spdlog::init_thread_pool(8192, 1))、配置轮转文件sink、注册async_logger,并注意字符串生命周期与shutdown时机。

在 C++ 项目中集成 spdlog 实现高性能异步日志记录,核心在于正确引入库、配置异步模式、避免线程竞争,并兼顾日志轮转与性能开销。它本身不依赖第三方构建系统,轻量且开箱即用。
使用 header-only 方式快速集成 spdlog
spdlog 支持 header-only 使用,适合中小型项目快速上手:
- 从 GitHub 官方仓库 下载最新 release 的
include/spdlog目录 - 将该目录整体复制到项目中的
third_party/spdlog或类似路径 - 确保编译器包含路径(
-I)指向该目录,例如:-I./third_party/spdlog - 在源文件中直接 include:
#include "spdlog/async_logger.h"和#include "spdlog/sinks/rotating_file_sink.h"
初始化全局异步日志器并设置线程安全策略
异步日志通过内部线程池处理日志写入,避免阻塞主线程。需显式初始化线程池并注册 logger:
- 调用
spdlog::init_thread_pool(8192, 1):队列容量 8192,工作线程数建议设为 1(多数场景下单线程足够,避免上下文切换开销) - 创建 rotating file sink(支持按大小轮转):
auto rotating_sink = std::make_shared<:sinks::rotating_file_sink_mt>("app.log", 1024 * 1024 * 5, 3);(单文件上限 5MB,最多保留 3 个历史文件) - 构造 async_logger:
auto logger = std::make_shared<:async_logger>("app", rotating_sink, spdlog::thread_pool()); - 注册为默认 logger:
spdlog::register_logger(logger); spdlog::set_default_logger(logger);
规范日志调用方式以保障异步性能
异步 logger 对调用方式敏感,不当用法会退化为同步行为或引发崩溃:
Easily find JSON paths within JSON objects using our intuitive Json Path Finder
立即学习“C++免费学习笔记(深入)”;
- 避免传递局部变量地址或未持久化字符串(如
std::string临时对象),应使用std::string_view或已拷贝的字符串 - 推荐格式化方式:
logger->info("User {} logged in at {}", user_id, timestamp);(spdlog 内部延迟格式化,线程安全) - 禁止在析构函数、信号处理函数、静态对象初始化中调用日志;确保 logger 生命周期长于所有日志调用点
- 如需立即刷盘(如程序退出前),调用
spdlog::shutdown();—— 它会等待队列清空并安全关闭线程池
进阶:自定义格式与多 sink 输出
可通过组合多个 sink 实现控制台 + 文件双输出,并统一格式:
- 创建 console sink:
auto console_sink = std::make_shared<:sinks::stdout_color_sink_mt>(); - 设置格式:
console_sink->set_pattern("[%Y-%m-%d %H:%M:%S.%e] [%n] [%^%l%$] %v"); - 合并 sink 到 async logger:
std::vector<:sink_ptr> sinks{rotating_sink, console_sink}; auto logger = std::make_shared<:async_logger>("multi", begin(sinks), end(sinks), spdlog::thread_pool()); - 注意:多个 sink 共享同一 thread pool,无需重复 init
不复杂但容易忽略的是 shutdown 时机和字符串生命周期管理。只要保证 logger 初始化早于任何日志调用、销毁晚于最后一条日志,再配合合理轮转与线程池配置,就能稳定支撑每秒数万条日志的异步写入需求。










