Boost Log 的 attribute 的简易使用
本文主要是分享怎么使用 Boost Log 在每一笔纪录里面附加的 attribute。
说实话,虽然用 Boost Log 来作纪录是蛮方便的~但是, Boost Log 在格式化、以及筛选时所使用 expression…不知道之后有没有可能直接用 C++ 标准的 lambda expression 来做?个人觉得那样应该会好写很多…总之,这边还是来大概写一下,在 Boost Log 里面,要怎么附加 attribute 的数据吧~没意外的话,下面就开始吧。
Attribute 的使用
首先,在前面的范例里可以看到, Boost Log 的每一笔纪录(record),基本上都是透过文字、来做没有特定格式的纪录的。
但是,仔细想的话,也会注意到,在‘trivial’模式、或是 severity_logger<>, 其实都还是有一些特定格式的数据在纪录里,例如时间、severity level 等等;而这些有特定格式的数据,就是 Boost Log 提供的‘attribute’。透过这些可以自己定义的 attribute,在某些时候,可以让我们更好地去结构化我们的 log 系统的数据。
基本上,Boost Log 的 attribute 是每笔纪录都各自独立的、并且可以用一个名字来做存取;Heresy 个人觉得最典型的读取方法,就是使用 set_formatter() 的时候,透过 boost::log::expressions::attr<TYPE>(NAME) 这个函数来取得数据、并指定数据的型别。
像是在《Boost Log 的一些 logger 使用细节》这篇帖子里面最后的范例,就是用这个方式来读取 severity level:
- pSink->set_formatter(
- boost::log::expressions::stream
- << "<" << boost::log::expressions::attr<severity_level>("Severity")
- << ">\t" <<boost::log::expressions::message
- );
而如果想要简化程序码的话,建议可以搭配 namespace alias 来使用:
- namespace expr = boost::log::expressions;
- pSink->set_formatter(
- expr::stream
- << "<" << expr::attr<severity_level>("Severity")
- << ">\t" << expr::message
- );
这样的话,程序码是会看起来干净不少的。
而如果想要简化 attribute 的读取的话,可以搭配 BOOST_LOG_ATTRIBUTE_KEYWORD() 这个 macro 来使用。
设置 Attribute
而要指定 attribute 的值的话,个人是觉得应该可以分为两大类:第一种是在建立每一笔纪录时再加上去各自的 attribute,另一种方法则是在建立 Boost.Log 的环境的时候、就直接设置完成。
前者的话,可以在使用 BOOST_LOG() 建立纪录的时候,用 boost::log::add_value() 来加入。
(需要 include <boost/log/utility/manipulators/add_value.hpp> 这个文件)
例如下面的程序码里面,就是在这笔纪录里面、附加一个名为‘att1’的 attribute,其值为‘1’。
BOOST_LOG( mLogger ) << boost::log::add_value("att1",1) << "log 2";
而除了这样在每笔纪录里面,都各自去附加 attribute 外,另一种方法,就是针对不同的物件、直接附加固定的 attribute。像是在《程序的记录辅助工具:Boost Log》一文中所提到的 add_common_attributes(),就是这种类型。
而根据需求的不同,attribute 可以附加在 core 上、当作全域的 attribute(大家都有)(global),或是根据 thread 不同做设置的(thread-specific);另外也可以附加在不同的 logger 物件上,作为 log 来源的区隔(source-specific)。
而以全域的 attribute 来说,它的使用方法,是透过 boost::log::core 的 add_global_attribute() 这个函数来做设置;其使用范例如下:
boost::shared_ptr<boost::log::core> core = boost::log::core::get();
core->add_global_attribute("TimeStamp", boost::log::attributes::local_clock());
这个函数的第一个参数是一个字串、代表这个 attribute 的名字,而第二个参数则是型别为 attribute 的物件,用来让 Boost Log 在建立纪录的时候,可以取得 attribute 的值。
这边的 local_clock 是一个继承 attribute 的类别,定义在 boost/log/attributes/clock.hpp 这个文件里;他会在建立每一笔纪录的时候,去读取现在的时间、并当作 attribute 的值、附加到纪录里。
而 thread-specific 的 attribute,则是调用 core 的 add_thread_attribute() 函数,他的参数和 add_global_attribute() 是相同的;和 add_global_attribute() 不同的地方在于,使用 add_thread_attribute() 加入的 attribute 只会出现在这个 thread 产生的纪录里,其他 thread 产生的纪录不会有这个 attribute。
至于 source-specific 的 attribute,则是调用 logger 的 add_attribute() 这个函数,他的介面基本上也是相同的;不同的地方在于,透过这种方法加入的 attribute 只有在使用这个 logger 的时候才会有,如果使用别的 logger 则不会有。
至于用来产生值得 attribute 的部分,Boost Log 也有提供许多不同的功能可以使用,像是上面的 local_clock 就是用来产生时间的数据的;而其他也还有像是 timer、current_process_id、current_scope_info 等等,有兴趣的话请参考官方文件(链结)。
而如果是要用常数(固定的值)的话,则可以使用 constant<> 这个 template 型别、或是直接使用 make_constant() 这个函数。
如果想要使用自己的函数来产生值的话,除了继承 attribute 写一个新的的外,也可以使用 make_function() 这个函数,来透过指定 functiuon object 的方法来做。
(不过在 Visual C++ 2010 下,似乎和 C++11 的 lambda expression 有兼容性问题…)
Boost Log 的 lambda expression
Boost Log 的格式设置、以及筛选条件,都是自己定义的 lambda exprerssion、而非标准的 lambda expression 或 function object,这点算是 Heresy 比较讨厌的地方。而为了做到更多功能,所以 Boost Log 在这边,也提供了很多不同的功能。不过这边就是只是大概列一下一些东西、不打算仔细写了,细节请参考官方文件。
由于纪录里面不一定会有对应的 attribute,所以在读取 attribute 的值的时候,也可以透过 or_none()、or_throw()、or_default() 这三个韩式,来做额外的处理。
可以透过 has_attr() 来判断此笔纪录是否有指定的 attribute;而在这部分,boost log 也有提供其他的数据判断函数,可以做一些简单的 filter。
Boost Log 的 expression 也有提供语法很诡异的 if 来做条件判断…
可以搭配 Boost Phoenix 来使用一班的函数
本文就写到这了。说实话,自己都觉得这系列写的超凌乱的… orz
作者后记:基本上,就只能算是自己的纪录了;要拿来当作学习的参考,可能会有点难度。除非之后遇到特殊的需求,不然应该也不会再继续写、或是重新整理了吧…
- 评论列表(网友评论仅供网友表达个人看法,并不表明本站同意其观点或证实其描述)
-
