【问题标题】:How can I set a severity level per log source with Boost log?如何使用 Boost 日志为每个日志源设置严重性级别?
【发布时间】:2017-08-24 09:12:59
【问题描述】:

我是 Boost Log 的新手,在做一些非常简单的事情时遇到了麻烦。 我正在尝试创建一个记录器并为其分配一个级别(例如警告、信息、跟踪等),并过滤掉(出于性能原因)发送到此记录器的任何日志,并且分配给logger,在 Logging 核心级别,而不是在 sink 级别。 例如(伪代码):

logger lg;
lg.setLevel(Warn);
BOOST_LOG_TRIVIAL(trace) << "A trace severity message"; // Will be filtered
BOOST_LOG_TRIVIAL(warn) << "A warning severity message"; // Won't be filtered

我很确定这可以通过 Boost Log 实现,但由于某种原因我无法做到这一点。

谢谢,

奥马尔。

【问题讨论】:

    标签: c++ logging boost boost-log


    【解决方案1】:

    Boost.Log 中的记录器(源)级别没有过滤器。您可以全局(在日志核心中)或每个接收器设置过滤器,所有来源的日志记录将被统一处理。

    您可以使用channels 实现您想要的行为,方法是为每个记录器分配一个通道并根据通道和严重性级别进行过滤。

    BOOST_LOG_ATTRIBUTE_KEYWORD(a_severity, "Severity", LogSeverity)
    BOOST_LOG_ATTRIBUTE_KEYWORD(a_channel, "Channel", std::string)
    
    typedef sources::severity_channel_logger< LogSeverity, std::string > logger_type;
    
    logger_type lg_a(keywords::channel = "A");
    logger_type lg_b(keywords::channel = "B");
    
    core::get()->set_filter
    (
        (a_channel == "A" && a_severity >= LogSeverity::info) ||
        (a_channel == "B" && a_severity >= LogSeverity::warning)
    );
    

    该库还提供了a specialized filter,可用于简化此操作。

    auto min_severity = expressions::channel_severity_filter(a_channel, a_severity);
    min_severity["A"] = LogSeverity::info;
    min_severity["B"] = LogSeverity::warning;
    
    core::get()->set_filter(min_severity);
    

    请注意,您实际上并不仅限于每个通道只有一个记录器 - 您可以创建多个记录器,并且每个通道的日志记录将被以相同的方式处理。

    【讨论】:

    • 感谢安德烈的回答!每条记录在到达接收器之前是否在 Logging 核心中经过大量处理?这是否意味着如果我每个通道有多个接收器,则上面的过滤器将应用于每个接收器,或者我可以将其全局应用于与通道相关的所有接收器?
    • 在过滤阶段,除了过滤器,没有任何记录处理。所有其他处理,包括日志消息组合,都发生在至少一个接收器接受记录之后(即通过此接收器的过滤)。首先应用全局过滤器,然后依次应用特定于接收器的过滤器。因此,在我的示例中,过滤器是全局的,并且无论接收器如何,每条记录仅应用一次。如果您设置了特定于接收器的过滤器,那么每个这样的过滤器将在每条通过全局过滤器的记录中应用一次。
    • 感谢您的评论!但是Andrey,恐怕Boost.Log丰富的功能集和灵活性可能会对性能造成很大影响(我的项目涉及高速数据包处理,因此性能是至关重要的要求)。是否进行了任何性能测试,甚至更好,与其他 C++ 日志框架进行性能比较?提前致谢!
    • 我没有进行任何比较,但是您可以搜索网络。您可以在库中进行一些性能测试。
    【解决方案2】:

    我建议你使用this link作为参考...

    下面是我的代码的一个小sn-p。在这个小型 sn-p 中,我使用了同步后端,但您可以随意使用异步后端。

    log.hpp

    #pragma once
    
    #include <boost/log/common.hpp>
    #include <boost/log/sources/severity_logger.hpp>
    
    enum class LogSeverity {
        trace, debug, info, warning, error, fatal
    };
    
    extern boost::log::sources::severity_logger<LogSeverity> g_logger;
    
    void log_set_filter(LogSeverity level);
    void init_logger();
    
    #define LOG_TRACE   BOOST_LOG_SEV(g_logger, LogSeverity::trace)
    #define LOG_DEBUG   BOOST_LOG_SEV(g_logger, LogSeverity::debug)
    #define LOG_INFO    BOOST_LOG_SEV(g_logger, LogSeverity::info)
    #define LOG_WARNING BOOST_LOG_SEV(g_logger, LogSeverity::warning)
    #define LOG_ERROR   BOOST_LOG_SEV(g_logger, LogSeverity::error)
    #define LOG_FATAL   BOOST_LOG_SEV(g_logger, LogSeverity::fatal)
    

    log.cpp

    #include "bumper-common/log.hpp"
    #include <boost/log/common.hpp>
    #include <boost/log/sources/severity_logger.hpp>
    #include <boost/log/sinks/sync_frontend.hpp>
    #include <boost/log/sinks/text_ostream_backend.hpp>
    #include <boost/log/core.hpp>
    #include <boost/log/expressions.hpp>
    #include <boost/log/attributes.hpp>
    #include <boost/log/utility/setup/common_attributes.hpp>
    #include <boost/log/support/date_time.hpp>
    #include <boost/core/null_deleter.hpp>
    #include <iomanip>
    #include <iostream>
    
    using namespace boost::log;
    
    using LogTextSink = sinks::synchronous_sink<sinks::text_ostream_backend>;
    
    LogSeverity g_logLevel = LogSeverity::info;
    sources::severity_logger<LogSeverity> g_logger;
    
    BOOST_LOG_ATTRIBUTE_KEYWORD(severity, "Severity", LogSeverity)
    BOOST_LOG_ATTRIBUTE_KEYWORD(timestamp, "TimeStamp", boost::posix_time::ptime)
    BOOST_LOG_ATTRIBUTE_KEYWORD(log_thread_id, "ThreadID", attributes::current_thread_id::value_type)
    
    std::ostream& operator<< (std::ostream& strm, LogSeverity level)
    {
        static const std::array<std::string, 6> strings
        {
            std::string{"trace"},
            std::string{"debug"},
            std::string{"info"},
            std::string{"warn"},
            std::string{"error"},
            std::string{"fatal"}
        };
    
        strm << strings[static_cast< std::size_t >(level)];
    
        return strm;
    }
    
    void init_logger()
    {
        boost::shared_ptr<std::ostream> stream{&std::cout,
            boost::null_deleter{}};
    
        auto loggerSink = boost::make_shared<LogTextSink>();
    
        add_common_attributes();
    
        loggerSink->locked_backend()->add_stream(stream);
        loggerSink->locked_backend()->auto_flush(true);
    
        loggerSink->set_filter(severity >= g_logLevel);
    
        loggerSink->set_formatter( expressions::stream
            << "[" << expressions::format_date_time(timestamp, "%H:%M:%S.%f") << "] ["
            << std::setw(5) << std::left << severity << "] ["
            << log_thread_id << "] "
            << expressions::smessage
        );
    
        boost::log::core::get()->add_sink(loggerSink);
    }
    
    void log_set_filter(LogSeverity level)
    {
        g_logLevel = level;
    }
    

    希望这可以帮助你。我对这个图书馆很困扰。所以我强烈建议您阅读我之前发布的文档。

    【讨论】:

    • 感谢您的回答!如果我正确理解了您的代码 sn-p,则级别过滤是在接收器级别完成的 (loggerSink->set_filter(severity >= g_logLevel);)。有没有办法在日志核心级别进行此过滤?性能对我来说非常重要,我想尽早过滤掉日志。
    • @omer 我在这里问过同样的问题:stackoverflow.com/questions/16102128/…
    • 如果速度很关键,请考虑使用其他日志库:github.com/gabime/spdlog 或类似的
    • 这是完全相同的问题,因为我的目标是创建具有不同级别的不同记录器,并且在您的情况下,所有记录器都具有相同的级别。关于性能,我正在寻找一个在功能集和性能之间具有良好平衡的库,因此它不必是最快的库,只需一个不需要太多处理即可决定是否应该记录日志记录的库处理与否。
    • 如果您查看我的回复,您就会得到问题的答案:logging::core::get()-&gt;set_filter ( logging::trivial::severity &gt;= logging::trivial::info );
    猜你喜欢
    • 2021-12-26
    • 2023-03-15
    • 1970-01-01
    • 2023-04-07
    • 1970-01-01
    • 1970-01-01
    • 2015-12-17
    • 2022-10-17
    • 2020-05-11
    相关资源
    最近更新 更多