spdlog — 高性能日志库
spdlog 是 C++ 最流行的日志库,基于 fmtlib,支持异步日志、多 sink、结构化日志,零配置即可使用。
安装
bash
# vcpkg
vcpkg install spdlog
# Conan
conan install spdlog/1.13.0
# CMake FetchContent
FetchContent_Declare(spdlog
GIT_REPOSITORY https://github.com/gabime/spdlog.git
GIT_TAG v1.13.0)
FetchContent_MakeAvailable(spdlog)
target_link_libraries(myapp PRIVATE spdlog::spdlog)快速开始
cpp
#include <spdlog/spdlog.h>
int main() {
// 直接使用默认 logger(输出到 stdout)
spdlog::info("Hello, {}!", "world");
spdlog::warn("警告: {}", 42);
spdlog::error("错误码: {}", -1);
spdlog::critical("严重错误!");
// 设置全局日志级别
spdlog::set_level(spdlog::level::debug);
spdlog::debug("调试信息: x={}, y={}", 1, 2);
// 格式化输出
spdlog::info("整数: {:05d}", 42); // 00042
spdlog::info("浮点: {:.3f}", 3.14159); // 3.142
spdlog::info("十六进制: {:#x}", 255); // 0xff
}创建 Logger
cpp
#include <spdlog/spdlog.h>
#include <spdlog/sinks/stdout_color_sinks.h>
#include <spdlog/sinks/basic_file_sink.h>
#include <spdlog/sinks/rotating_file_sink.h>
#include <spdlog/sinks/daily_file_sink.h>
// 控制台 logger(带颜色)
auto console = spdlog::stdout_color_mt("console");
console->info("彩色输出");
// 文件 logger
auto file_logger = spdlog::basic_logger_mt("file", "logs/app.log");
file_logger->info("写入文件");
// 滚动文件(按大小)
auto rotating = spdlog::rotating_logger_mt(
"rotating",
"logs/app.log",
1024 * 1024 * 10, // 10MB 滚动
3 // 保留 3 个文件
);
// 按天滚动
auto daily = spdlog::daily_logger_mt("daily", "logs/app.log", 0, 0); // 每天 00:00 滚动
// 获取已注册的 logger
auto logger = spdlog::get("console");多 Sink(同时输出到多个目标)
cpp
#include <spdlog/sinks/stdout_color_sinks.h>
#include <spdlog/sinks/rotating_file_sink.h>
// 创建多个 sink
auto console_sink = std::make_shared<spdlog::sinks::stdout_color_sink_mt>();
console_sink->set_level(spdlog::level::info); // 控制台只显示 info 及以上
auto file_sink = std::make_shared<spdlog::sinks::rotating_file_sink_mt>(
"logs/app.log", 1024 * 1024 * 5, 3);
file_sink->set_level(spdlog::level::debug); // 文件记录所有级别
// 组合为一个 logger
spdlog::logger logger("multi", {console_sink, file_sink});
logger.set_level(spdlog::level::debug); // logger 级别要 <= sink 级别
logger.debug("只写文件");
logger.info("写文件 + 控制台");
logger.error("写文件 + 控制台(红色)");
// 注册为全局可访问
spdlog::register_logger(std::make_shared<spdlog::logger>(logger));异步日志
cpp
#include <spdlog/async.h>
#include <spdlog/sinks/basic_file_sink.h>
// 初始化异步线程池(队列大小, 线程数)
spdlog::init_thread_pool(8192, 1);
// 创建异步 logger
auto async_logger = spdlog::basic_logger_async<spdlog::async_overflow_policy::block>(
"async", "logs/async.log");
// 日志调用立即返回,实际写入在后台线程
async_logger->info("异步写入,不阻塞主线程");
// 确保所有日志写完再退出
spdlog::shutdown();自定义格式
cpp
// 格式说明符
// %Y-%m-%d %H:%M:%S 时间戳
// %l 日志级别
// %n logger 名称
// %v 日志内容
// %t 线程 ID
// %s 源文件名
// %# 行号
// %! 函数名
spdlog::set_pattern("[%Y-%m-%d %H:%M:%S.%e] [%n] [%^%l%$] [%t] %v");
// 输出:[2026-04-23 10:30:00.123] [console] [info] [12345] Hello!
// 带源码位置(需要用宏)
#include <spdlog/spdlog.h>
SPDLOG_INFO("带位置信息: {}", 42); // 自动记录文件名和行号
// 自定义格式器
spdlog::set_pattern("%+"); // 默认格式结构化日志
cpp
// spdlog 支持 fmtlib 的所有格式化特性
struct Request {
std::string method;
std::string path;
int status;
};
// 自定义类型格式化
template<>
struct fmt::formatter<Request> {
constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
auto format(const Request& r, format_context& ctx) const {
return fmt::format_to(ctx.out(), "{} {} -> {}",
r.method, r.path, r.status);
}
};
Request req{"GET", "/api/users", 200};
spdlog::info("请求: {}", req);
// 输出:请求: GET /api/users -> 200生产配置示例
cpp
#include <spdlog/spdlog.h>
#include <spdlog/sinks/stdout_color_sinks.h>
#include <spdlog/sinks/rotating_file_sink.h>
#include <spdlog/async.h>
void init_logging(const std::string& log_dir, spdlog::level::level_enum level) {
// 异步线程池
spdlog::init_thread_pool(65536, 2);
std::vector<spdlog::sink_ptr> sinks;
// 控制台(仅 warn 及以上)
auto console = std::make_shared<spdlog::sinks::stdout_color_sink_mt>();
console->set_level(spdlog::level::warn);
sinks.push_back(console);
// 滚动文件(所有级别)
auto file = std::make_shared<spdlog::sinks::rotating_file_sink_mt>(
log_dir + "/app.log",
1024 * 1024 * 100, // 100MB
10 // 保留 10 个
);
file->set_level(spdlog::level::trace);
sinks.push_back(file);
auto logger = std::make_shared<spdlog::async_logger>(
"app", sinks.begin(), sinks.end(),
spdlog::thread_pool(),
spdlog::async_overflow_policy::block
);
logger->set_level(level);
logger->set_pattern("[%Y-%m-%d %H:%M:%S.%e] [%^%l%$] [%t] %v");
spdlog::set_default_logger(logger);
spdlog::flush_every(std::chrono::seconds(3));
}关键认知
spdlog 的性能来自两点:基于 fmtlib 的零开销格式化,以及异步模式下的无锁队列。生产环境用异步 logger + 滚动文件,开发环境用彩色控制台。SPDLOG_* 宏在 Release 模式下可以完全消除日志调用。