当前位置: 首页 > news >正文

spdlog日志格式化 标志全指南

一、spdlog格式化核心机制

SPDLOG通过set_pattern()函数实现灵活的日志格式定制,该函数解析用户提供的格式字符串,生成包含时间、源代码、进程等信息的结构化日志。其底层由pattern_formatter类处理,通过识别%+标志符的组合动态生成格式化器对象。


二、格式化标志全集(按功能分类)

  1. ​时间与日期​

    标志描述示例输出
    %c标准日期时间Tue Apr 23 00:00:17 2024
    %x短日期 (MM/DD/YY)04/23/24
    %H24小时制小时14
    %M分钟05
    %S30
    %e毫秒981
    %F纳秒123456789
    %z时区+0800
  2. ​进程与线程​

    标志描述示例输出
    %P进程ID22588
    %t线程ID22600
  3. ​源代码定位​

    标志描述示例输出
    %g完整源文件路径/home/user/src/main.cpp
    %s短文件名main.cpp
    %#行号415
    %!函数名UploadStatusData(...)
  4. ​日志级别与消息​

    标志描述示例输出
    %l日志级别[debug]
    %v原始消息内容data_period=20240423
  5. ​高级功能​

    标志描述
    %^颜色范围开始 (需终端支持)
    %$颜色范围结束
    %u距离上条日志的纳秒间隔
    %i微秒间隔

三、实战格式示例

// 包含进程、线程、时间、源码、消息的完整格式
my_logger->set_pattern("%^[%c|%x|ms:%e][%l] ""[P:%P|t:%t][Code:%g:%#|%!] %v%$"
);

输出效果:

[Tue Apr 23 00:00:17 2024|04/23/24|ms:981][debug] 
[P:22588|t:22600][Code:/src/main.cpp:415|UploadStatusData] device_type=YWIND00

四、工作机制详解

  1. 格式解析流程
    set_pattern()将字符串拆解为%+标志符的标记。

    • 每个标记触发pattern_formatter::handle_flag_()生成对应的格式化器(如%g生成源文件格式化器)。

    • 格式化器存入队列,日志输出时按序拼接信息。

  2. 时间处理优化
    need_localtime_标志控制是否使用本地时间(默认启用),多时区场景需显式设置时区格式%z


五、高级定制技巧

自定义格式器:继承custom_flag_formatter实现format()接口,通过add_flag()注册到日志器。

动态字段截断:使用%10!格式将函数名截断至10字符,避免过长的日志行。


六、注意事项

性能影响:启用源码定位(%#, %!)会轻微降低性能,建议在调试时使用。

线程安全daily_logger_mt为多线程安全,单线程环境使用_st后缀版本。

通过合理组合格式化标志,开发者可生成适应复杂调试、生产监控等多场景的高效日志系统,实现堪比断点调试的代码追踪能力。

附注源码:

这段代码是SPDLOG日志库的源代码的一部分,具体是格式化日志消息的pattern_formatter类的成员函数handle_flag_

具体的源码如下:路径为:usr->local->include->spdlog->pattern_formatter-inl.h->{}spdlog->handle_flag_(char,detailspadding info)


template<typename Padder>
SPDLOG_INLINE void pattern_formatter::handle_flag_(char flag, details::padding_info padding)
{// process custom flagsauto it = custom_handlers_.find(flag);if (it != custom_handlers_.end()){auto custom_handler = it->second->clone();custom_handler->set_padding_info(padding);formatters_.push_back(std::move(custom_handler));return;}// process built-in flagsswitch (flag){case ('+'): // default formatterformatters_.push_back(details::make_unique<details::full_formatter>(padding));need_localtime_ = true;break;case 'n': // logger nameformatters_.push_back(details::make_unique<details::name_formatter<Padder>>(padding));break;case 'l': // levelformatters_.push_back(details::make_unique<details::level_formatter<Padder>>(padding));break;case 'L': // short levelformatters_.push_back(details::make_unique<details::short_level_formatter<Padder>>(padding));break;case ('t'): // thread idformatters_.push_back(details::make_unique<details::t_formatter<Padder>>(padding));break;case ('v'): // the message textformatters_.push_back(details::make_unique<details::v_formatter<Padder>>(padding));break;case ('a'): // weekdayformatters_.push_back(details::make_unique<details::a_formatter<Padder>>(padding));need_localtime_ = true;break;case ('A'): // short weekdayformatters_.push_back(details::make_unique<details::A_formatter<Padder>>(padding));need_localtime_ = true;break;case ('b'):case ('h'): // monthformatters_.push_back(details::make_unique<details::b_formatter<Padder>>(padding));need_localtime_ = true;break;case ('B'): // short monthformatters_.push_back(details::make_unique<details::B_formatter<Padder>>(padding));need_localtime_ = true;break;case ('c'): // datetimeformatters_.push_back(details::make_unique<details::c_formatter<Padder>>(padding));need_localtime_ = true;break;case ('C'): // year 2 digitsformatters_.push_back(details::make_unique<details::C_formatter<Padder>>(padding));need_localtime_ = true;break;case ('Y'): // year 4 digitsformatters_.push_back(details::make_unique<details::Y_formatter<Padder>>(padding));need_localtime_ = true;break;case ('D'):case ('x'): // datetime MM/DD/YYformatters_.push_back(details::make_unique<details::D_formatter<Padder>>(padding));need_localtime_ = true;break;case ('m'): // month 1-12formatters_.push_back(details::make_unique<details::m_formatter<Padder>>(padding));need_localtime_ = true;break;case ('d'): // day of month 1-31formatters_.push_back(details::make_unique<details::d_formatter<Padder>>(padding));need_localtime_ = true;break;case ('H'): // hours 24formatters_.push_back(details::make_unique<details::H_formatter<Padder>>(padding));need_localtime_ = true;break;case ('I'): // hours 12formatters_.push_back(details::make_unique<details::I_formatter<Padder>>(padding));need_localtime_ = true;break;case ('M'): // minutesformatters_.push_back(details::make_unique<details::M_formatter<Padder>>(padding));need_localtime_ = true;break;case ('S'): // secondsformatters_.push_back(details::make_unique<details::S_formatter<Padder>>(padding));need_localtime_ = true;break;case ('e'): // millisecondsformatters_.push_back(details::make_unique<details::e_formatter<Padder>>(padding));break;case ('f'): // microsecondsformatters_.push_back(details::make_unique<details::f_formatter<Padder>>(padding));break;case ('F'): // nanosecondsformatters_.push_back(details::make_unique<details::F_formatter<Padder>>(padding));break;case ('E'): // seconds since epochformatters_.push_back(details::make_unique<details::E_formatter<Padder>>(padding));break;case ('p'): // am/pmformatters_.push_back(details::make_unique<details::p_formatter<Padder>>(padding));need_localtime_ = true;break;case ('r'): // 12 hour clock 02:55:02 pmformatters_.push_back(details::make_unique<details::r_formatter<Padder>>(padding));need_localtime_ = true;break;case ('R'): // 24-hour HH:MM timeformatters_.push_back(details::make_unique<details::R_formatter<Padder>>(padding));need_localtime_ = true;break;case ('T'):case ('X'): // ISO 8601 time format (HH:MM:SS)formatters_.push_back(details::make_unique<details::T_formatter<Padder>>(padding));need_localtime_ = true;break;case ('z'): // timezoneformatters_.push_back(details::make_unique<details::z_formatter<Padder>>(padding));need_localtime_ = true;break;case ('P'): // pidformatters_.push_back(details::make_unique<details::pid_formatter<Padder>>(padding));break;case ('^'): // color range startformatters_.push_back(details::make_unique<details::color_start_formatter>(padding));break;case ('$'): // color range endformatters_.push_back(details::make_unique<details::color_stop_formatter>(padding));break;case ('@'): // source location (filename:filenumber)formatters_.push_back(details::make_unique<details::source_location_formatter<Padder>>(padding));break;case ('s'): // short source filename - without directory nameformatters_.push_back(details::make_unique<details::short_filename_formatter<Padder>>(padding));break;case ('g'): // full source filenameformatters_.push_back(details::make_unique<details::source_filename_formatter<Padder>>(padding));break;case ('#'): // source line numberformatters_.push_back(details::make_unique<details::source_linenum_formatter<Padder>>(padding));break;case ('!'): // source funcnameformatters_.push_back(details::make_unique<details::source_funcname_formatter<Padder>>(padding));break;case ('%'): // % charformatters_.push_back(details::make_unique<details::ch_formatter>('%'));break;case ('u'): // elapsed time since last log message in nanosformatters_.push_back(details::make_unique<details::elapsed_formatter<Padder, std::chrono::nanoseconds>>(padding));break;case ('i'): // elapsed time since last log message in microsformatters_.push_back(details::make_unique<details::elapsed_formatter<Padder, std::chrono::microseconds>>(padding));break;case ('o'): // elapsed time since last log message in millisformatters_.push_back(details::make_unique<details::elapsed_formatter<Padder, std::chrono::milliseconds>>(padding));break;case ('O'): // elapsed time since last log message in secondsformatters_.push_back(details::make_unique<details::elapsed_formatter<Padder, std::chrono::seconds>>(padding));break;default: // Unknown flag appears as isauto unknown_flag = details::make_unique<details::aggregate_formatter>();if (!padding.truncate_){unknown_flag->add_ch('%');unknown_flag->add_ch(flag);formatters_.push_back((std::move(unknown_flag)));}// fix issue #1617 (prev char was '!' and should have been treated as funcname flag instead of truncating flag)// spdlog::set_pattern("[%10!] %v") => "[      main] some message"// spdlog::set_pattern("[%3!!] %v") => "[mai] some message"else{padding.truncate_ = false;formatters_.push_back(details::make_unique<details::source_funcname_formatter<Padder>>(padding));unknown_flag->add_ch(flag);formatters_.push_back((std::move(unknown_flag)));}break;}
}

这段代码是SPDLOG日志库的源代码的一部分,具体是格式化日志消息的pattern_formatter类的成员函数handle_flag_

这个函数负责处理日志格式字符串中的各种标志。根据不同的标志,它会创建不同的格式化对象,并将这些对象添加到formatters_向量中。这些格式化对象会在日志消息被记录时用于格式化消息。

例如,如果标志是'%',则函数会创建一个percent_formatter对象;如果标志是'n',则函数会创建一个logger_name_formatter对象;如果标志是'd',则函数会创建一个date_formatter对象等等。这些格式化对象都是formatter类的派生类,它们实现了format函数,该函数用于将日志消息的特定部分格式化为字符串。

此外,函数还处理一些其他标志,例如'+',它会设置默认的格式化器;'-',它会取消设置默认的格式化器;'#',它会在日志消息中包含源代码文件的行号;'&',它会在日志消息中包含当前运行的线程ID;'@',它会在日志消息中包含源代码文件的名称。

总之,这个函数负责根据日志格式字符串中的标志创建适当的格式化对象,并将这些对象添加到formatters_向量中,以便在记录日志消息时使用。

相关文章:

  • GPT系列:自然语言处理的演进与多模态的探索
  • 从规划到完善,原型标注图全流程设计
  • 2025年渗透测试面试题总结-渗透测试红队面试八(题目+回答)
  • Spring Boot 参数验证
  • MySQL性能调优探秘:我的实战笔记 (下篇:深入内核、锁与监控)
  • 基于STM32、HAL库的BME680气压传感器 驱动程序设计
  • 【题解-洛谷】B3881 [信息与未来 2015] 拴奶牛
  • 免费Office图片音频高效提取利器
  • Autoregressive Distillation of Diffusion Transformers
  • (自用)Java学习-5.8(总结,springboot)
  • css 点击后改变样式
  • SAGAR线上网页程序生成准随机结构(SQS)
  • Vue学习百日计划-Deepseek版
  • CRM和SCRM有什么区别
  • 【HTOP 使用指南】:如何理解主从线程?(以 Faster-LIO 为例)
  • 接口出现 请求参数格式错误 的解决方法
  • 02.Golang 切片(slice)源码分析(一、定义与基础操作实现)
  • 流体力学绪论(期末复习)
  • LVGL(线条控件lv_line)
  • cursor 出现问题 为客户解决问题
  • 习近平出席中拉论坛第四届部长级会议开幕式并发表主旨讲话
  • 牛市早报|中美日内瓦经贸会谈联合声明公布
  • 中美发布日内瓦经贸会谈联合声明达成关税共识,外交部回应
  • 中国科学院院士徐春明不再担任山东石油化工学院校长
  • 为证明我爸是我爸,我将奶奶告上法庭
  • 外交部:习近平主席同普京总统达成许多新的重要共识