资讯动态

C++日志库spdlog实战:集成、异步日志与滚动文件配置详解

发布时间:2026/8/30 12:50:29 来源:尧图企业网站定制
C 项目里打日志是一件看起来简单、铺开就乱的事情。早期方案无非是printf加一个文件重定向或者自己封装一个fprintf轮子再往后可能换到 log4cxx、glog 这些老牌库。但要么跨平台麻烦要么编译依赖重要么接口不顺手。很多项目做到中途日志系统反而成了最不想动、又最需要维护的部分。如果你也在 C 项目里折腾过日志多半能理解这种处境。spdlog 是目前 C 社区里最值得优先考虑的日志库之一。它的核心优势不是“功能多”这么简单而是把日志记录这件事的工程成本压得很低头部模式header-only可以直接塞进现有项目编译快依赖简单默认就带异步日志、滚动文件、格式化、按天切分这些生产环境必需的机制。而且它的 API 非常直观基本上一行代码就能开始打日志。这篇文章我会从实际使用的角度讲清楚 spdlog 的引入、配置、常见用法和容易踩坑的地方重点覆盖四个方面第一它的核心概念和设计思路第二如何下载、集成到一个 C 工程里第三从基础日志到异步日志、滚动文件日志、MFC 项目集成这些完整示例第四生产环境使用时的排查方法和最佳实践。如果你正准备给 C 项目引入日志库或者已经在用 spdlog 但想进一步用好它这篇文章可以直接参考操作。1. spdlog 真正解决了什么问题先说一个很典型的开发场景。项目早期你可能用printf配合fprintf(stderr, ...)看输出程序跑起来就算完事。等模块多了、项目进入联调阶段问题开始出现多线程打印内容交错不同模块的输出混在一起无法按级别过滤线上环境不能看终端只能写文件但文件无法自动切分跑一天就几个 GB定位问题的时候日志里没有时间、线程号、源码位置根本没法追踪调用链。这些问题的本质是打日志本身不难难的是日志系统的“可用性”。一个可用的日志系统至少要解决四个问题线程安全。多线程环境不能出现内容错乱。格式化能力。要能方便地输出变量、容器、自定义类型。输出路由。内存、终端、文件、远程日志可以灵活切换。性能。日志写入不能拖垮业务逻辑。spdlog 正是围绕这些问题设计的。它内部使用锁和异步队列来保证线程安全支持格式化输出语法通过 sink输出目标机制把“日志内容”和“输出到哪里”解耦异步模式下日志写入和业务线程分离调用方几乎无感知。更关键的是它的默认配置已经覆盖了大多数项目的基本需求真正做到了“开箱即用”。从技术成本角度看spdlog 替代的不只是printf加文件流而是整个自研日志模块的开发量。它默认依赖只有一个 fmt 库实际上 1.x 版本已经内置 fmt 支持可以以纯头文件方式使用也可以编译成静态库/动态库接入。这种设计让它在 CMake、vcpkg、conan、MFC、Qt 项目里都能顺利落地。2. spdlog 的核心概念与设计原理要真正用好 spdlog需要先理解它的三个核心概念logger日志器、sink输出目标、pattern输出格式。2.1 Logger日志记录的门面Logger 是你在代码里直接操作的对象。它负责三件事接收日志内容、判断当前日志级别是否需要输出、把日志内容交给一个或多个 sink。spdlog 提供了两种使用方式全局静态函数例如spdlog::info(...)。底层使用一个默认的 logger 实例适合快速使用和轻量项目。命名 logger例如spdlog::get(my_logger)。可以创建多个 logger按模块或业务维度区分写不同的日志文件、使用不同的级别配置。第二种方式更适合中大型项目因为不同模块可以独立控制日志输出避免全部日志混在一个文件里。2.2 Sink输出目标Sink 是 spdlog 里最值得理解的设计。它把“记录日志”和“输出日志”彻底解耦。常用的 sink 有Sink用途stdout_sink / stderr_sink输出到控制台stdout_color_sink带颜色的控制台输出basic_file_sink输出到单个文件rotating_file_sink按文件大小滚动切分daily_file_sink按日期切分msvc_sink输出到 Visual Studio 输出窗口syslog_sink / tcp_sink系统日志或网络传输一个 logger 可以同时挂多个 sink。例如开发阶段控制台看日志、文件留记录生产环境只留文件并且按大小滚动。2.3 Pattern日志格式模板Pattern 决定了每条日志长什么样。spdlog 使用类似 C 风格占位符的格式串常用的占位符包括占位符含义%Y-%m-%d %H:%M:%S时间%e毫秒%l日志级别%t线程 ID%s源码文件名%#源码行号%v日志正文例如[%Y-%m-%d %H:%M:%S.%e] [%l] [thread %t] [%s:%#] %v可以输出成下面这种格式[2025-01-08 14:23:55.123] [info] [thread 3021] [main.cpp:15] application started这种格式在排查问题时非常有用因为可以快速定位日志来自哪个文件哪一行以及是哪个线程打出来的。2.4 异步机制为什么不卡业务线程spdlog 的异步模式值得单独提。异步 logger 内部维护一个线程池和一个消息队列。业务线程调用logger-info(...)时只是把日志内容格式化并塞进队列真正的文件写入由后台线程完成。这样日志写入不会阻塞业务逻辑在高频日志场景下性能提升明显。这里需要区分一个容易误解的点异步不是“默认开启”的。直接使用spdlog::info时是同步模式日志内容在调用线程内完成格式化并写入 sink。只有使用spdlog::create_async或者spdlog::async_logger相关接口时才会走线程池队列。理解了这个设计后续在配置异步日志时就不会犯“以为设了队列就是异步”的错误。3. spdlog 下载与环境准备spdlog 的官方仓库在 GitHub 的gabime/spdlog。下载方式可以按项目和团队习惯任选一种。3.1 直接下载源码从 GitHub Releases 页面下载最新源码包解压后把include目录加入项目的头文件搜索路径即可。这是最快的接入方式适合小型项目或者临时验证。官方仓库链接https://github.com/gabime/spdlog3.2 使用 CMake FetchContent在实际工程中更推荐使用 CMake 的 FetchContent 或者 Git 子模块的方式来管理。使用 Git 子模块git submodule add https://github.com/gabime/spdlog.git third_party/spdlog在 CMakeLists.txt 里添加子目录add_subdirectory(third_party/spdlog) target_link_libraries(your_target PRIVATE spdlog::spdlog)或者用 FetchContent 自动下载include(FetchContent) FetchContent_Declare( spdlog GIT_REPOSITORY https://github.com/gabime/spdlog.git GIT_TAG v1.x # 以实际版本标签为准 ) FetchContent_MakeAvailable(spdlog) target_link_libraries(your_target PRIVATE spdlog::spdlog)3.3 使用 vcpkg 或 conan如果你的项目已经使用了 vcpkg 或 conan可以直接安装vcpkg install spdlogconan install spdlog/1.x这里有一个容易踩的坑vcpkg 默认安装的是编译好的静态库/动态库形式而 spdlog 本身还支持 header-only 模式。两种模式的宏定义不同混用会出现链接错误下面第 8 节会详细说。3.4 环境要求spdlog 对 C 标准的要求是 C11 以上但这个“以上”很宽松。实际项目建议至少使用 C11如果条件允许直接用 C17 会让fmt格式化能力更完整。它支持 Windows、Linux、macOS也支持 MinGW、MSVC、GCC、Clang 等主流编译器。不依赖额外的大型第三方库这是它能快速接入各类项目的重要原因。4. 第一个 spdlog 示例快速跑通先用最小代码体验一下 spdlog 的基本使用。假设你已经把include目录配置好了。创建一个main.cpp// 文件路径src/main.cpp #include spdlog/spdlog.h int main() { // 使用全局默认 logger spdlog::info(Welcome to spdlog!); spdlog::warn(This is a warning, value {}, 42); spdlog::error(An error occurred, code {}, -1); // 设置默认 logger 的输出格式 spdlog::set_pattern([%Y-%m-%d %H:%M:%S.%e] [%l] [%t] %v); // 设置最低日志级别默认是 info spdlog::set_level(spdlog::level::debug); spdlog::debug(Debug-level message); return 0; }编译运行。如果你使用 Linux 或 macOSg src/main.cpp -I/path/to/spdlog/include -stdc17 -pthread -o demo ./demo预期输出类似[2025-01-08 14:23:55.123] [info] Welcome to spdlog! [2025-01-08 14:23:55.124] [warning] This is a warning, value 42 [2025-01-08 14:23:55.124] [error] An error occurred, code -1 [2025-01-08 14:23:55.125] [debug] Debug-level message这段代码虽然简单但已经展示了 spdlog 的几个核心能力{}占位符格式化、全局默认 logger、级别控制、格式设置。{}是 spdlog 基于 fmt 的格式化语法比printf的%d、%s安全编译器会检查参数类型支持自定义类型格式化这也是很多 C 开发者从printf迁徙过来的主要原因之一。5. 核心功能详解sink、级别、格式化与日志刷新第一段代码跑通后再看 spdlog 的常用功能配置这些才是实际项目中真正需要的。5.1 创建文件日志开发阶段控制台日志够用但生产环境必须落盘。创建一个简单的文件日志// 文件路径src/file_logger_demo.cpp #include spdlog/spdlog.h #include spdlog/sinks/basic_file_sink.h int main() { // 创建名为 file_logger 的日志器写入日志文件 auto logger spdlog::basic_logger_mt(file_logger, logs/demo.log); logger-info(This is a file log, user_id {}, 10001); logger-warn(Disk space is low, remaining {} MB, 256); // 程序退出前刷新并关闭日志 spdlog::shutdown(); return 0; }这里值得解释的是basic_logger_mt。mt表示 multi-threads即线程安全的日志器适用于多线程程序。spdlog 还提供了basic_logger_st其中的st表示 single-thread单线程场景下性能更好但多线程使用不安全。默认情况下文件日志器不会自动刷新到磁盘需要手动设置刷新策略。5.2 日志级别与刷新策略spdlog 的日志级别从低到高分别是级别说明trace最详细的调试信息debug调试信息info普通信息warn警告err / error错误critical严重错误设置级别有两个方向一个是 logger 的级别决定哪些日志会被输出另一个是 flush 级别决定哪些级别的日志会立即刷新到磁盘。// 只有高于等于 warn 的日志才会输出 logger-set_level(spdlog::level::warn); // 当出现 warn 及以上级别日志时立即刷新到磁盘防止程序崩溃丢日志 logger-flush_on(spdlog::level::warn); // 每 3 秒自动刷新一次 spdlog::flush_every(std::chrono::seconds(3));这些配置在生产环境中很关键。如果不设置刷新策略程序异常退出时最后的日志可能还停留在缓冲区里丢失排障信息。但如果每条日志都强制刷新性能又会明显下降。正确做法是正常级别按时间或大小批量刷新错误级别即时刷新。5.3 Pattern 格式化完整示例一个更完整的格式化配置// 文件路径src/pattern_demo.cpp #include spdlog/spdlog.h #include spdlog/sinks/basic_file_sink.h int main() { auto logger spdlog::basic_logger_mt(pattern_logger, logs/pattern.log); // 输出文件名、行号、线程号方便定位问题 logger-set_pattern([%Y-%m-%d %H:%M:%S.%e] [%l] [thread %t] [%s:%#] %v); logger-info(order created, order_id {}, 20250108001); spdlog::shutdown(); return 0; }输出结果会包含源码文件名和行号。注意%s和%#依赖编译器预处理宏__FILE__和__LINE__debug 和 release 下都会生效不会影响性能。许多项目最后还会定义一个全局宏统一管理 logger 引用和格式比如// 文件路径src/log_util.h #pragma once #include spdlog/spdlog.h #include spdlog/sinks/basic_file_sink.h #define LOG_INFO(...) SPDLOG_LOGGER_INFO(spdlog::get(app), __VA_ARGS__) #define LOG_WARN(...) SPDLOG_LOGGER_WARN(spdlog::get(app), __VA_ARGS__) #define LOG_ERROR(...) SPDLOG_LOGGER_ERROR(spdlog::get(app), __VA_ARGS__)这种宏定义方式一方面不用每次写spdlog::get(app)另一方面也保留了对默认 logger 或命名 logger 的灵活性。5.4 多个 Sink 组合实际项目中经常需要“控制台 文件”同时输出。spdlog 支持把一个 logger 挂多个 sink// 文件路径src/multi_sink_demo.cpp #include spdlog/spdlog.h #include spdlog/sinks/stdout_color_sinks.h #include spdlog/sinks/rotating_file_sink.h int main() { auto console_sink std::make_sharedspdlog::sinks::stdout_color_sink_mt(); console_sink-set_level(spdlog::level::debug); auto file_sink std::make_sharedspdlog::sinks::rotating_file_sink_mt( logs/multi.log, 1024 * 1024 * 5, 3 ); file_sink-set_level(spdlog::level::info); auto logger std::make_sharedspdlog::logger(multi_logger, spdlog::sinks_init_list{console_sink, file_sink}); logger-set_level(spdlog::level::debug); logger-info(console and file logger work together); spdlog::register_logger(logger); spdlog::shutdown(); return 0; }这里rotating_file_sink_mt的参数含义是文件路径、单文件最大大小5 MB、保留文件数量3 个。当文件超过 5 MB 时自动滚动成multi.1.log、multi.2.log最多保留 3 个滚动文件。这个机制在生产环境中非常重要避免单个日志文件无限增长撑爆磁盘。6. 异步日志与滚动文件实战生产环境里日志写入频率可能很高尤其是网络服务、游戏服务器这类程序。如果同步写文件业务线程会被文件 I/O 卡住。spdlog 的异步模式就是为了解决这个问题。6.1 异步日志基础使用异步日志需要先初始化线程池然后创建异步 logger。// 文件路径src/async_demo.cpp #include spdlog/spdlog.h #include spdlog/async.h #include spdlog/sinks/rotating_file_sink.h int main() { // 初始化线程池队列大小 8192后台线程数 1 spdlog::init_thread_pool(8192, 1); auto logger spdlog::create_asyncspdlog::sinks::rotating_file_sink_mt( async_logger, logs/async.log, 1024 * 1024 * 10, // 单文件 10 MB 5 // 保留 5 个滚动文件 ); logger-set_pattern([%Y-%m-%d %H:%M:%S.%e] [%l] [thread %t] %v); for (int i 0; i 1000; i) { logger-info(async log message, index {}, i); } spdlog::shutdown(); return 0; }init_thread_pool(8192, 1)中的 8192 是消息队列容量1 是后台写入线程数。当业务线程产生日志的速度超过后台写入速度时日志消息会堆积在队列里。队列满时spdlog 有两种处理策略默认是丢弃新日志另一种是阻塞调用线程直到队列有空间。6.2 异步溢出策略如果队列满默认行为是阻塞还是丢弃spdlog 默认使用async_overflow_policy::block也就是队列满时会阻塞调用线程保证日志不丢失。可以通过下面的方式设置为丢弃新消息#include spdlog/async.h #include spdlog/sinks/stdout_color_sinks.h // 使用丢弃策略创建异步 logger auto logger spdlog::create_asyncspdlog::sinks::stdout_color_sink_mt( async_drop_logger, spdlog::async_overflow_policy::overrun_oldest );overrun_oldest表示队列满时覆盖最早的日志适合“只要最新日志不想要旧日志”的监控场景。而如果业务日志非常重要建议保持默认的block策略虽然会带来一定阻塞但日志不会丢。6.3 按天切分日志有些业务日志更适合按日期归档比如每天一个文件保留最近 30 天。spdlog 提供了daily_file_sink// 文件路径src/daily_demo.cpp #include spdlog/spdlog.h #include spdlog/sinks/daily_file_sink.h int main() { // 每天 0 点整切分分钟和小时决定切分时刻保留 30 个历史文件 auto logger spdlog::daily_logger_mt(daily_logger, logs/daily.log, 0, 0, false, 30); logger-info(today log content); spdlog::shutdown(); return 0; }daily_logger_mt的参数分别是logger 名称、日志文件路径、切分时间小时、分钟、是否在启动时截断旧文件、最大文件数量。日志文件会以daily_2025-01-08.log这样的形式命名。这里提醒一点daily_file_sink只能按自然时间切分不能按文件大小切分。如果你需要“既按时间又按大小”有daily_file_sink和rotating_file_sink结合的自定义方案也可以在代码中组合多个 sink或者使用spdlog::sinks::daily_file_sink的自定义文件命名规则。7. MFC / Windows 项目集成技巧搜索“mfc使用 spdlog例子代码”的人很多因为 MFC 项目接入第三方库时坑往往不在库本身而在项目配置和字符处理上。这里单独讲一下 MFC 集成 spdlog 的完整思路。7.1 在 MFC 项目中添加 spdlog如果你用 Visual Studio 开发 MFC 项目最简单的方式是使用 vcpkgvcpkg install spdlog:x86-windows然后在 VS 的“项目属性 - C/C - 常规 - 附加包含目录”中添加 vcpkg 对应的 include 路径或者直接使用 vcpkg 的集成命令vcpkg integrate install如果不使用 vcpkg也可以直接把 spdlog 源码的include目录复制到项目里然后配置好头文件路径。在 MFC 项目中一个常见的需求是让日志同时输出到文件和控制台窗口。对 MFC 这种 GUI 程序来说控制台窗口不是默认存在的可以在InitInstance里分配一个控制台或者直接只写文件调试阶段再用OutputDebugString在 VS 输出窗口查日志。7.2 在 MFC 应用启动时初始化日志下面这段代码演示了在 MFC 的CMyApp::InitInstance中初始化一个文件日志并设置常用的格式// 文件路径MyApp.cpp #include spdlog/spdlog.h #include spdlog/sinks/rotating_file_sink.h #include spdlog/sinks/msvc_sink.h BOOL CMyApp::InitInstance() { // 创建文件 sink按大小滚动 auto file_sink std::make_sharedspdlog::sinks::rotating_file_sink_mt( logs/app.log, 1024 * 1024 * 5, 3 ); // 创建 VS 输出窗口 sink方便调试 auto msvc_sink std::make_sharedspdlog::sinks::msvc_sink_mt(); auto logger std::make_sharedspdlog::logger( mfc_app, spdlog::sinks_init_list{file_sink, msvc_sink} ); logger-set_level(spdlog::level::debug); logger-set_pattern([%Y-%m-%d %H:%M:%S.%e] [%l] [%s:%#] %v); logger-flush_on(spdlog::level::err); spdlog::register_logger(logger); spdlog::set_default_logger(logger); logger-info(MFC application started); // ... 其他初始化 ... return TRUE; }使用msvc_sink是个很实用的技巧。调试时日志会输出到 Visual Studio 的“输出”窗口点开日志能看到源码文件和行号排查问题比看弹窗提示高效得多。7.3 MFC 中 CString 与 spdlog 的格式化MFC 里到处是CString。直接向 spdlog 传入CString会失败因为 spdlog 的格式化器不认识CString类型。处理方式是在传参前转换成std::string或std::wstring。// 文件路径StringConvert.h #pragma once #include atlstr.h #include string // CString 转 UTF-8 std::string inline std::string CStringToUtf8(const CString str) { if (str.IsEmpty()) { return std::string(); } int len ::WideCharToMultiByte( CP_UTF8, 0, str.GetString(), str.GetLength(), nullptr, 0, nullptr, nullptr ); std::string result(len, 0); ::WideCharToMultiByte( CP_UTF8, 0, str.GetString(), str.GetLength(), result[0], len, nullptr, nullptr ); return result; }使用的时候CString userName L张三; logger-info(user login, name {}, CStringToUtf8(userName));这里要注意编码问题。MFC 项目默认可能是 Unicode 字符集CString底层是宽字符。CStringToUtf8转成 UTF-8 后写入日志文件时可读性最好。如果不做转换直接传CString不但编译不过还会因为字符编码问题产生乱码。7.4 MFC 项目中的运行时库匹配MFC 项目在 Windows 上有一个隐蔽的坑就是运行时库设置。spdlog 在 Windows 上写文件使用标准 C 文件流理论上运行时库要和张模式匹配。如果项目用的/MT静态运行时而 spdlog 编译时使用了/MD动态运行时链接会报 LNK2038 或 LNK2005 之类的错误。解决思路是保持整个项目运行时库一致。通常把 MFC 项目和 spdlog 的“代码生成 - 运行库”设成相同选项或者干脆直接用 header-only 模式让编译器按项目设置来编译 spdlog 的模板代码。这也是 spdlog 在 Windows 上比较推荐 header-only 模式的原因之一。8. spdlog 常见问题与排查方法日志库的问题通常不像业务代码那样直接更多出现在编译期、链接期和运行时环境上。下面按实际频率整理几个高频问题。问题现象可能原因排查方式解决方案链接错误 LNK2019 / LNK2005spdlog 相关符号未解析或重复定义编译模式与链接模式不一致header-only 与 compiled 混用查看编译命令中是否定义了 SPDLOG_COMPILED_LIB保持统一模式header-only 不定义SPDLOG_COMPILED_LIBcompiled 模式则必须统一定义找不到spdlog/fmt/bundled相关头文件fmt 库冲突或 spdlog 版本内置 fmt 未启用查看 include 路径和项目已有 fmt 版本使用 spdlog 内置 fmt避免外部 fmt或使用SPDLOG_FMT_EXTERNAL并确保外部 fmt 版本匹配中文日志乱码文件编码与写入字节不一致CString 未转换检查日志文件编码和传入的字符串类型统一使用 UTF-8或让文件 sink 使用宽字符日志异步 logger 初始化时崩溃或抛异常调用create_async前未初始化线程池检查是否调用了spdlog::init_thread_pool或spdlog::create_async的时机在创建 async logger 之前初始化线程池全局初始化只做一次日志文件不按预期滚动rotating sink 参数理解偏差或时间切分混用查看滚动日志生成的文件名和时间rotating 按大小滚动daily 按日期滚动确认使用的是哪个 sink输出窗口没有 msvc_sink 日志MFC 项目没有附加 msvc_sink或 VS 输出窗口未打开检查 logger 构造时是否加入msvc_sink把msvc_sink_mt加入 sinks_init_list性能下降明显每条日志都flush或同步模式下日志量过大分析日志调用频率和 flush 策略减少非关键路径日志频率开启异步模式设置flush_on为错误级别 flush_every批量刷新除了表格里的问题还有一个容易忽略的点spdlog 的spdlog::shutdown()应该在程序即将退出时调用它会刷新所有 logger 并释放资源。如果程序通过exit()或者 Windows 的TerminateProcess直接终止日志可能来不及落盘最后一段日志丢失。另外在 Windows 上从 GitHub 下载 spdlog 源码可能会遇到网络问题。可以把源码包放到公司内部 Git 仓库或者使用 vcpkg 缓存避免每次配置环境都重新下载。9. 工程最佳实践与注意事项项目里的日志系统一旦跑起来改动成本会越来越高。因此一开始就把规范定好能节省大量后期维护时间。9.1 明确使用命名 Logger不要在整个项目里到处使用默认 logger。正确做法是按模块或服务创建命名 logger例如订单模块用order_logger用户模块用user_logger。这样每个模块可以独立设置级别、输出文件和滚动策略。模块之间日志互不干扰排查问题时只需看对应模块的日志文件。9.2 级别设置要区分 Debug 和 Release开发阶段为了调试方便可以把级别设为debug甚至trace。但生产环境如果也开debug日志量会非常恐怖影响性能也会让关键错误信息淹没在大量非关键日志里。建议Debug 构建spdlog::set_level(spdlog::level::debug)。Release 构建spdlog::set_level(spdlog::level::info)或warn。特殊时期通过配置中心或环境变量动态调整级别而不是改代码重新编译。9.3 合理设计刷新策略日志的刷新策略要分场景错误和严重级别日志flush_on(spdlog::level::err)哪怕牺牲一点性能也要保证错误日志落盘。普通日志使用flush_every(std::chrono::seconds(3))批量刷新降低 I/O 压力。程序结束调用spdlog::shutdown()。9.4 不要把敏感信息写入日志这是非常容易被忽视的一点。日志中不要记录密码、token、身份证号、银行卡号等敏感信息。如果业务确实需要记录用户标识可以使用脱敏后的 ID而不是完整信息。一旦日志文件泄露敏感数据会直接造成安全事故。spdlog 本身没有脱敏能力脱敏逻辑要在业务层完成。9.5 生产环境默认使用异步和滚动文件生产环境最稳妥的组合是rotating_file_sink或daily_file_sink加异步模式。日志文件要设置大小上限和保留数量避免磁盘被日志写满。对长时间运行的服务来说无限增长的日志文件是最大的隐患之一。9.6 高版本 C 带来的额外收益如果项目允许尽量使用 C17 及以上。spdlog 的格式化底层依赖 fmt更高的 C 标准意味着更好的编译优化和更完整的格式化支持。同时新版本的 spdlog 对概念、自定义类型格式化支持更友好使用体验会明显提升。9.7 团队协作时统一封装在团队项目里建议在 spdlog 之上再做一层薄薄的封装比如提供统一的LOG_INFO、LOG_ERROR宏或者日志管理类。这样未来如果要迁移日志系统不需要改动每个业务文件只需要改封装层。但封装要薄不要过度设计避免把 spdlog 的高性能特性包没了。10. 总结与后续学习方向spdlog 吸引人的地方不是它有多么花哨的功能而是它把 C 日志系统里那些“不得不做”的基础工作全部做完了跨平台、线程安全、格式化、文件滚动、异步队列、多样化的输出目标。引入 spdlog 之后团队可以把精力从“怎么把日志写进文件”转移到“日志内容是否有价值”上。读完这篇文章你可以从三个方面继续深入第一跑通一个最小 spdlog 示例确认集成路径无误后再把文件日志和异步日志接入自己的项目。第二根据项目规模选择具体用法。小型工具直接使用全局静态函数实现几行日志大型服务优先按模块创建命名 logger并使用旋转文件加异步模式。第三针对特殊场景比如自定义 sink、多进程日志文件锁、远程日志传输、结构化日志输出可以去看 spdlog 的源码和官方示例。spdlog 的源码规模并不大注释也比较清晰读源码是理解日志系统设计的好方式。日志系统的价值往往要到问题发生时才会体现。如果那行救命的日志恰好被你写进了代码调试时间可能从几小时缩短到几分钟。而 spdlog 能保证的就是当那行日志被写出来时它能够稳定、快速、按你期望的格式出现在正确的地方。建议收藏备用。下次给 C 项目接入日志时直接按这篇文章的路径操作能少踩不少坑。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价