C++ 应用程序中的日志记录:最佳实践
日志记录是任何严肃 C++ 软件开发的基础部分。没有可靠的日志记录系统,调试复杂错误、监控性能和安全审计几乎不可能。在本文中,我们将探讨 C++ 中日志记录的最佳实践,从库的选择到高级格式化和文件轮转技术。
1. 选择日志记录库
C++ 中有几个成熟的日志记录库。放弃自己实现而选择现成的解决方案可以节省时间并减少错误数量。
- spdlog — 最流行的库。具有高性能(header-only、异步模式)、简单的 API 以及对多种格式(JSON、纯文本)的支持。
- Boost.Log — 来自 Boost 的一个功能强大但更重量级的库。非常适合需要复杂过滤和灵活后端配置的企业级项目。
- Google Logging (glog) — 来自 Google 的简单库。非常适合小型项目,但灵活性较差。
spdlog 初始化示例:
#include <spdlog/spdlog.h>#include <spdlog/sinks/basic_file_sink.h>
int main() { // 创建一个写入文件 "logs/app.log" 的记录器 auto logger = spdlog::basic_logger_mt("file_logger", "logs/app.log"); // 设置日志级别 logger->set_level(spdlog::level::debug); // 记录消息 logger->info("应用程序已启动"); return 0;}2. 日志级别和过滤
使用日志级别(trace、debug、info、warning、error、critical)是事实上的标准。它们允许根据环境(开发、测试、生产)灵活配置输出的信息量。
级别建议:
- Trace/Debug — 仅用于开发。关于执行流程、变量值的详细信息。
- Info — 标准事件:服务启动/停止、成功操作。
- Warning — 不会导致错误的异常情况(例如,使用过时的 API)。
- Error — 需要注意但非致命的错误。
- Critical — 致命错误,应用程序无法继续运行。
在 spdlog 中配置过滤的示例:
// 在生产环境中只记录 warning 及以上级别auto console_sink = std::make_shared<spdlog::sinks::stdout_color_sink_mt>();console_sink->set_level(spdlog::level::warn);
// 在文件中记录所有内容,包括 debugauto file_sink = std::make_shared<spdlog::sinks::basic_file_sink_mt>("logs/debug.log");file_sink->set_level(spdlog::level::debug);
auto logger = std::make_shared<spdlog::logger>("multi_sink", spdlog::sinks_init_list({console_sink, file_sink}));
spdlog::register_logger(logger);3. 性能和异步日志记录
同步日志记录可能成为性能瓶颈,尤其是在高负载系统中。每次调用 logger->info(...) 都会阻塞线程,直到写入磁盘完成。
性能最佳实践:
- 异步日志记录 — 使用单独的线程进行日志写入。spdlog 开箱即支持此功能。
- 避免在日志字符串中进行昂贵操作 — 不要在日志宏内部调用重型函数。例如,
logger->info("Result: {}", computeExpensiveValue());即使日志级别未达到也会调用computeExpensiveValue()。
```