boost.log要点笔记

经常使用简写:

namespace logging = boost::log; namespace src = boost::log::sources; namespace expr = boost::log::expressions; namespace sinks = boost::log::sinks; namespace attrs = boost::log::attributes; namespace keywords = boost::log::keywords;

要点:

  1. 结构图要牢记在心;
  2. trivial头文件可用于通常的控制台输出,日志等级被定义在改头文件;
  3. 全局日志等级过滤使用logging::core::get()->set_filter();
  4. 若是不只仅须要简单的控制台输出,这时候就要添加sink,使用logging::add_file_log可添加文件sink后端,格式以下:
1
2
3
4
5
6
7
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%" //日志消息格式 );

除了这种语法外,也能够创建sinks::text_file_backend后端,用之初始化一个sink。 file rotation的选项有不少,能够指定日期、时间间隔、文件大小,甚至能够指定本身的谓词。 此外,能够设置在创建新文件后首先执行(sink->locked_backend()->set_open_handler(xx)),以及rotation以前最后执行的语句。 能够综合管理这些日志文件,限制输出文件夹,日志总大小限制,以及最低磁盘空间限制。以下:ios

1
2
3
4
5
sink->locked_backend()->set_file_collector(sinks::file::make_collector(
        keywords::target="logs", //目标文件夹 keywords::max_size=16*1024*1024, //全部日志加起来的最大大小, keywords::min_free_space=100*1024*1024 //最低磁盘空间限制 ));

若是多个后端制定了相同的存放文件夹,限制取其中最严格的,另外,注意避免不一样后端日志的命名冲突问题。 注意使用sink->locked_backend()->scan_for_files() 来扫描其余实例创建的日志文件。express

以上都是使用程序自己使用单日志文件的状况,若是须要根据请求的不一样将消息分发到不一样的文件,可使用sinks::text_mutlifile_backend。该后端经常使用于多线程调试。windows

  1. 除了文件后端,更经常使用的是文本流后端sinks::text_ostream_backend,与别的后端不一样,文本流后端能够添加多个输出对象,这些对象因为都在同一个sink中,因此输出格式是同样的,这种作法的性能比添加文件后端更高,可是会失去对文件的控制能力。后端

  2. 对于大规模应用程序,为了方便查看记录,各模块的日志应该相互独立,所以一个logger通常是不够的,咱们须要本身创建logger。logger的创建方法很简单,new一个src::logger就能够了…安全

若是真的只须要一个logger,除了使用前面提到的trivial中的宏之外,也能够用BOOST_LOG_INLINE_GLOBAL_LOGGER_DEFAULT(my_logger,src::logger_mt),本身定义属于本身的全局logger。而后在须要的时候使用src::logger_mt& lg=my_logger::get()得到logger的单例引用(这里最好是线程安全的logger,显然)。多线程

logger的使用方法:frontend

1
2
3
4
5
6
7
8
logging::record rec=log.open_record();
if(rec) { logging::record_ostream strm(rec); strm<<"Hello,World!"; strm.flush(); lg.push_record(boost::move(rec)); }

以上能够简化成一个宏:BOOST_LOG(lg)<<"Hello World"函数

  1. attribute是log record的附加信息,不一样于通常的消息记录,属性能够被单独拿出来处理,做为某种过滤条件,或者其余使用。属性分为全局属性,特定线程属性和特定源的属性。

经常使用的属性,如时间戳、计数器,boost.log都已经有实现好的版本,直接使用logging::add_common_attributes() 能够一次性得到LineID,TimeStampProcessIDThreadID 这些经常使用属性(单线程程序没有线程ID)。post

能够本身注册安全等级,定义相关枚举,而后使用其做为src::serverity_logger<>的模板参数初始化,就获得了自定义Severity属性的logger。这种logger可使用BOOST_LOG_SEV(logger,serverity)来记录。性能

特定范围的属性能够用来作一些特殊日志,好比须要评估性能的地方可使用BOOST_LOG_SCOPED_THREAD_ATTR("Timeline",attrs::timer());注册一个时间线标签。

此外,能够给属性定义占位符,至关于注册为关键字,方便在流中使用。关于属性的函数大多定义在expr命名空间里面。

  1. 格式化输出消息,前文有set_formatter的用法。格式化消息可使用stl格式expr::stream<<xxx,也可使用boost::format格式,即expr::format("%1%)%xxx这种。

为了取得最大灵活性,能够自定义一个formatter

  1. 过滤子,如前文,可使用sink.set_filter来设置,可使用的过滤条件包括布尔表达式和lambda表达式等,若是想要肯定有没有某个属性,可以使用expr::has_attr()

  2. 宽字符。使用windows的话,这块算是最恶心的部分了

辅助函数

boost.log定义了大量辅助函数实现经常使用功能。

logging::add_console_log()能够直接添加控制台sink,返回boost::shared_ptr<sinks::synchronous_sink<sinks::text_ostream_backend>>,可利用返回值设置过滤器或其余属性。

logging::add_file_log(),前文已经提过,能够直接获得文件sink…

最后logging::add_common_attributes能够得到经常使用属性,前文也有详解。

示例

彻底封装boost.log的工程量比较大,不过对于小规模工程,使用一个初始化函数就足够了,可是这会致使整个项目与boost深度耦合。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
/*  * FILE: boost.log.init.hpp  * INSTRUCTION: 这个文件用于初始化boost.log  * DETAIL: 这里从新定义了日志级别和对应的文本内容.  * 文件大小限制等信息被硬编码在cpp文件中,若有需求能够修改。  */ #ifndef BOOST_LOG_INIT_TAIRAN_HPP #define BOOST_LOG_INIT_TAIRAN_HPP #include <iostream> #include <boost/date_time/posix_time/posix_time.hpp> #include <boost/log/support/date_time.hpp> #include <boost/log/common.hpp> #include <boost/log/expressions.hpp> #include <boost/log/expressions/keyword.hpp> #include <boost/log/attributes.hpp> #include <boost/log/attributes/timer.hpp> #include <boost/log/sources/logger.hpp> #include <boost/log/sources/severity_logger.hpp> #include <boost/log/sinks/sync_frontend.hpp> #include <boost/log/sinks/text_file_backend.hpp> #include <boost/log/utility/setup/file.hpp> #include <boost/log/utility/setup/console.hpp> #include <boost/log/utility/setup/common_attributes.hpp> #include <boost/log/attributes/named_scope.hpp> namespace logging = boost::log; namespace attrs = boost::log::attributes; namespace src = boost::log::sources; namespace sinks = boost::log::sinks; namespace expr = boost::log::expressions; namespace keywords = boost::log::keywords; enum SeverityLevel { Log_Info, Log_Notice, Log_Debug, Log_Warning, Log_Error, Log_Fatal }; // The formatting logic for the severity level template< typename CharT, typename TraitsT > inline std::basic_ostream< CharT, TraitsT >& operator<< ( std::basic_ostream< CharT, TraitsT >& strm, SeverityLevel lvl) { static const char* const str[] = { "Info", "Notice", "Debug", "Warning", "Error", "Fatal" }; if (static_cast< std::size_t >(lvl) < (sizeof(str) / sizeof(*str))) strm << str[lvl]; else strm << static_cast< int >(lvl); return strm; } BOOST_LOG_ATTRIBUTE_KEYWORD(log_severity, "Severity", SeverityLevel) BOOST_LOG_ATTRIBUTE_KEYWORD(log_timestamp, "TimeStamp", boost::posix_time::ptime) BOOST_LOG_ATTRIBUTE_KEYWORD(log_uptime, "Uptime", attrs::timer::value_type) BOOST_LOG_ATTRIBUTE_KEYWORD(log_scope, "Scope", attrs::named_scope::value_type) void g_InitLog(); #endif

实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#include "boost.log.init.hpp" void g_InitLog() { logging::formatter formatter= expr::stream <<"["<<expr::format_date_time(log_timestamp,"%H:%M:%S") <<"]"<<expr::if_(expr::has_attr(log_uptime)) [ expr::stream<<" ["<<format_date_time(log_uptime,"%O:%M:%S")<<"]" ] <<expr::if_(expr::has_attr(log_scope)) [ expr::stream<<"["<<expr::format_named_scope(log_scope,keywords::format = "%n")<<"]" ] <<"<"<<log_severity<<">"<<expr::message; logging::add_common_attributes(); auto console_sink=logging::add_console_log(); auto file_sink=logging::add_file_log ( keywords::file_name="%Y-%m-%d_%N.log", //文件名 keywords::rotation_size=10*1024*1024, //单个文件限制大小 keywords::time_based_rotation=sinks::file::rotation_at_time_point(0,0,0) //天天重建 ); file_sink->locked_backend()->set_file_collector(sinks::file::make_collector( keywords::target="logs", //文件夹名 keywords::max_size=50*1024*1024, //文件夹所占最大空间 keywords::min_free_space=100*1024*1024 //磁盘最小预留空间 )); file_sink->set_filter(log_severity>=Log_Warning); //日志级别过滤 file_sink->locked_backend()->scan_for_files(); console_sink->set_formatter(formatter); file_sink->set_formatter(formatter); file_sink->locked_backend()->auto_flush(true); logging::core::get()->add_global_attribute("Scope",attrs::named_scope()); logging::core::get()->add_sink(console_sink); logging::core::get()->add_sink(file_sink); }

使用:

调用g_initlog()初始化一次之后,在任意位置声明logger,使用宏BOOST_LOG_SEV(logger,SeverityLevel)<<"..."来写入日志便可。

相关文章
相关标签/搜索