码迷,mamicode.com
首页 > 其他好文 > 详细

boost.log(五)属性

时间:2015-04-28 13:33:23      阅读:142      评论:0      收藏:0      [点我收藏+]

标签:

前面几节我们提到属性属性好几在这里我们会学习如何使用属性添加更多数据到日志记录

每条日志记录可以附加多个已命名的属性值,属性可以代表日志记录产生时任何与程序运行相关的数据信息。如代码位置、执行模块名称、当前数据和时间以及程序运行相关的任何数据信息。属性可以表现为一个值生成器,在这种情况下,将用于返回它参与的每个不同日志记录所生成的值一旦属性生成值,就可以把这个值用于过滤器,格式化器和接收器。但是使用该属性值你必须知道它的名称和类型,或者至少知道它的类型组。Log库中实现了常用的属性,你可以在文档中找到它们值的类型

除此之外,属性有三种可能的范围:局部范围,特定线程和全局。当进行日志记录,这三个范围的属性值被加入到一个集合并传递到接收器。这意味着属性的来源在接收器中没有区别。任何属性可以在任何范围内进行注册。当注册时属性会被赋予一个唯一的名称,使得能够搜索它。如果碰巧几个范围中有同样名称的属性,那么局部范围的属性将被优先考虑并做出进一步的处理,包括日志过滤和输出格式化。这种行为能够覆盖全局和线程范围的属性在你本地记录器中的注册,从而减少线程干扰。

下面属性注册过程的描述。

常用属性

几乎任何程序都有可能被用到的属性,如计数器、时间戳等,它们可以通过调用一个函数很容易地被添加:
  1. #include <boost/log/utility/setup/common_attributes.hpp>
  2. int main()
  3. {
  4. boost::log::add_common_attributes();
  5. return 0;
  6. }
调用add_common_attributes这个函数将在全局注册"LineID"、"TimeStamp"、"ProcessID"和"ThreadID"。"LineID"属性是一个计数器,每个纪录递增。"TimeStamp"属性总是会产生当前时间 。最后两个记录日志产生时当前进程和线程的ID。

[注意]单线程情况下"ThreadID"属性不会被注册

[提示]默认情况下,当应用程序启动时,log库中没有注册任何属性。应用程序必须在开始写日志之前在log库中注册所有必要的属性。这作为log库初始化的一部分。但是为什么第一节中BOOST_LOG_TRIVIAL宏可以正常工作呢?答案是默认接收器除了严重级别没有使用任何属性值来组成它的输出。这样做是为了避免需要Trivial Logging进行初始化。如果你一旦使用过滤器或格式化或者非默认接收器,那么你必须注册你所需要的属性。

某些属性可以在记录器构造时自动注册。例如,severity_logger 注册特定源属性可以用来添加强调不同的日志记录级别的"Severity"。举个例子:
  1. #include <boost/log/sources/record_ostream.hpp>
  2. #include <boost/log/sources/severity_logger.hpp>
  3. #include <boost/log/sources/severity_feature.hpp>
  4. #include <boost/log/utility/setup/common_attributes.hpp>
  5. enum severity_level
  6. {
  7. normal,
  8. notification,
  9. warning,
  10. error,
  11. critical
  12. };
  13. void logging_function()
  14. {
  15. boost::log::sources::severity_logger< severity_level > slg;
  16. BOOST_LOG_SEV(slg, normal) << "A regular message";
  17. BOOST_LOG_SEV(slg, warning) << "Something bad is going on but I can handle it";
  18. BOOST_LOG_SEV(slg, critical) << "Everything crumbles, shoot me now!";
  19. }
BOOST_LOG_SEV 宏的行为很像 BOOST_LOG, 不同在于它需要为open_record函数传入一个参数,BOOST_LOG_SEV  宏与下面的代码等价:
  1. #include <boost/log/keywords/severity.hpp>
  2. #include <boost/log/sources/record_ostream.hpp>
  3. #include <boost/log/sources/severity_logger.hpp>
  4. #include <boost/log/sources/severity_feature.hpp>
  5. #include <boost/log/utility/setup/common_attributes.hpp>
  6. enum severity_level
  7. {
  8. normal,
  9. notification,
  10. warning,
  11. error,
  12. critical
  13. };
  14. void manual_logging()
  15. {
  16. boost::log::sources::severity_logger< severity_level > slg;
  17. boost::log::record rec = slg.open_record(boost::log::keywords::severity = normal);
  18. if (rec)
  19. {
  20. boost::log::record_ostream strm(rec);
  21. strm << "A regular message";
  22. strm.flush();
  23. slg.push_record(boost::move(rec));
  24. }
  25. }
在这里你可以看到 open_record 可以使用命名的参数。由log库提供的一些记录器类型都支持这种额外的参数,这种做法也可以在用户编写自己的记录器时使用。

更多属性

现在我们看看在调用add_common_attributes()函数时,它具体做了什么。
  1. inline void add_common_attributes()
  2. {
  3. shared_ptr< core > pCore = core::get();
  4. pCore->add_global_attribute(
  5. aux::default_attribute_names::line_id(),
  6. attributes::counter< unsigned int >(1));
  7. pCore->add_global_attribute(
  8. aux::default_attribute_names::timestamp(),
  9. attributes::local_clock());
  10. pCore->add_global_attribute(
  11. aux::default_attribute_names::process_id(),
  12. attributes::current_process_id());
  13. #if !defined(BOOST_LOG_NO_THREADS)
  14. pCore->add_global_attribute(
  15. aux::default_attribute_names::thread_id(),
  16. attributes::current_thread_id());
  17. #endif
  18. }
这里的line_id、timestamp等类,它们由共同的接口父类attribute派生。log库还提供了很多其它的属性类(参见log\detail\default_attribute_names.hpp)。包含函数对象属性,通过调用一些函数来获取值。例如,我们以类似的方式注册一个名字为 named_scope 的属性:
  1. boost::log::core::get()->add_global_attribute("Scope", boost::log::attributes::named_scope());
这将使应用程序我们能够将范围名称存储在每个日志记录中。下面是如何使用它:
  1. void named_scope_logging()
  2. {
  3. BOOST_LOG_NAMED_SCOPE("named_scope_logging");
  4. boost::log::sources::severity_logger< severity_level > slg;
  5. BOOST_LOG_SEV(slg, normal) << "Hello from the function named_scope_logging!";
  6. }
记录器特有的属性并不比那些全局的属性有用。严重级别和渠道名是程序执行中最明显的属性。没有什么能阻止你为你的记录器增加更多的属性,像这样:
  1. void tagged_logging()
  2. {
  3. boost::log::sources::severity_logger< severity_level > slg;
  4. slg.add_attribute("Tag", boost::log::attributes::constant< std::string >("My tag value"));
  5. BOOST_LOG_SEV(slg, normal) << "Here goes the tagged record";
  6. }
现在通过此日志记录器的所有日志记录都将被标记“Tag”这个特定的属性。此属性的值可用于过滤筛选或者是自定义输出格式。

属性的另一个好用途是在应用程序执行一个过程中,日志记录有标记此过程中不同部分的能力我们甚至可以实现一个粗略的分析工具来检测性能瓶颈例子:
  1. void timed_logging()
  2. {
  3. BOOST_LOG_SCOPED_THREAD_ATTR("Timeline", boost::log::attributes::timer());
  4. boost::log::sources::severity_logger< severity_level > slg;
  5. BOOST_LOG_SEV(slg, normal) << "Starting to time nested functions";
  6. logging_function();
  7. BOOST_LOG_SEV(slg, normal) << "Stopping to time nested functions";
  8. }
现在每个日志记录从 logging_function 函数中取得,调用任何其他函数获得。记录中包含具有"Timeline"属性的精度时间。根据这些时间,我们可以很容易检测到哪些代码耗费了更多的时间来执行。由于BOOST_LOG_SCOPED_THREAD_ATTR注册的属性是范围内属性,所有离开timed_logging()函数的作用域这个属性就会被注销

定义属性占位符

我们将在接下来的几节中看到这种方式:定义关键字来描述特定属性。此关键字能够参与到日志过滤和输出格式的设定中,像前面各节中的严重级别占位符。例如,要声明上面例子中的那些属性,可以这样定义占位符:
  1. BOOST_LOG_ATTRIBUTE_KEYWORD(line_id, "LineID", unsigned int)
  2. BOOST_LOG_ATTRIBUTE_KEYWORD(severity, "Severity", severity_level)
  3. BOOST_LOG_ATTRIBUTE_KEYWORD(tag_attr, "Tag", std::string)
  4. BOOST_LOG_ATTRIBUTE_KEYWORD(scope, "Scope", boost::log::attributes::named_scope::value_type)
  5. BOOST_LOG_ATTRIBUTE_KEYWORD(timeline, "Timeline", boost::log::attributes::timer::value_type)
每个宏定义一个关键字。第一个参数是占位符的名字,第二个是属性名,最后一个参数是属性值类型。一旦定义,占位符可以在模板表达式和log库的一些其它环境中使用。上面定义的属性关键字的更多细节可以在这里找到。




boost.log(五)属性

标签:

原文地址:http://www.cnblogs.com/zhangpanyi/p/4462552.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!