当前位置: 首页 > 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_向量中,以便在记录日志消息时使用。

http://www.xdnf.cn/news/399223.html

相关文章:

  • Java详解LeetCode 热题 100(14):LeetCode 56. 合并区间(Merge Intervals)详解
  • 【网络安全】SQL注入
  • pdf 不是扫描件,但却无法搜索关键词【问题尝试解决未果记录】
  • 用短说社区搭建的沉浸式生活方式分享平台
  • Redis+Caffeine构建高性能二级缓存
  • Python邮件处理(使用imaplib和email库实现自动化邮件处理)
  • Kubernetes控制平面组件:Kubelet详解(一):API接口层介绍
  • 自主添加删除开机启动项
  • tinyint(3)数据类型讲解
  • stm32之BKP备份寄存器和RTC时钟
  • 基于Python的高效批量处理Splunk Session ID并写入MySQL的解决方案
  • Hadoop 的代理用户(Proxy User)​ 功能解释
  • 配置hosts
  • 推理加速新范式:火山引擎高性能分布式 KVCache (EIC)核心技术解读
  • 深入理解Embedding Models(嵌入模型):从原理到实战(下)
  • 【机器人】复现 UniGoal 具身导航 | 通用零样本目标导航 CVPR 2025
  • SpringBoot校园失物招领信息平台
  • Shell脚本编程3(函数+正则表达式)
  • [特殊字符] 本地大模型编程实战(29):用大语言模型LLM查询图数据库NEO4J(2)
  • Modbus协议介绍
  • springboot旅游小程序-计算机毕业设计源码76696
  • Unity ML-Agents实战指南:构建多技能游戏AI训练系统
  • 在Ubuntu系统下编译OpenCV 4.8源码
  • react-diff-viewer 如何实现语法高亮
  • 一小时学会Docker使用!
  • 树莓派4基于Debian GNU/Linux 12 (Bookworm)开启VNC,使用MobaXterm连接VNC出现黑屏/灰屏问题
  • 笔记本电脑升级实战手册【扩展篇1】:flash id查询硬盘颗粒
  • 十四、继承与组合(Inheritance Composition)
  • 【Linux网络编程】HTTPS协议原理
  • 杨校老师项目之基于SSM与JSP的鲜花销售系统-【成品设计含文档】