2026年世界杯官网 C++之高性能跨平台日记库spdlog

更多 C++ 著述见《 修远之路(C++集萃) 》专栏
spdlog 是一个基于 fmt 库的高性能、头文献优先的 C++ 日记框架,通过预分派环形部队与异步线程池已毕零拷贝日记纪录。
超高速:异步形状可达百万条 / 秒糊涂,比 glog/log4cpp 快数倍。无锁联想:异步用无锁部队 + 线程池,干线程仅入队即复返,真实不阻塞。零拷贝 / 内存池:减少内存分派,高并发更稳。同步 / 异步双形状:同步:径直写 I/O,通俗径直。异步:后台线程处理 I/O,干线程无阻塞。中枢进程 #C++ #编程言语 #后端 #逐日精选著述中枢模块| 模块 | 中枢使命/作用 | 输入/输出 | | ---
| Logger | 日记级别过滤、音问分发、不实处理 长入进口,营救多 sink 组合 | 法子化字符串 +
| Sink | 内容 I/O 操作、法子化输出 可蔓延输出见解,单一使命 | log_msg 对象 字节流到见解 | | Formatter | 音问法子化、时刻戳处理、面孔标志 营救自界说法子,缓存优化 | log_msg 对象 法子化字符串 | | Registry | 全局 logger 处分、设立分发、人命周期 勾通处分,幸免全局变量浑浊 | logger 注册苦求 logger 援用 | | Thread Pool | 异步音问处理、后台线程调遣 解耦业务线程与 I/O 线程 | async_msg 对象 调用 logger sink_it_ | | MPMC Queue | 线程安全音问部队、阻塞/非阻塞计策 坐褥者-糟践者解耦,零分派 | log_msg 对象 出队音问 |
使用场景
| 同步日记 | 单线程哄骗、调试阶段、低频日记 | 高并发坐褥环境、性能明锐旅途 | | 异步日记 | 高并发作事、游戏引擎、及时系统 | 需要严格轨则保证、崩溃时日记不成丢失 | | 环形缓冲 | 固定内存预算、可容忍音问丢失 | 需要抓久化整个日记、审计场景 | | 多 Sink 组合 | 同期输出到文献/舍弃台/网罗 | 单一输出见解、极简场景 | | 自界说法子 | 结构化日记、日记分析系统 | 顺次法子即可繁华需求 |
中枢践诺时序同步日记践诺进程异步日记践诺进程旨趣与联想spdlog 通过预分派与零拷贝联想,在保证接口大略的前提下已毕极致性能:
环形部队:断送部分天真性(固定大小),交流零分派与缓存友好模板计策:编译期决定线程安全计策,零运行时支拨异步解耦:业务线程仅贯注入队,I/O 蔓延不影响中枢旅途关键详尽与机制环形部队(Circular Queue)spdlog 的中枢肠能优化来自预分派的环形部队,其已毕位于 circular_q.h :
template
class circular_q { size_t max_items_ = 0; typename std::vector::size_type head_ = 0; typename std::vector::size_type tail_ = 0; size_t overrun_counter_ = 0; std::vector v_; void push_back(T &&item) { if (max_items_ > 0) { v_[tail_] = std::move(item); tail_ = (tail_ +
AG百家乐APP中国官方下载if (tail_ == head_) { // 部队满,秘密最旧音问 head_ = (head_ +
++overrun_counter_; } } } };
关键联想点:
预分派:构造时刻派 max_items + 1 个元素,幸免运行时刻派秘密计策:部队满时自动秘密最旧音问,保证写入不阻塞零拷贝:使用 std::move 飘摇整个权,幸免深拷贝计数器: overrun_counter_ 纪录丢失音问数,用于监控MPMC 阻塞部队多坐褥者-多糟践者队诸君于 mpmc_blocking_q.h ,封装了环形部队并提供线程安全:
template
class mpmc_blocking_queue { std::mutex queue_mutex_; std::condition_variable push_cv_; std::condition_variable pop_cv_; spdlog::details::circular_q q_; std::atomic discard_counter_{0}; void enqueue(T &&item) { { std::unique_lock lock(queue_mutex_); pop_cv_.wait(lock, [this] { return !this->q_.full; }); q_.push_back(std::move(item)); } push_cv_.notify_one; } bool dequeue_for(T &popped_item, std::chrono::milliseconds wait_duration) { { std::unique_lock lock(queue_mutex_); if (!push_cv_.wait_for(lock, wait_duration, [this] { return !this->q_.empty; })) { return false; } popped_item = std::move(q_.front); q_.pop_front; } pop_cv_.notify_one; return true; } };
并发舍弃计策:
双条款变量: push_cv_ 叫醒糟践者, pop_cv_ 叫醒坐褥者细粒度锁:锁的抓未必刻仅限于部队操作,不包含 I/O超时机制: dequeue_for 营救超时复返,幸免死锁丢弃计数: discard_counter_ 纪录 enqueue_if_have_room 失败次数Sink 详尽与线程安全Sink 接口界说于 sink.h :
class sink {
public:
virtual ~sink = default;
virtual void log(const details::log_msg &msg) = 0;
virtual void flush = 0;
virtual void set_pattern(const std::string &pattern) = 0;
virtual void set_formatter(std::unique_ptr sink_formatter) = 0;
void set_level(level::level_enum log_level);
level::level_enum level const;
bool should_log(level::level_enum msg_level) const;
protected:
level_t level_{level::trace};
};
线程安全通过模板计策已毕,位于 base_sink.h :
template
class base_sink : public sink { public: void log(const details::log_msg &msg) final override { std::lock_guard lock(mutex_); sink_it_(msg); } void flush final override { std::lock_guard lock(mutex_); flush_; } protected: std::unique_ptr formatter_; Mutex mutex_; virtual void sink_it_(const details::log_msg &msg) = 0; virtual void flush_ = 0; };
联想上风:
编译期多态:通过模板参数采取 std::mutex 或 details::null_mutex零运行时支拨:单线程场景使用 null_mutex ,无锁竞争CRTP 形状:基类舍弃进程,派生类已毕具体逻辑法子化器与时刻戳缓存Pattern Formatter 位于 pattern_formatter.h :
class pattern_formatter final : public formatter {
private:
std::string pattern_;
std::string eol_;
pattern_time_type pattern_time_type_;
bool need_localtime_;
std::tm cached_tm_;
std::chrono::seconds last_log_secs_;
std::vector> formatters_;
std::tm get_time_(const details::log_msg &msg) {
if (need_localtime_) {
auto time_now = log_clock::to_time_t(msg.time);
if (last_log_secs_ != time_now) {
cached_tm_ = localtime(time_now);
last_log_secs_ = time_now;
}
return cached_tm_;
}
return gmtime(log_clock::to_time_t(msg.time));
}
};
性能优化:
时刻戳缓存:归并秒内的日记分享 std::tm 结构编译期解析:形状字符串在构造时解析为 flag_formatter 链表内存复用: memory_buf_t 使用 fmt 的 memory_buffer ,幸免屡次分派中枢联想遴选性能 vs 易用性| 联想有蓄意 | 性能收益 | 易用性代价 | 适用场景 | | ---
| Header-only 形状 | 无编译优化,编译时刻长 | 无需构建,2026年世界杯官网集成通俗 | 快速原型、袖珍技俩 | | 编译形状 | 编译时刻短,二进制体积小 | 需要 CMake 设立 | 坐褥环境、大型技俩 | | 异步形状 | 业务线程零阻塞 | 崩溃时可能丢失日记 | 高并发作事 | | 同步形状 | 日记轨则严格保证 | I/O 阻塞业务线程 | 调试、审计场景 |
关键量度:异步形状下,日记音问在入队时已法子化,但 log_msg_buffer 仍需拷贝 payload。这是为了确保业务线程开释原始字符串后,后台线程仍能安全访谒日记内容。
一致性 vs 可用性enum class async_overflow_policy {
block, // 阻塞直到有空间(强一致性)
overrun_oldest, // 秘密最旧音问(高可用性)
discard_new // 丢弃新音问(低蔓延优先)
};
场景分析:
block:适用于审计日记,不成容忍丢失,但可能阻塞业务线程overrun_oldest:适用于监控日记,容忍丢失旧数据,保说明时性discard_new:适用于调试日记,部队满时丢弃新音问,幸免阻塞详尽进程 vs 天真性Sink 详尽层级:
sink (接口)
└─ base_sink (模板基类,提供线程安全)
├─ basic_file_sink (单文献)
├─ rotating_file_sink (滚动文献)
├─ daily_file_sink (按日历分割)
└─ stdout_sink (舍弃台)
蔓延机制:
自界说 Sink:接管 base_sink 并已毕 sink_it_ 和 flush_自界说 Formatter:接管 custom_flag_formatter 并注册到 pattern_formatter自界说不实处理:通过 set_error_handler 注册回调源码舆图spdlog-1.15.2/
├── include/spdlog/
│ ├── spdlog.h # 全局 API 进口,registry 访谒
│ ├── logger.h # 中枢 logger 类,同步日记已毕
│ ├── async_logger.h # 异步 logger,接管 logger
│ ├── formatter.h # 法子化器接口
│ ├── pattern_formatter.h # 默许法子化器已毕
│ ├── async.h # 异步工场函数
│ ├── common.h # 专家类型界说,编译设立
│ │ ├── thread_pool.h # 异步线程池
│ │ ├── mpmc_blocking_q.h # 多坐褥者多糟践者部队
│ │ ├── circular_q.h # 环形部队底层已毕
│ │ ├── log_msg.h # 日记音问结构
│ │ ├── log_msg_buffer.h # 带缓冲的音问,用于异步
│ │ └── file_helper.h # 文献操作缓助类
│ ├── base_sink.h # 线程安全模板基类
│ ├── basic_file_sink.h # 基础文献 Sink
│ ├── rotating_file_sink.h # 滚动文献 Sink
│ ├── daily_file_sink.h # 日历分割 Sink
│ ├── stdout_sinks.h # 舍弃台 Sink
│ └── dist_sink.h # 分发 Sink(多见解)
│ └── src/ ├── spdlog.cpp # 编译形状已毕
├── async.cpp # 异步干系已毕
└── bundled_fmtlib_format.cpp # fmt 库编译已毕
中枢文献解析:
logger.h :界说 logger 类,包含日记级别过滤、不实处理、sink 处分async_logger.h :重写 sink_it_ 和 flush_ ,将音问推送到线程池mpmc_blocking_q.h :中枢并发数据结构,决定异步性能上限pattern_formatter.h :法子化逻辑,时刻戳缓存优化registry.h :全局情状处分,logger 人命周期舍弃API 使用常用 API全局 API通过 spdlog:: 定名空间访谒
| logger->log(level, fmt, args...) | level: 日记级别 | 输出指定级别日记 | | logger->set_level(level) | level: 日记级别 | 缔造该 logger 的日记级别 | | logger->flush | 无 | 手动 flush 整个 sink | | logger->sinks | 无 | 复返 sink 列表援用,可动态添加 sink | | logger->set_formatter(formatter) | formatter: 法子化器指针 | 缔造自界说法子化器 | | logger->error_handler | 无 | 获恰当前不实处理器 | | logger->set_error_handler(handler) | handler: 不实处理函数 | 缔造不实处理回调 |
| spdlog::create_async(name, args...) | Sink: sink 类型,name: logger 称呼 | 创建异步 logger | | spdlog::init_thread_pool(q_size, n_threads) | q_size: 部队大小,n_threads: 线程数 | 启动化全局线程池 | | async_logger(logger_name, sink, tp, policy) | tp: 线程池,policy: 溢出计策 | 构造异步 logger |
样例 Demo以下示例展示无缺样例,包括不实处理、多 sink、异步形状和资源算帐:
#include # include # include # include # include # include # include class GameLogger { public: static bool Initialize { try { // Initialize thread pool with 8192 queue size and 1 worker thread spdlog::init_thread_pool(8192, 1); // Create console sink (stdout with color) auto console_sink = std::make_shared; console_sink->set_level(spdlog::level::debug); console_sink->set_pattern("[%Y-%m-%d %H:%M:%S.%e] [%^%l%$] [%t] %v"); // Create rotating file sink (5MB per file, max 3 files) auto file_sink = std::make_shared( "logs/game.log", 1024 *
file_sink->set_level(spdlog::level::info); file_sink->set_pattern("[%Y-%m-%d %H:%M:%S.%e] [%l] [%t] [%s:%#] %v"); // Combine sinks std::vector sinks{console_sink, file_sink}; // Create async logger auto logger = std::make_shared( "game_logger", sinks.begin, sinks.end, spdlog::thread_pool, spdlog::async_overflow_policy::block ); logger->set_level(spdlog::level::debug); logger->flush_on(spdlog::level::warn); // Set error handler logger->set_error_handler([](const std::string &msg) { std::cerr flush; }); // Release all loggers and stop threads spdlog::shutdown; } static void LogGameEvent(const std::string &event_name, int player_id, float value) { SPDLOG_INFO("GameEvent: {} [player={}, value={:.2f}]", event_name, player_id, value); } static void LogPerformanceMetric(const std::string &metric, double ms) { if (ms > 16.67) { // Below 60 FPS SPDLOG_WARN("Performance warning: {} took {:.2f}ms", metric, ms); } else { SPDLOG_DEBUG("Performance: {} = {:.2f}ms", metric, ms); } } };
int main { if (!GameLogger::Initialize) { return 1; } try { // Basic logging SPDLOG_INFO("Game started"); SPDLOG_DEBUG("Debug message (only visible in debug builds)"); // Formatted logging GameLogger::LogGameEvent("PlayerJump", 12345, 98.5f); GameLogger::LogPerformanceMetric("RenderFrame", 14.2); GameLogger::LogPerformanceMetric("PhysicsUpdate", 18.5); // Error handling SPDLOG_ERROR("Simulated error with code {}", 404); // Flush manually spdlog::default_logger->flush; } catch (const std::exception &ex) { SPDLOG_CRITICAL("Exception: {}", ex.what); GameLogger::Shutdown; return 1; } GameLogger::Shutdown; return 0; }
关键工程执行:
启动化轨则:先启动化线程池,再创建 logger,终末注册不实处理:拿获 spdlog::spdlog_ex 非常,缔造不实处理器资源算帐: shutdown 必须调用,不然异步线程不会罢手Flush 计策: flush_on(warn) 确保 warning 及以上司别立即写入Backtrace:存储最近 N 条日记,崩溃时 dump 用于调试场景残忍设立处分// config/logger_config.h
struct LoggerConfig {
std::string log_file_path = "logs/app.log";
size_t max_file_size = 5 *
int max_files = 3; spdlog::level::level_enum level = spdlog::level::info; bool async_mode = true; size_t queue_size = 8192; std::string pattern = "[%Y-%m-%d %H:%M:%S.%e] [%l] [%t] %v"; static LoggerConfig LoadFromFile(const std::string &config_path); };
日记跟踪// Use MDC (Mapped Diagnostic Context) for request tracing
#include void HandleHttpRequest(const HttpRequest &req) { // Set trace ID for all logs in this scope spdlog::mdc::put("trace_id", req.trace_id); spdlog::mdc::put("user_id", std::to_string(req.user_id)); SPDLOG_INFO("Processing request"); // ... business logic ... spdlog::mdc::remove("trace_id"); spdlog::mdc::remove("user_id"); }
// Custom formatter with MDC support // Pattern: [%Y-%m-%d %H:%M:%S.%e] [%l] [trace:%X{trace_id}] %v
性能调优// Monitor async queue health
void MonitorLoggerQueue {
auto tp = spdlog::thread_pool;
if (tp) {
size_t overrun = tp->overrun_counter;
size_t discard = tp->discard_counter;
size_t queue_size = tp->queue_size;
if (overrun > 0 2026年世界杯官网