如何在Boost Log自定义格式化器中访问add_common_attributes()添加的属性?
Boost Log自定义格式化器访问公共属性问题解决
问题背景
原本使用Boost Log的默认格式化配置时,通过add_common_attributes()添加的TimeStamp、ThreadID等属性可以正常输出,日志格式如下:
[2023-01-31 08:08:13.300149] [0x00007f66a048d000] [info] My message
但切换为自定义着色格式化器后,无法正确访问这些公共属性,最终仅输出: My message,核心问题出在属性提取的类型匹配和访问方式上。
原自定义格式化器代码存在的问题:
void coloring_formatter(const boost::log::record_view& record, boost::log::formatting_ostream& stream) { auto severity = record[boost::log::trivial::severity]; assert(severity); switch (severity.get()) { case boost::log::trivial::severity_level::trace: stream << "\e[97m"; break; case boost::log::trivial::severity_level::debug: stream << "\e[34m"; break; case boost::log::trivial::severity_level::info: stream << "\e[32m"; break; case boost::log::trivial::severity_level::warning: stream << "\e[93m"; break; case boost::log::trivial::severity_level::error: stream << "\e[91m"; break; case boost::log::trivial::severity_level::fatal: stream << "\e[41m"; break; } stream /* << boost::log::extract<boost::posix_time::ptime>("TimeStamp", record) << ": " */ // 编译失败 << boost::log::extract<unsigned int>("ThreadID", record) << ": " // 提取为空 << record[boost::log::expressions::message]; // 仅该部分正常工作 if (severity) { stream << "\033[0m"; } }
解决方法
1. 匹配正确的属性类型
add_common_attributes()添加的属性有固定类型,错误的类型会导致提取失败或编译错误:
TimeStamp:类型为boost::posix_time::ptime(对应Boost版本的本地时钟值类型)ThreadID:类型为boost::log::attributes::current_thread_id::value_type(本质是平台相关的线程ID类型,如pthread_t或std::thread::id,而非unsigned int)
2. 安全提取属性并输出
使用boost::log::extract或直接通过record[]访问属性时,需先检查属性是否存在,避免空输出。以下是修正后的格式化器代码:
#include <boost/log/attributes/current_thread_id.hpp> #include <boost/log/attributes/local_clock.hpp> void coloring_formatter(const boost::log::record_view& record, boost::log::formatting_ostream& stream) { auto severity = record[boost::log::trivial::severity]; assert(severity); // 根据日志级别设置终端颜色 switch (severity.get()) { case boost::log::trivial::trace: stream << "\e[97m"; break; case boost::log::trivial::debug: stream << "\e[34m"; break; case boost::log::trivial::info: stream << "\e[32m"; break; case boost::log::trivial::warning: stream << "\e[93m"; break; case boost::log::trivial::error: stream << "\e[91m"; break; case boost::log::trivial::fatal: stream << "\e[41m"; break; } // 提取并输出TimeStamp auto timestamp = boost::log::extract<boost::posix_time::ptime>("TimeStamp", record); if (timestamp) { stream << "[" << *timestamp << "] "; } // 提取并输出ThreadID using thread_id_type = boost::log::attributes::current_thread_id::value_type; auto thread_id = boost::log::extract<thread_id_type>("ThreadID", record); if (thread_id) { stream << "[" << *thread_id << "] "; } // 输出日志级别和消息 stream << "[" << severity << "] " << record[boost::log::expressions::message]; // 重置终端颜色 stream << "\033[0m"; }
3. 简化的属性访问方式
也可以直接通过属性名称的关键字访问,代码更简洁:
// 访问TimeStamp auto timestamp = record[boost::log::attributes::local_clock::get_name()]; if (timestamp) { stream << "[" << timestamp << "] "; } // 访问ThreadID auto thread_id = record[boost::log::attributes::current_thread_id::get_name()]; if (thread_id) { stream << "[" << thread_id << "] "; }
修正后,日志输出会恢复原有的TimeStamp、ThreadID字段,并根据级别显示对应颜色。
内容的提问来源于stack exchange,提问作者Dominic
相关产品推荐
相关产品推荐

