• 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。在其他情况下,此策略是默认的。还有其他策略可以替代。

    可以通过编译和运行测试来尝试这是如何工作的。

  • 相关阅读:
    170516、ActiveMQ 的安装与使用(单节点)
    170515、mybatis批量操作
    170512、java日志文件log4j.properties配置详解
    170511、Spring IOC和AOP 原理彻底搞懂
    170510、数据库默认隔离级别
    170509、文本编辑器编写的shell脚本在linux下无法执行的解决方法
    170508、忘记jenkins密码或者修改jenkins密码
    170505、MySQL的or/in/union与索引优化
    170504、MongoDB和MySQL对比(译)
    Jenkins Android 打包
  • 原文地址:https://www.cnblogs.com/kohlrabi/p/9160384.html
Copyright © 2020-2023  润新知