如何避免Boost Log日志消息重复?自定义标签过滤问题
日志过滤规则重复问题的解决方法
问题背景
我在代码中使用不同标签(如database.message、database.odbc、event.cevent等)记录不同类别的日志,同时读取JSON配置文件获取各标签对应的日志级别过滤规则:
{ "database" : { "message": "INFO", "odbc": "DEBUG", }, "event" : { "cevent" : "INFO", }, }
需求是为未在JSON中配置的标签设置基础过滤规则(仅记录INFO及以上级别日志)。
当前为每个配置的标签单独添加Sink实现规则:
logging::core::get()->add_global_attribute("Tag", attrs::constant<std::string>("")); logging::add_common_attributes(); std::vector<std::string> tags; // 假设已从JSON中填充所有配置的标签 ... for (const auto& tag :tags) { boost::shared_ptr<text_sink> sink(new text_sink(backend)); // 同文档示例 auto level = logging::trivial::info; // 示例级别,实际从JSON读取 sink->set_filter(expr::attr<std::string>("Tag") == tag && expr::attr<logging::trivial::severity_level>("Severity") >= level); logging::core::get()->add_sink(sink); }
这段代码能正常按JSON配置过滤日志,但添加基础规则时出现重复日志:
boost::shared_ptr<text_sink> basic_sink(new text_sink(backend)); auto filter = logging::trivial::severity >= logging::trivial::info; for (const auto& tag : tags) { filter = filter && expr::attr<std::string>("Tag") != tag; } basic_sink->set_filter(filter); logging::core::get()->add_sink(basic_sink);
原本以为基础Sink会过滤掉已配置的标签,但实际导致已配置标签的日志重复输出,求解决办法。
解决方案
核心思路:用单个Sink+复合过滤规则替代多Sink
问题根源在于每个Sink会独立处理匹配的日志,已配置标签的日志会同时命中对应标签Sink和基础Sink。更高效的方式是把所有过滤规则整合到同一个Sink中,从根源避免重复处理。
实现方式1:构建复合过滤规则
logging::core::get()->add_global_attribute("Tag", attrs::constant<std::string>("")); logging::add_common_attributes(); // 存储从JSON读取的标签-级别映射 std::vector<std::pair<std::string, logging::trivial::severity_level>> tag_rules; // 创建单个Sink boost::shared_ptr<text_sink> sink(new text_sink(backend)); // 构建复合过滤规则 expr::filter filter; // 添加已配置标签的规则:匹配标签且级别达标 for (const auto& rule : tag_rules) { auto tag_filter = expr::attr<std::string>("Tag") == rule.first && expr::attr<logging::trivial::severity_level>("Severity") >= rule.second; filter = filter || tag_filter; } // 添加基础规则:未匹配任何已配置标签,且级别>=INFO auto basic_filter = expr::attr<logging::trivial::severity_level>("Severity") >= logging::trivial::info; for (const auto& rule : tag_rules) { basic_filter = basic_filter && expr::attr<std::string>("Tag") != rule.first; } filter = filter || basic_filter; // 设置Sink的过滤规则 sink->set_filter(filter); logging::core::get()->add_sink(sink);
实现方式2:用bind动态获取标签级别(更简洁)
利用Boost Log的bind功能,直接通过函数动态匹配标签对应的级别:
// 定义根据标签获取对应级别的函数(从JSON配置读取) logging::trivial::severity_level get_tag_level(const std::string& tag) { static const std::map<std::string, logging::trivial::severity_level> config = { {"database.message", logging::trivial::info}, {"database.odbc", logging::trivial::debug}, {"event.cevent", logging::trivial::info} }; auto it = config.find(tag); return it != config.end() ? it->second : logging::trivial::info; } // 构建过滤规则:日志级别 >= 该标签对应的级别 auto filter = expr::attr<logging::trivial::severity_level>("Severity") >= expr::bind(&get_tag_level, expr::attr<std::string>("Tag")); boost::shared_ptr<text_sink> sink(new text_sink(backend)); sink->set_filter(filter); logging::core::get()->add_sink(sink);
这种方式无需拆分多个规则,代码更简洁,同时彻底避免多Sink导致的重复日志问题。
内容的提问来源于stack exchange,提问作者Forague
相关产品推荐
相关产品推荐

