span.kw { color: #007020; font-weight: bold; }
code > span.dt { color: #902000; }
code > span.dv { color: #40a070; }
code > span.bn { color: #40a070; }
code > span.fl { color: #40a070; }
code > span.ch { color: #4070a0; }
code > span.st { color: #4070a0; }
code > span.co { color: #60a0b0; font-style: italic; }
code > span.ot { color: #007020; }
code > span.al { color: #ff0000; font-weight: bold; }
code > span.fu { color: #06287e; }
code > span.er { color: #ff0000; font-weight: bold; }

-->

常用简写:

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之前最后执行的语句。 可以综合管理这些日志文件,限制输出文件夹,日志总大小限制,以及最低磁盘空间限制。如下:

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() 来扫描其他实例建立的日志文件。

以上都是使用程序本身使用单日志文件的情况,如果需要根据请求的不同将消息分发到不同的文件,可以使用sinks::text_mutlifile_backend。该后端常用于多线程调试。

  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的使用方法:

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, TimeStamp, ProcessID, ThreadID 这些常用属性(单线程程序没有线程ID)。

可以自己注册安全等级,定义相关枚举,然后使用其作为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)<<"..."来写入日志即可。

boost.log要点笔记的更多相关文章

  1. boost.asio与boost.log同时使用导致socket不能正常收发数据

    现象: 1. 没有使用boost.log前能正常收发数据 2.加入boost.log后async_connect没有回调 fix过程: 1. gdb调试发现程序block在pthread_timed_ ...

  2. Boost.log

    =================================版权声明================================= 版权声明:本文为博主原创文章 未经许可不得转载  请通过右 ...

  3. boost.log在项目中应用

    //头文件#pragma once #include <string> #include <boost/log/trivial.hpp> using std::string; ...

  4. 编译boost.log模块遇到的一些问题

    线上日志用到的是日志库,在全局有一个锁,导致在高并发的时候,容易因为锁竞争问题导致时延.在某些情况下,会因为同一个用户,同时访问某个变量,导致读写冲突使线上服务整体core掉(考虑到请求的间隔,为了应 ...

  5. Boost log中的几个问题

    1. 使用动态库时,要定义 BOOST_LOG_DYN_LINK  或者 BOOST_ALL_DYN_LINK 否则会出现如下错误: CMakeFiles/xxxx.dir/xxxx.cpp.o: I ...

  6. Boost Log 基本使用方法

    Boost Log 基本使用方法 flyfish 2014-11-5 依据boost提供的代码演示样例,学习Boost Log 的基本使用方法 前提 boost版本号boost_1_56_0 演示样例 ...

  7. C++ 日志库 boost::log 以及 glog 的对比

    日志能方便地诊断程序原因.统计程序运行数据,是大型软件系统必不可少的组件之一.本文将从设计上和功能上对比 C++ 语言常见的两款日志库: boost::log 和 google-glog . 设计 b ...

  8. C++ boost.python折腾笔记

    为了让当年研究生时写的图像处理系统重出江湖起到更大的作用,应研究生导师的意见,对原有的c++框架做了python扩展处理,为了避免遗忘,备注如下: 一.boost 编译 下载boost源码,这里使用b ...

  9. golang语法要点笔记

    golang学习笔记 读<go学习笔记第四版> <学习go语言> <gopl-zh><Go语言实战>记录 多变量赋值时,先计算所有相关值,然后再从左到右 ...

随机推荐

  1. 【Xamarin挖墙脚系列:Xamarin.IOS的程序的结构】

    原文:[Xamarin挖墙脚系列:Xamarin.IOS的程序的结构] 开始熟悉Xamarin在开发IOS的结构!!!!!!! 先看官方 这个是以一个单页面的程序进行讲述的. 1 程序引用的程序集,核 ...

  2. vs2015 Xamarin.Android安装

    原文:vs2015 Xamarin.Android安装 Xamarin.Android 安装步骤,以vs2015为例 1,安装vs2015中的跨平台项,但是安装在国内肯定失败,因为需要到谷歌下载 当我 ...

  3. mysqll 数据库相互堵塞问题

    192.168.11.186 远程访问192.168.11.185 数据库 186上看到: centos6.5:/root#mysql -uroot -p'kjk123123' -h192.168.1 ...

  4. git撤销提交到remote的commit

    Reseting remote to a certain commit Assuming that your branch is called master both here and remotel ...

  5. Light OJ 1064 - Throwing Dice

    题目大意: 给你n个骰子, 问点数大于等于x的概率是多少? #include<cstdio> #include<cstring> #include<iostream> ...

  6. selenium webdriver(2)---页面对象定位

    webdriver的元素定位很灵活,提供了多种定位方式: Id LinkText PartialLinkText Name TagName Xpath ClassName CssSelector 这些 ...

  7. JavaScript高级程序设计42.pdf

    IE中的事件对象 要访问IE中的event对象有几种不同的方式,取决于指定事件处理程序的方法.在使用DOM0级方法添加事件处理程序时,event对象作为window对象的一个属性存在 wondow.e ...

  8. centos 系统程序包安装记录

    -添加sudoer su - vi /etc/sudoers 在root ALL=(ALL) ALL 下添加: pete ALL=(ALL) ALL -安装拼音: sudo yum install & ...

  9. Bzoj 4034: [HAOI2015]T2 树链剖分,子树问题,dfs序

    4034: [HAOI2015]T2 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 1841  Solved: 598[Submit][Status] ...

  10. Bzoj 3289: Mato的文件管理 莫队,树状数组,逆序对,离散化,分块

    3289: Mato的文件管理 Time Limit: 40 Sec  Memory Limit: 128 MBSubmit: 1539  Solved: 665[Submit][Status][Di ...