40人参与 • 2026-04-14 • C/C++
spdlog 是一个高性能、超快速、零配置的 c++ 日志库,它旨在提供简洁的 api 和丰富的功能,同时保持高性能的日志记录。它支持多种输出目标、格式化选项、线程安全以及异步日志记录。
特点:
(1)步骤:
sudo apt-get update # 更新软件源 sudo apt-get install libspdlog-dev # 安装开发库
(2)特点:
(3)验证安装:

# 下载源码 git clone https://github.com/gabime/spdlog.git # 切换目录 cd spdlog/ # 创建并进入构建目录 mkdir build cd build/ # 执行构建命令,生成 makefile cmake .. # 编译代码 make # 安装到系统目录(默认 /usr/local) sudo make install
namespace spdlog {
namespace level {
enum level_enum : int
{
trace = spdlog_level_trace,
debug = spdlog_level_debug,
info = spdlog_level_info,
warn = spdlog_level_warn,
error = spdlog_level_error,
critical = spdlog_level_critical,
off = spdlog_level_off,
n_levels
};
}
}在 spdlog/include/spdlog/common.h 头文件中,其宏定义如下:
#define spdlog_level_trace 0
#define spdlog_level_debug 1
#define spdlog_level_info 2
#define spdlog_level_warn 3
#define spdlog_level_error 4
#define spdlog_level_critical 5
#define spdlog_level_off 6
namespace spdlog {
class logger
{
// 构造函数
logger(std::string name);
logger(std::string name, sink_ptr single_sink);
logger(std::string name, sinks_init_list sinks);
// 设置输出等级(只输出 高于或等于 此等级的日志)
void set_level(level::level_enum log_level);
// 自定义 日志输出格式
void set_pattern(const std::string& pattern);
// 以不同等级 输出日志信息的接口
template<typename... args>
void trace(fmt::format_string<args...> fmt, args &&...args)
template<typename... args>
void debug(fmt::format_string<args...> fmt, args &&...args)
template<typename... args>
void info(fmt::format_string<args...> fmt, args &&...args)
template<typename... args>
void warn(fmt::format_string<args...> fmt, args &&...args)
template<typename... args>
void error(fmt::format_string<args...> fmt, args &&...args)
template<typename... args>
void critical(fmt::format_string<args...> fmt, args &&...args)
// 立刻刷新日志信息
void flush();
// 设置刷新策略(指定一个日志等级,一旦有 高于或等于指定等级的日志,立刻刷新日志信息)
void flush_on(level::level_enum log_level);
};
}假设log 是logger类对象的智能指针
log->set_pattern("%y-%m-%d %h:%m:%s [%t] [%-8l] %v");
%t - 线程 id(thread id)
%n - 日志器名称(logger name)
%l - 日志级别名称(level name),如 info, debug, error 等
%v - 日志内容(message)
%y - 年(year)
%m - 月(month)
%d - 日(day)
%h - 小时(24-hour format)
%m - 分钟(minute)
%s - 秒(second)namespace spdlog {
namespace details {
class thread_pool
{
thread_pool(size_t q_max_items, size_t threads_n, std::function<void()> on_thread_start,
std::function<void()> on_thread_stop);
thread_pool(size_t q_max_items, size_t threads_n, std::function<void()> on_thread_start);
thread_pool(size_t q_max_items, size_t threads_n);
};
}
}通过registry类(单例)持有 全局线程池实例:
// registry 类(单例)管理全局线程池
namespace spdlog {
namespace details {
class registry
{
std::shared_ptr<thread_pool> _tp; // 全局线程池实例
std::mutex _mutex; // 线程安全锁
public:
// 获取单例实例(线程安全)
static registry &instance()
{
static registry s_instance; // 静态实例(c++11保证线程安全)
return s_instance;
}
// 获取全局线程池(延迟初始化)
std::shared_ptr<thread_pool> get_tp()
{
std::lock_guard<std::mutex> lock(_mutex);
if (!_tp)
{
// 首次调用时创建默认线程池(8192队列 + 1线程)
_tp = std::make_shared<thread_pool>(8192, 1);
}
return _tp;
}
// 重置全局线程池(线程安全)
void set_tp(std::shared_ptr<thread_pool> new_tp)
{
std::lock_guard<std::mutex> lock(_mutex);
// 先停止旧线程池的所有任务
if (_tp)
{
_tp->shutdown(); // 内部停止所有工作线程
}
_tp = std::move(new_tp); // 替换为新线程池
}
private:
registry() = default; // 禁用外部构造
registry(const registry&) = delete; // 禁用拷贝
registry& operator=(const registry&) = delete; // 禁用赋值
};
}
}namespace spdlog {
// 获取全局线程池的共享指针
std::shared_ptr<details::thread_pool> thread_pool()
{
return details::registry::instance().get_tp();
}
// 重置全局线程池(指定队列大小和线程数)
void init_thread_pool(size_t q_size, size_t thread_count)
{
auto new_tp = std::make_shared<details::thread_pool>(q_size, thread_count);
details::registry::instance().set_tp(new_tp);
}
}
namespace spdlog {
class async_logger final : public logger
{
async_logger(std::string logger_name, sinks_init_list sinks_list, std::weak_ptr<details::thread_pool> tp,
async_overflow_policy overflow_policy = async_overflow_policy::block);
async_logger(std::string logger_name, sink_ptr single_sink, std::weak_ptr<details::thread_pool> tp,
async_overflow_policy overflow_policy = async_overflow_policy::block);
}
}| 类型 | 日志写入流程 | 线程模型 |
|---|---|---|
| (同步)日志记录器 | 主线程直接调用i/o操作(如文件写入、控制台输出) • 日志生成 → 立即执行磁盘/网络i/o → 主线程阻塞等待完成 | 单线程模型:日志i/o占用主线程时间片 |
| 异步日志记录器 | 主线程将日志存入内存队列(任务队列) • 日志生成 → 存入队列 → 立即返回主线程 • 后台线程池消费队列并执行i/o | 生产者-消费者模型:主线程与i/o线程分离 |
关键区别:异步日志通过内存队列缓冲和线程池异步刷盘,避免主线程因i/o等待被阻塞
using async_factory = async_factory_impl<async_overflow_policy::block>;
//创建一个彩色输出到标准输出的日志记录器,默认工厂 创建同步日志记录器
template<typename factory = spdlog::synchronous_factory>
std::shared_ptr<logger> stdout_color_mt(const std::string &logger_name,
color_mode mode = color_mode::automatic);
//标准错误
template<typename factory = spdlog::synchronous_factory>
std::shared_ptr<logger> stderr_color_mt(const std::string &logger_name,
color_mode mode = color_mode::automatic);
// 指定文件
template<typename factory = spdlog::synchronous_factory>
std::shared_ptr<logger> basic_logger_mt(const std::string &logger_name, const filename_t &filename,
bool truncate = false,
const file_event_handlers &event_handlers = {})
//循环文件
template<typename factory = spdlog::synchronous_factory>
std::shared_ptr<logger> rotating_logger_mt(const std::string &logger_name, const filename_t &filename,
size_t max_file_size, size_t max_files,
bool rotate_on_open = false)日志记录器工厂类:封装了 日志记录器类对象 的构建 和 配置过程
有了日志记录器工厂类,我们不需要关心 日志记录器类对象 的构建 和 配置过程,可以通过api接口一键构造 日志记录器类对象
spdlog::basic_logger_mt()接口 的 第三个参数 truncate 的功能:
| 值 | 行为 | 适用场景 |
|---|---|---|
| true | 若日志文件已存在,清空文件内容,从头开始写入新日志。 | 需要覆盖旧日志的场景(如临时调试) |
| false (默认) | 若日志文件已存在,追加新日志到文件末尾;若文件不存在则创建新文件。 | 长期运行的程序需保留历史日志的场景 |
采用默认工厂,创建的都是 同步日志记录器对象
(1)创建 向标准输出写入日志 的同步日志记录器对象
// 使用stdout_color_mt接口,只需指定 要创建的日志记录器对象的名字,
// 它就会创建 指定名字的日志记录器对象,并返回指向该对象的智能指针
auto log = spdlog::stdout_color_mt("sync_logger");
(2)创建 向指定文件写入日志 的同步日志记录器对象
// 使用basic_logger_mt接口,需指定 要创建的日志记录器对象的名字 和 文件,
// 它就会创建 向指定文件写入日志的 指定名字的日志记录器对象,并返回指向该对象的智能指针
auto file_log = spdlog::basic_logger_mt("file_sync_logger", "log.txt");
要创建异步日志记录器对象,需要显式指定 工厂类型(spdlog::async_factory)
(1)创建 向标准输出写入日志 的异步日志记录器对象
auto log = spdlog::stdout_color_mt<spdlog::async_factory>("sync_logger");
(2)创建 向指定文件写入日志 的异步日志记录器对象
auto file_log = spdlog::basic_logger_mt<spdlog::async_factory>("file_sync_logger", "log.txt");
namespace spdlog {
// 日志刷新策略-每隔 n 秒刷新一次
void flush_every(std::chrono::seconds interval);
// 设置输出等级(只输出 高于或等于 此等级的日志)
void set_level(level::level_enum log_level);
// 设置刷新策略(指定一个日志等级,一旦有 高于或等于指定等级的日志,立刻刷新日志信息)
void flush_on(level::level_enum log_level);
// 自定义 日志输出格式
void set_pattern(const std::string& pattern);
}注:全局配置的 优先级低于 日志记录器对象的专属配置!
spdlog 采用作用域逐级覆盖的配置策略:
影响所有未单独配置的日志记录器,作为默认值存在。
每个日志器对象独立配置,优先级高于全局配置。
要使用spdlog库,在你的 c++ 源文件中必须包含 spdlog 的头文件:
#include <spdlog/spdlog.h>
#include <spdlog/spdlog.h>
#include <spdlog/sinks/stdout_color_sinks.h> // 包含 spdlog::stdout_color_mt() 的实现
int main()
{
// 1. 全局配置
spdlog::flush_on(spdlog::level::level_enum::info);
// 设置输出等级(只输出 高于或等于 info等级的日志)
spdlog::set_level(spdlog::level::level_enum::info);
// 自定义 日志输出格式
spdlog::set_pattern("%y-%m-%d %h:%m:%s [%t] [%-8l] %v");
// 日志刷新策略-每隔 1 秒刷新一次
spdlog::flush_every(std::chrono::seconds(1));
// 2. 创建同步日志器(向标准输出写日志)
auto log = spdlog::stdout_color_mt("sync_logger");
// 3. 使用同步日志器 向标准输出写日志
log->trace("你好!{}", "中国"); // {}是占位符,不区分数据类型
log->debug("你好!{}","中国");
log->info("你好!{}","中国");
log->warn("你好!{}","中国");
log->error("你好!{}","中国");
log->critical("你好!{}","中国");
return 0;
}注:spdlog库依赖 fmt库,所以链接时,还需要显式指定fmt库


#include <spdlog/spdlog.h>
#include <spdlog/sinks/basic_file_sink.h> // 包含 spdlog::basic_logger_mt() 的实现
int main()
{
// 1. 全局配置
// 日志刷新策略-每隔 1 秒刷新一次
spdlog::flush_every(std::chrono::seconds(1));
// 2. 创建同步日志器(向当前目录下的log.txt文件 写日志)
auto file_log = spdlog::basic_logger_mt("sync_logger", "log.txt");
// 使用同步日志器的专用配置接口
file_log->flush_on(spdlog::level::level_enum::info);
file_log->set_level(spdlog::level::level_enum::info);
file_log->set_pattern("%y-%m-%d %h:%m:%s [%t] [%-8l] %v");
// 3. 使用同步日志器 向指定文件写日志
file_log->trace("你好!{}", "中国"); // {}是占位符,不区分数据类型
file_log->debug("你好!{}","中国");
file_log->info("你好!{}","中国");
file_log->warn("你好!{}","中国");
file_log->error("你好!{}","中国");
file_log->critical("你好!{}","中国");
return 0;
}

#include <spdlog/spdlog.h>
#include <spdlog/sinks/basic_file_sink.h> // 包含 spdlog::basic_logger_mt() 的实现
#include <spdlog/async.h> // 包含 spdlog::async_factory工厂类的实现
int main()
{
// 1. 全局配置
// 日志刷新策略-每隔 1 秒刷新一次
spdlog::flush_every(std::chrono::seconds(1));
// 初始化全局线程池 的任务队列数 和 线程数量
spdlog::init_thread_pool(4096, 2);
// 2. 显式指定工厂类, 创建异步日志器(向当前目录下的log.txt文件 写日志)
// 创建异步日志器对象时,需要指定 线程池实例,
// basic_logger_mt接口 创建异步日志器对象时,会指定 全局线程池实例,
// 如果之前未初始化全局线程池的配置,全局线程池实例采用默认配置:8192队列 + 1线程
auto file_log = spdlog::basic_logger_mt<spdlog::async_factory>("sync_logger", "log.txt");
// 使用异步日志器的专用配置接口
file_log->flush_on(spdlog::level::level_enum::info);
file_log->set_level(spdlog::level::level_enum::info);
file_log->set_pattern("%y-%m-%d %h:%m:%s [%t] [%-8l] %v");
// 3. 使用异步日志器 向指定文件写日志
file_log->trace("你好!{}", "中国"); // {}是占位符,不区分数据类型
file_log->debug("你好!{}","中国");
file_log->info("你好!{}","中国");
file_log->warn("你好!{}","中国");
file_log->error("你好!{}","中国");
file_log->critical("你好!{}","中国");
return 0;
}
到此这篇关于高性能c++ 日志实战:spdlog 核心架构解析与最佳实践指南的文章就介绍到这了,更多相关c++ 日志 spdlog内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
您想发表意见!!点此发布评论
版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。
发表评论