You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何避免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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 15:25:24