zoukankan      html  css  js  c++  java
  • Boost Log : Log record formatting

    Log record formatting

    如果您尝试运行前几节中的示例,您可能已经注意到,只有日志记录消息被写到文件中。当没有设置格式器(formatter)时,这是Log库的默认行为。除非指定格式器,否则即使向logging core或logger添加了属性,属性值将无法输出。回到前面的教程章节中的一个例子:

    void init()
    {
        logging::add_file_log
        (
            keywords::file_name = "sample_%N.log",
            keywords::rotation_size = 10 * 1024 * 1024,
            keywords::time_based_rotation = sinks::file::rotation_at_time_point(0, 0, 0),
            keywords::format = "[%TimeStamp%]: %Message%"
        );
    
        logging::core::get()->set_filter
        (
            logging::trivial::severity >= logging::trivial::info
        );
    }
    

    对于add_file_log函数,format参数允许指定日志记录的格式。如果喜欢手动设置sink,那么sink前端会为此提供set_formatter成员函数。

    如前所述,可以通过多种方式指定格式。

    Lambda-style formatters

    可以使用如下所示的lambda样式的表达式创建格式器:

    void init()
    {
        logging::add_file_log
        (
            keywords::file_name = "sample_%N.log",
            // This makes the sink to write log records that look like this:
            // 1: <normal> A normal severity message
            // 2: <error> An error severity message
            keywords::format =
            (
                expr::stream
                    << expr::attr< unsigned int >("LineID")
                    << ": <" << logging::trivial::severity
                    << "> " << expr::smessage
            )
        );
    }
    

    完整代码
    在这里,stream是格式化输出日志记录的stream的占位符。其他插入参数,例如attr和message,是定义应该在stream中存储什么内容的操作器。我们已经在过滤表达式中看到了severity占位符,现在,它又在格式器中被使用。这是一个很好的统一:可以在过滤器和格式器中使用相同的占位符。attr占位符与severity占位符相似,因为它也表示属性值。不同之处是,severity占位符表示名称为“Severity”这个特定属性,其类型为trivial::severity_level,但attr可以用来表示任何属性。在其他方面这两个占位符是等价的。例如,可以用以下方法替代severity :

    expr::attr< logging::trivial::severity_level >("Severity")
    

    Tip
    如前一节所示,可以为用户的属性定义类似severity这样的占位符。作为使用更简单的模板表达式的好处,此类占位符允许在占位符定义中包含所有关于属性(名称和值类型)的信息。这使得编码更不容易出错(不会拼写错误的属性名称或指定不正确的值类型),因此推荐使用这种方式定义新属性并在模板表达式中使用它们。

    还有其他的格式化程序操纵器可以提供对日期的高级支持,时间和其他类型。一些操纵器接受附加参数,用来自定义其行为。这些参数中大多数都是命名的,可以通过 Boost.Parameter风格传递。
    做一些改变,让我们看看手动初始化sink是如何完成的:

    void init()
    {
        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 >("sample.log"));
    
        sink->set_formatter
        (
            expr::stream
                   // line id will be written in hex, 8-digits, zero-filled
                << std::hex << std::setw(8) << std::setfill('0') << expr::attr< unsigned int >("LineID")
                << ": <" << logging::trivial::severity
                << "> " << expr::smessage
        );
    
        logging::core::get()->add_sink(sink);
    }
    

    完整代码
    可以看到,可以在表达式中绑定格式更改操作器;就像streams,当后续的日志记录被格式化时,这些操作器将影响其属性值格式。更多的操作器在Detailed features description部分被描述。

    Boost.Format-style formatters

    作为另一种选择,您可以使用类似Boost.Format的语法来定义格式器。如上所述的格式器可以如下所示:

    void init()
    {
        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 >("sample.log"));
    
        // This makes the sink to write log records that look like this:
        // 1: <normal> A normal severity message
        // 2: <error> An error severity message
        sink->set_formatter
        (
            expr::format("%1%: <%2%> %3%")
                % expr::attr< unsigned int >("LineID")
                % logging::trivial::severity
                % expr::smessage
        );
    
        logging::core::get()->add_sink(sink);
    }
    

    完整代码
    format占位符接受带有(参数的)位置说明的格式化字符串。注意,目前只支持位置格式。add_file_log和类似函数可以使用相同的格式规范。

    Specialized formatters

    Log库为许多类型(如日期、时间和作用域)提供专门的格式器。这些格式器对格式化后的值提供扩展控制。例如,可以使用与Boost.DateTime兼容的格式字符串来描述日期和时间格式:

    void init()
    {
        logging::add_file_log
        (
            keywords::file_name = "sample_%N.log",
            // This makes the sink to write log records that look like this:
            // YYYY-MM-DD HH:MI:SS: <normal> A normal severity message
            // YYYY-MM-DD HH:MI:SS: <error> An error severity message
            keywords::format =
            (
                expr::stream
                    << expr::format_date_time< boost::posix_time::ptime >("TimeStamp", "%Y-%m-%d %H:%M:%S")
                    << ": <" << logging::trivial::severity
                    << "> " << expr::smessage
            )
        );
    }
    

    完整代码
    同样的formatter也可以在Boost.Format-style formatter上下文中使用。

    String templates as formatters

    在某些情况下,文本模板也可以作为格式器。在这种情况下,将调用Log库初的始化支持代码来解析模板并重构适当的格式器。当使用这种方法时,需要注意一些事项,但是这里我们只简单地描述一下模板格式。

    void init()
    {
        logging::add_file_log
        (
            keywords::file_name = "sample_%N.log",
            keywords::format = "[%TimeStamp%]: %Message%"
        );
    }
    

    完整代码
    模板可能包含许多被百分号(%)包含的占位符。每个占位符必须包含要插入的属性值名称,而不是占位符。日志记录消息将替换%Message%占位符。

    Note
    sink后端的set_formatter方法中不接受文本格式模板。

    Custom formatting functions

    您可以向支持格式化的接收器后端添加自定义格式器。格式器实际上是一个函数对象,支持以下签名:

    void (logging::record_view const& rec, logging::basic_formatting_ostream< CharT >& strm);
    

    这里的CharT是目标字符类型。当日志记录视图rec通过过滤并存储在日志中时,将调用格式器。

    Tip
    记录视图与记录非常相似。值得注意的区别是,视图是不可变的,并且实现了浅拷贝。格式器和sinks只能对记录视图进行操作,这阻止它们修改记录,从而其他线程中的其他sinks仍然可以使用记录视图。

    格式化的记录应该通过插入到与stl兼容的输出流strm中来构建。下面是一个自定义格式化程序函数使用的示例:

    void my_formatter(logging::record_view const& rec, logging::formatting_ostream& strm)
    {
        // Get the LineID attribute value and put it into the stream
        strm << logging::extract< unsigned int >("LineID", rec) << ": ";
    
        // The same for the severity level.
        // The simplified syntax is possible if attribute keywords are used.
        strm << "<" << rec[logging::trivial::severity] << "> ";
    
        // Finally, put the record message to the stream
        strm << rec[expr::smessage];
    }
    
    void init()
    {
        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 >("sample.log"));
    
        sink->set_formatter(&my_formatter);
    
        logging::core::get()->add_sink(sink);
    }
    

    完整代码

  • 相关阅读:
    java的构造方法 java程序员
    No result defined for action cxd.action.QueryAction and result success java程序员
    大学毕业后拉开差距的真正原因 java程序员
    hibernate的回滚 java程序员
    验证码 getOutputStream() has already been called for this response异常的原因和解决方法 java程序员
    浅谈ssh(struts,spring,hibernate三大框架)整合的意义及其精髓 java程序员
    你平静的生活或许会在某个不可预见的时刻被彻底打碎 java程序员
    Spring配置文件中使用ref local与ref bean的区别. 在ApplicationResources.properties文件中,使用<ref bean>与<ref local>方法如下 java程序员
    poj1416Shredding Company
    poj1905Expanding Rods
  • 原文地址:https://www.cnblogs.com/kohlrabi/p/9160176.html
Copyright © 2011-2022 走看看