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

    完整代码

  • 相关阅读:
    Hibernate unsaved-value 属性
    ResulsetHandler九个实现类
    Introspector内省和反射的区别.
    数据库表、字段命名规范
    Linux 时间同步 ntpdate
    http升级https改造方案
    org.apache.tomcat.util.net.NioEndpoint,打开的文件过多
    kafka常用命令
    elasticsearch.yml 配置说明
    getDate() 各种时间格式
  • 原文地址:https://www.cnblogs.com/kohlrabi/p/9160176.html
Copyright © 2011-2022 走看看