
1. 什么是 spdlogspdlog 是一个 C 的日志库特点就三个快、简单、纯头文件。你只需要#include一个头文件就能用不需要额外编译链接。本文只讲核心概念和每个函数的参数、返回值、用法帮你用最短时间上手。2. 安装与引入任选一种方式安装# vcpkg vcpkg install spdlog 或用 Conan conan install spdlog/1.14.1 或直接克隆源码 git clone https://github.com/gabime/spdlog.git代码中只需要一行#include spdlog/spdlog.h3. 日志级别spdlog 用枚举spdlog::level::level_enum表示级别从低到高共 7 个值枚举值含义使用场景spdlog::level::trace最详细的跟踪极致调试spdlog::level::debug调试信息开发阶段spdlog::level::info常规运行信息生产环境默认spdlog::level::warn警告潜在问题spdlog::level::error错误功能异常但不崩溃spdlog::level::critical严重错误即将崩溃spdlog::level::off关闭全部日志完全禁用相关函数// 函数spdlog::set_level // 参数spdlog::level::level_enum lvl —— 目标级别 // 返回值void spdlog::set_level(spdlog::level::info); // 全局设置低于info的日志不再输出 // 函数logger-set_level (成员函数) // 参数同上 // 返回值void auto lg spdlog::stdout_color_mt(mylog); lg-set_level(spdlog::level::debug); // 只对这个logger生效 // 函数logger-level (成员函数) // 参数无 // 返回值spdlog::level::level_enum —— 当前级别 auto current_level lg-level(); // 函数logger-should_log (成员函数) // 参数spdlog::level::level_enum lvl —— 要检查的级别 // 返回值bool —— 该级别是否会被输出 if (lg-should_log(spdlog::level::debug)) { // 只有debug级别启用时才执行 }4. 日志器 LoggerLogger 是 spdlog 的核心对象所有日志都通过 Logger 输出。下面是创建和管理 Logger 的全部核心函数。4.1 创建 Logger// 1) stdout_color_mt —— 创建控制台Logger多线程安全带颜色 // 参数const std::string name —— Logger名称用于后续查找 // 返回值std::shared_ptrspdlog::logger auto console_lg spdlog::stdout_color_mt(console); // 2) stdout_color_st —— 同上单线程版本非线程安全略快 // 参数、返回值同上 auto console_lg_st spdlog::stdout_color_st(console_st); // 3) basic_logger_mt —— 创建文件Logger多线程安全 // 参数1const std::string name —— Logger名称 // 参数2const std::string filename —— 日志文件路径 // 参数3bool truncate false —— 是否清空已有文件默认追加 // 返回值std::shared_ptrspdlog::logger auto file_lg spdlog::basic_logger_mt(file, logs/app.log); // 4) rotating_logger_mt —— 创建循环文件Logger文件超过大小自动切分 // 参数1const std::string name —— Logger名称 // 参数2const std::string filename —— 基础文件路径 // 参数3size_t max_file_size —— 单个文件最大字节数 // 参数4size_t max_files —— 最多保留的历史文件数 // 返回值std::shared_ptrspdlog::logger auto rotating_lg spdlog::rotating_logger_mt(rot, logs/rot.log, 1024 * 1024 * 5, 3); // 5) daily_logger_mt —— 创建按天切分的文件Logger // 参数1const std::string name // 参数2const std::string filename // 参数3int hour 0 —— 每天几点切分0~23 // 参数4int minute 0 —— 每天几分切分0~59 // 返回值std::shared_ptrspdlog::logger auto daily_lg spdlog::daily_logger_mt(daily, logs/daily.log, 0, 0);4.2 获取与管理 Logger// 函数spdlog::get // 参数const std::string name —— Logger名称 // 返回值std::shared_ptrspdlog::logger —— 找到返回指针未找到返回nullptr auto lg spdlog::get(console); if (lg) { lg-info(找到了); } // 函数spdlog::set_default_logger // 参数std::shared_ptrspdlog::logger logger —— 要设为默认的logger // 返回值void // 作用设置后spdlog::info(...) 等全局函数就用这个logger输出 spdlog::set_default_logger(console_lg); // 函数spdlog::default_logger // 参数无 // 返回值std::shared_ptrspdlog::logger —— 当前默认logger auto def spdlog::default_logger(); // 函数spdlog::register_logger // 参数std::shared_ptrspdlog::logger logger —— 手动注册注册后可通过 get() 查找 // 返回值void spdlog::register_logger(file_lg); // 函数spdlog::drop // 参数const std::string name —— 要删除的logger名称 // 返回值void spdlog::drop(file); // 函数spdlog::drop_all // 参数无 // 返回值void —— 删除所有已注册logger spdlog::drop_all();5. 输出目标 SinksSink 决定日志写到哪。每个 Logger 至少绑定一个 Sink。上面 4.1 小节的创建函数如basic_logger_mt内部会自动创建对应的 Sink。你也可以手动创建 Sink 再组装// 手动创建 Sink 并组合多个输出目标 auto console_sink std::make_sharedspdlog::sinks::stdout_color_sink_mt(); auto file_sink std::make_sharedspdlog::sinks::basic_file_sink_mt(logs/multi.log); // 构造函数spdlog::logger 的构造函数 // 参数1const std::string name —— Logger名称 // 参数2迭代器 begin —— Sink列表起始 // 参数3迭代器 end —— Sink列表结束 // 返回值构造出的logger对象通过make_shared包装 std::vectorspdlog::sink_ptr sinks{console_sink, file_sink}; auto multi_lg std::make_sharedspdlog::logger(multi, sinks.begin(), sinks.end()); spdlog::register_logger(multi_lg); // Sink 也有自己的 set_level 和 set_pattern // 函数sink-set_level // 参数spdlog::level::level_enum lvl // 返回值void console_sink-set_level(spdlog::level::warn); // 控制台只输出warn及以上 // 函数sink-set_pattern // 参数const std::string pattern —— 格式字符串见第7节 // 返回值void file_sink-set_pattern([%Y-%m-%d %H:%M:%S] [%l] %v);6. 日志输出函数每个 Logger 有 6 个输出函数对应 6 个级别。它们的签名完全一致可变参数模板只是级别不同。// 成员函数签名以info为例 // templatetypename... Args // void logger-info(const char* fmt, const Args... args) // 参数1const char* fmt —— 格式字符串{} 作为占位符 // 参数2...const Args... args —— 零个或多个参数依次填入占位符 // 返回值void auto lg spdlog::stdout_color_mt(demo); lg-trace(trace级别x{}, y{}, 10, 20); lg-debug(debug级别当前状态正常); lg-info(info级别用户{}登录成功, Alice); lg-warn(warn级别内存使用率{}%, 85); lg-error(error级别打开文件失败: {}, data.txt); lg-critical(critical级别系统即将退出错误码{}, 500); // 全局便捷函数使用默认logger // 函数spdlog::info(const char* fmt, const Args... args) 等6个 // 参数、返回值同上无需持有logger指针 spdlog::info(直接用全局函数输出{}, 42); spdlog::error(全局错误函数);7. 格式化输出通过set_pattern自定义日志的输出格式。// 函数spdlog::set_pattern (全局) // 函数logger-set_pattern (成员) // 参数const std::string pattern —— 格式字符串 // 返回值void spdlog::set_pattern(%^[%Y-%m-%d %H:%M:%S.%e] [%l] [%n] %v%$); // 常用格式占位符 // %Y-%m-%d 日期年-月-日 // %H:%M:%S 时间时:分:秒 // %e 毫秒 // %l 日志级别缩写如 info → Iwarn → W // %L 日志级别全称如 INFO、WARNING // %n Logger 名称 // %v 日志消息正文 // %t 线程 ID // %P 进程 ID // %s 源文件名需配合 SPDLOG_LOGGER_* 宏使用 // %# 源文件行号同上 // %! 函数名同上 // %^ 开始颜色控制台 // %$ 结束颜色控制台8. 异步日志异步日志把写日志的活交给后台线程主线程只把消息丢进队列就返回适合高频日志场景。#include spdlog/async.h #include spdlog/sinks/basic_file_sink.h // 函数spdlog::init_thread_pool // 参数1size_t q_size —— 队列最大容量消息数 // 参数2size_t thread_count —— 后台线程数通常1个就够 // 返回值void spdlog::init_thread_pool(8192, 1); // 创建异步Logger —— 用法和普通Logger一样只是多传一个模板参数 async_factory // 函数spdlog::basic_logger_mtspdlog::async_factory // 参数1const std::string name // 参数2const std::string filename // 返回值std::shared_ptrspdlog::logger auto async_lg spdlog::basic_logger_mtspdlog::async_factory(async, logs/async.log); // 异步写日志主线程几乎不阻塞 for (int i 0; i 10000; i) { async_lg-info(第{}条日志, i); }9. 条件日志与频率限制宏这三个宏用于控制日志是否真的写出避免日志刷屏。// 1) SPDLOG_LOGGER_CONDITIONAL —— 条件满足时才写日志 // 参数1logger —— std::shared_ptrspdlog::logger目标logger // 参数2condition —— bool表达式为true才输出 // 参数3level —— 日志级别如 info、error // 参数4fmt, ... —— 格式字符串和参数 int error_count 5; SPDLOG_LOGGER_CONDITIONAL(lg, error_count 0, error, 发现{}个错误, error_count); // 2) SPDLOG_LOGGER_EVERY_N —— 每N次调用才写一次 // 参数1logger —— 目标logger // 参数2level —— 日志级别 // 参数3N —— int间隔次数每N次输出1次 // 参数4fmt, ... —— 格式字符串和参数 for (int i 0; i 100; i) { SPDLOG_LOGGER_EVERY_N(lg, info, 10, 进度: {}, i); // i0,10,20,... 才输出 } // 3) SPDLOG_LOGGER_THROTTLE —— 按时间间隔限制单位秒 // 参数1logger —— 目标logger // 参数2level —— 日志级别 // 参数3interval_sec —— double最小间隔秒数 // 参数4fmt, ... —— 格式字符串和参数 for (int i 0; i 100; i) { SPDLOG_LOGGER_THROTTLE(lg, warn, 1.0, 高频事件: {}, i); // 每秒最多1条 } // 简化版使用默认logger // SPDLOG_CONDITIONAL(condition, level, fmt, ...) // SPDLOG_EVERY_N(level, N, fmt, ...) // SPDLOG_THROTTLE(level, interval_sec, fmt, ...)10. 资源清理程序退出前务必刷新并释放资源。// 函数spdlog::flush // 参数无 // 返回值void —— 立即刷新所有logger的缓冲区 spdlog::flush(); // 函数logger-flush (成员) // 参数无 // 返回值void —— 只刷新该logger lg-flush(); // 函数spdlog::flush_on // 参数spdlog::level::level_enum lvl —— 达到该级别时自动刷新 // 返回值void spdlog::flush_on(spdlog::level::err); // 每次输出error及以上级别时自动刷盘 // 函数spdlog::flush_every (仅异步logger有效) // 参数std::chrono::duration interval —— 定时刷新间隔 // 返回值void spdlog::flush_every(std::chrono::seconds(3)); // 函数spdlog::shutdown // 参数无 // 返回值void —— 刷新所有日志并释放所有logger程序退出前必须调用 spdlog::shutdown();以上就是 spdlog 全部核心函数的用法。掌握这些日常开发中的日志需求基本都能覆盖。