如何在boost::log单个Sink上配置多个过滤器?
问题描述
我在使用Boost Log的Sink记录日志时,希望为每个自定义Tag设置不同的日志级别。原本尝试单独为每个Tag设置过滤器:
sink->set_filter(logging::trivial::severity >= logging::trivial::warning && expr::attr<std::string>("Tag") == tag); [...] sink->set_filter(logging::trivial::severity >= logging::trivial::warning && expr::attr<std::string>("Tag") == tag1);
但每次调用set_filter都会覆盖之前的配置,导致只有最后一个Tag的过滤规则生效。当前遍历JSON配置树时,每处理一个叶子节点就直接覆盖Sink的过滤器,代码如下:
void setSinks() { logging::core::get()->add_global_attribute("Tag", attrs::mutable_constant<std::string>("")); std::string path = "..../log_config.json"; [def of sink...] pt::ptree root; pt::read_json(path, root); std::function<void(pt::ptree, std::string)> parse_tree; auto setFilter = [](std::string tag, std::string logLevel) { logging::trivial::severity_level level; if (logLevel == "TRACE") level = logging::trivial::trace; else if (logLevel == "DEBUG") level = logging::trivial::debug; else if (logLevel == "INFO") level = logging::trivial::info; else if (logLevel == "WARNING") level = logging::trivial::warning; else if (logLevel == "ERROR") level = logging::trivial::error; else if (logLevel == "FATAL") level = logging::trivial::fatal; else level = logging::trivial::debug; return logging::trivial::severity >= level && expr::attr<std::string>("Tag") == tag; }; parse_tree = [&sink, &setFilter, &parse_tree](pt::ptree tree, std::string tag) { for (const auto& v : tree) { std::string name = v.first; pt::ptree value = v.second; if (value.empty()) { sink->set_filter(setFilter(tag + "." + name, value.data())); } else { parse_tree(value, (tag.empty() ? name : tag + "." + name)); } } }; parse_tree(root, ""); }
需要实现单个Sink上的多Tag过滤规则叠加。
解决思路
问题核心是每次调用set_filter会替换Sink的现有过滤器,而非叠加。正确的做法是将所有Tag的过滤条件用逻辑或(||)组合成一个复合表达式,最后一次性设置给Sink。
修改后的代码
void setSinks() { logging::core::get()->add_global_attribute("Tag", attrs::mutable_constant<std::string>("")); std::string path = "..../log_config.json"; [def of sink...] pt::ptree root; pt::read_json(path, root); // 初始化复合过滤器为"永远不匹配"的表达式 auto combined_filter = expr::false_expr(); auto setFilter = [](std::string tag, std::string logLevel) { logging::trivial::severity_level level; if (logLevel == "TRACE") level = logging::trivial::trace; else if (logLevel == "DEBUG") level = logging::trivial::debug; else if (logLevel == "INFO") level = logging::trivial::info; else if (logLevel == "WARNING") level = logging::trivial::warning; else if (logLevel == "ERROR") level = logging::trivial::error; else if (logLevel == "FATAL") level = logging::trivial::fatal; else level = logging::trivial::debug; return logging::trivial::severity >= level && expr::attr<std::string>("Tag") == tag; }; std::function<void(pt::ptree, std::string)> parse_tree; parse_tree = [&combined_filter, &setFilter, &parse_tree](pt::ptree tree, std::string tag) { for (const auto& v : tree) { std::string name = v.first; pt::ptree value = v.second; if (value.empty()) { // 将当前Tag的过滤条件与复合过滤器做逻辑或 combined_filter = combined_filter || setFilter(tag + "." + name, value.data()); } else { parse_tree(value, (tag.empty() ? name : tag + "." + name)); } } }; parse_tree(root, ""); // 最后一次性设置复合过滤器到Sink sink->set_filter(combined_filter); }
关键说明
- 初始化
combined_filter为expr::false_expr(),确保初始状态下没有日志会被匹配,后续逐步叠加规则。 - 遍历每个配置项时,用
||将当前Tag的过滤条件合并到combined_filter中,实现"满足任意一个Tag的规则即允许日志通过"的逻辑。 - 所有规则合并完成后,再调用一次
set_filter将复合表达式设置给Sink,避免每次覆盖。
内容的提问来源于stack exchange,提问作者Forague
相关产品推荐
相关产品推荐

