2017-08-24 165 views
0

我是Boost Log的新手,并且遇到了一些非常简单的问题。 我正在尝试创建一个记录器并为其分配一个级别(例如警告,信息,跟踪等),并过滤掉(出于性能原因)发送到该记录器的任何日志,并将其分配给记录器处于日志记录核心级别,而不是接收器级别。 例如(伪代码):如何使用Boost日志为每个日志源设置严重级别?

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 

我敢肯定,这可以加速日志来实现,但由于某些原因,我没能做到这一点。

谢谢,

奥默尔。

回答

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); 

注意,你实际上并不局限于每个通道只有一个记录 - 你可以创建多者和日志记录每个将被视为相同的方式。

+0

感谢您的回答Andrey! 在进入接收器之前,每个记录是否在Logging核心中进行实质性处理? 这是否意味着如果每个通道有多个接收器,上面的过滤器将应用于每个接收器,还是我可以将它全局应用于与通道相关的所有接收器? – omer

+0

在过滤阶段,除了过滤器外,没有记录处理。所有其他处理(包括日志消息组成)在至少一个接收器接受记录(即通过该接收器的过滤)后发生。首先应用全局滤波器,然后依次应用接收器专用滤波器。所以在我的例子中,过滤器是全球性的,并且无论接收器如何,每个记录应用一次。如果您设置接收器特定的过滤器,那么每个通过全局过滤器*的记录*将应用一次这样的过滤器。 –

+0

感谢您的评论!但安德烈恐怕丰富的功能和Boost.Log的灵活性可能会对性能造成严重影响(我的项目涉及高速率数据包处理,所以性能是一个至关重要的要求)。有没有进行任何性能测试,甚至更好,与其他C++日志框架进行性能比较? 在此先感谢! – omer

1

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

这里低于我的一小段代码。在这个小片段中,我使用了一个同步后端,但您可以自由使用异步后端。

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; 
} 

希望这可以帮助你。我对这个库感到困扰很多。所以我强烈建议你阅读我之前发布的文档。

+0

感谢您的回答! 如果我正确理解了您的代码片段,则会在接收器级别完成级别筛选(loggerSink-> set_filter(severity> = g_logLevel);)。有没有办法在日志核心级别执行此过滤器?性能对我来说非常重要,我希望尽早过滤掉日志。 – omer

+0

@omer我在这里问过同样的问题:https://stackoverflow.com/questions/16102128/how-to-redirect-boost-log-to-file –

+0

如果速度很关键考虑使用其他日志库:https ://github.com/gabime/spdlog或者类似的 –