Boost Log : Filtering revisited
Posted kohlrabi
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Boost Log : Filtering revisited相关的知识,希望对你有一定的参考价值。
Filtering revisited
我们在前面的章节中已经提到了过滤,但是我们仅仅触及到了表面。现在我们能够向Log records添加attribute并设置sink,我们就可以构建我们需要的任何复杂的过滤。让我们考虑一下这个例子:
BOOST_LOG_ATTRIBUTE_KEYWORD(line_id, "LineID", unsigned int)
BOOST_LOG_ATTRIBUTE_KEYWORD(severity, "Severity", severity_level)
BOOST_LOG_ATTRIBUTE_KEYWORD(tag_attr, "Tag", std::string)
void init()
{
// Setup the common formatter for all sinks
logging::formatter fmt = expr::stream
<< std::setw(6) << std::setfill('0') << line_id << std::setfill(' ')
<< ": <" << severity << "> "
<< expr::if_(expr::has_attr(tag_attr))
[
expr::stream << "[" << tag_attr << "] "
]
<< expr::smessage;
// Initialize sinks
typedef sinks::synchronous_sink< sinks::text_ostream_backend > text_sink;
boost::shared_ptr< text_sink > sink = boost::make_shared< text_sink >();
sink->locked_backend()->add_stream(
boost::make_shared< std::ofstream >("full.log"));
sink->set_formatter(fmt);
logging::core::get()->add_sink(sink);
sink = boost::make_shared< text_sink >();
sink->locked_backend()->add_stream(
boost::make_shared< std::ofstream >("important.log"));
sink->set_formatter(fmt);
sink->set_filter(severity >= warning || (expr::has_attr(tag_attr) && tag_attr == "IMPORTANT_MESSAGE"));
logging::core::get()->add_sink(sink);
// Add attributes
logging::add_common_attributes();
}
完整代码
在这个示例中,我们初始化了两个sinks:一个用于完整的日志文件,另一个仅用于重要的消息。两个sinks都将以相同的log record格式(我们一开始就初始化并保存到了fmt变量)写入文本文件。 formatter类型是一个带formatter调用签名的无类型函数对象;在许多方面,它可以被视为类似于boost:::function或std::function,除了它从不为空以外。也有用于filters的一个类似的函数对象。
值得注意的是formatter本身在这里包含一个filters。如您所见,该格式包含一个条件:仅当日志记录包含“Tag” attribute时才出现。has_attr谓词检查record是否包含“Tag” attribute value并控制它是否被写入文件中。我们使用attribute的关键字来指定谓词的attribute的名称和类型,但是也可以在has_attr调用处中指定它们。条件格式器可以在这里详细解释。
进一步对两个sinks进行初始化。第一个接收器没有任何filters,这意味着它将把每个log record保存到文件中。我们调用第二个sink上的set_filter,只保存severity不低于warning,或者有“Tag” attribute,并且value为“IMPORTANT_MESSAGE”的log record。正如您所看到的,filter语法非常类似于通常的c++,特别是在使用attribute关键字时。
与formatters一样,也可以使用自定义函数作为filter。在这种情况下,Boost.Phoenix非常有用,因为它的bind实现与attribute占位符兼容。前一个例子可以通过以下方式进行修改:
bool my_filter(logging::value_ref< severity_level, tag::severity > const& level,
logging::value_ref< std::string, tag::tag_attr > const& tag)
{
return level >= warning || tag == "IMPORTANT_MESSAGE";
}
void init()
{
// ...
namespace phoenix = boost::phoenix;
sink->set_filter(phoenix::bind(&my_filter, severity.or_none(), tag_attr.or_none()));
// ...
}
如您所见,自定义formatter接收封装在value_ref模板中的attribute values。此包装器包含对指定类型的attribute value的可选引用;如果log record包含所需类型的attribute value,则引用是有效的。可以无条件地应用my_filter中使用的关系运算符,因为如果引用无效,它们将自动返回false。剩下的部分将通过bind表达式完成,该表达式将识severity和tag_attr关键字,并在将其传递给my_filter之前提取相应的值。
Note
由于与Boost.Phoenix集成相关的限制(见#7996),当attribute的关键字与phoenix::bind或phoenix::function一起使用时,如果attribute value缺失,则需要显式指定回退策略。在上面的示例中,这是通过调用or_none完成的,如果没有找到值,这会导致出现一个空的value_ref。在其他情况下,此策略是默认的。还有其他策略可以替代。
可以通过编译和运行测试来尝试这是如何工作的。
以上是关于Boost Log : Filtering revisited的主要内容,如果未能解决你的问题,请参考以下文章