-->

使用Boost.Log的信道hiearchy为严重程度和过滤水槽使用Boost.Log的信道hiea

2019-05-12 05:50发布

我一直在研究Boost.Log了一段时间,我相信现在是时候让我从log4cxx转换我的代码基础,Boost.Log。 我相信Boost.Log的设计和实施,将显著改善我的代码维护和使用。 我知道Boost.Log常见问题有一个页面,上面写着

至于分级记录仪,也没有必要在当前库设计此功能。 它的一个在log4j的提供是确定(此库而言汇)在日志记录将结束的附加目的地的主要好处。 该库可通过过滤相同的结果。

我理解的概念等同,我不试图使Boost.Log到的log4j / log4cxx。 而是我的问题是:如何使用Boost.Log让我当前从log4cxx使用相同的功能? 具体地讲,我想设置严重性阈值和汇在日志源或信道层级特定节点。 举例来说,我已经通过登录组织来源libA.moduleB.componentC.logD在用点分隔的层级. 。 使用log4cxx一个可设置的整体阈libA到INFO,更具体的记录器, libA.moduleB ,具有DEBUG的阈值。

libA.threshold=INFO
libA.moduleB.threshold=DEBUG

同样一个可以将汇层次结构中的任意节点。

我相信,类似的能力是可能的Boost.Log但我需要如何真正实现帮助/指导。 另外,我相信其他人想从其他框架过渡到Boost.Log都会有同样的问题谁。

我真诚地感谢您的意见。

Answer 1:

In Boost.Log sinks (the objects that write log files) and loggers (the objects through which your application emits log records) are not connected directly, and any sink may receive a log message from any logger. In order to make records from certain loggers appear only in particular sinks you will have to arrange filters in sinks so that the unnecessary records are suppressed for sinks that are not supposed to receive them and passed for others. To distinguish records from different loggers the loggers have to add distinct attributes to every record they make. Typically this is achieved with channels - loggers will attach a Channel attribute that can be used to identify the logger in the filters, formatters or sinks. Channels can be combined with other attributes, such as severity levels. It must be noted though that channels and severity levels are orthogonal, and any channel may have records of any level. Values of different attributes are analyzed separately in filters.

So, for example, if you want records from channel A to be written to file A.log, and from channel B - to B.log, you have to create two sinks - one for each file, and set their filters accordingly.

BOOST_LOG_ATTRIBUTE_KEYWORD(a_severity, "Severity", severity_level)
BOOST_LOG_ATTRIBUTE_KEYWORD(a_channel, "Channel", std::string)

logging::add_file_log(
    keywords::file_name = "A.log",
    keywords::filter = a_channel == "A");

logging::add_file_log(
    keywords::file_name = "B.log",
    keywords::filter = a_channel == "B");

See the docs about defining attribute keywords and convenience setup functions. Now you can create loggers for each channel and log records will be routed to sinks by filters.

typedef src::severity_channel_logger< severity_level, std::string > logger_type;

logger_type lg_a(keywords::channel = "A");
logger_type lg_b(keywords::channel = "B");

BOOST_LOG_SEV(lg_a, info) << "Hello, A.log!";
BOOST_LOG_SEV(lg_b, info) << "Hello, B.log!";

You can have as many loggers for a single channel as you like - messages from each of them will be directed to a single sink.

However, there are two problems here. First, the library has no knowledge of the channel nature and considers it just an opaque value. It has no knowledge of channel hierarchy, so "A" and "A.bb" are considered different and unrelated channels. Second, setting up filters like above can be difficult if you want multiple channels to be written to a single file (like, "A" and "A.bb"). Things will become yet more complicated if you want different severity levels for different channels.

If channel hierarchy is not crucial for you, you can make filter configuration easier with a severity threshold filter. With that filter you can set minimal severity level for each corresponding channel. If you want to inherit severity thresholds in sub-channels then your only way is to write your own filter; the library does not provide that out of the box.

There are multiple ways to create a filter but it boils down to writing a function that accepts attribute values from log records and returns true if this record passed the filter and false otherwise. Perhaps, the easiest way is shown in Tutorial, see the example with phoenix::bind from Boost.Phoenix.

bool my_filter(
    logging::value_ref< severity_level, tag::a_severity > const& level,
    logging::value_ref< std::string, tag::a_channel > const& channel,
    channel_hierarchy const& thresholds)
{
    // See if the log record has the severity level and the channel attributes
    if (!level || !channel)
       return false;

    std::string const& chan = channel.get();

    // Parse the channel string, look for it in the hierarchy
    // and find out the severity threshold for this channel
    severity_level threshold = thresholds.find(chan);

    return level.get() >= threshold;
}

Now setting up sinks would change like this to make use of your new filter:

logging::add_file_log(
    keywords::file_name = "A.log",
    keywords::filter = phoenix::bind(&my_filter, a_severity.or_none(), a_channel.or_none(), hierarchy_A));

logging::add_file_log(
    keywords::file_name = "B.log",
    keywords::filter = phoenix::bind(&my_filter, a_severity.or_none(), a_channel.or_none(), hierarchy_B));

Here hierarchy_A and hierarchy_B are your data structures used to store severity thresholds for different channels for the two log files.



文章来源: Use channel hiearchy of Boost.Log for severity and sink filtering