【Boost】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;
要点:
- 结构图要牢记在心;
trivial头文件可用于一般的控制台输出,日志等级被定义在改头文件;- 全局日志等级过滤使用
logging::core::get()->set_filter(); - 如果不仅仅需要简单的控制台输出,这时候就要添加
sink,使用logging::add_file_log可添加文件sink后端,格式如下:
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之前最后执行的语句。 可以综合管理这些日志文件,限制输出文件夹,日志总大小限制,以及最低磁盘空间限制。如下:
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。该后端常用于多线程调试。
- 除了文件后端,更常用的是文本流后端
sinks::text_ostream_backend,与别的后端不同,文本流后端可以添加多个输出对象,这些对象由于都在同一个sink中,所以输出格式是一样的,这种做法的性能比添加文件后端更高,但是会失去对文件的控制能力。 - 对于大规模应用程序,为了方便查看记录,各模块的日志应该相互独立,因此一个 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的使用方法:
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"
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命名空间里面。
- 格式化输出消息,前文有
set_formatter的用法。格式化消息可以使用stl格式expr::stream<<xxx,也可以使用boost::format格式,即expr::format("%1%)%xxx这种。
为了取得最大灵活性,可以自定义一个formatter。
过滤子,如前文,可以使用
sink.set_filter来设置,可以使用的过滤条件包括布尔表达式和lambda表达式等,如果想要确定有没有某个属性,可使用expr::has_attr()。宽字符。使用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深度耦合。
/*
* 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
实现:
#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】boost.log 要点笔记的更多相关文章
- boost.log要点笔记
span.kw { color: #007020; font-weight: bold; } code > span.dt { color: #902000; } code > span. ...
- boost boost::asio::read socket.read_some 区别
boost boost::asio::read 尝试读一定数量的字节,直到读到为止,或者出错 socket.read_some 读一下socket,读到多少算多少 带async的类似
- Boost线程库学习笔记
一.创建一个线程 创建线程 boost::thread myThread(threadFun); 需要注意的是:参数可以是函数对象或者函数指针.并且这个函数无参数,并返回void类型. 当一个thre ...
- Boost::filesystem 使用小笔记
今天拿起手要用C++写个小工具,从指定的目录递归遍历文件,然后做一下处理.又翻了一下boost的filesystem库.小结一下,希望能加深印象,免得下次又要查看文档. 1. path对象就是一个跨平 ...
- boost asio io_service学习笔记
构造函数 构造函数的主要动作就是调用CreateIoCompletionPort创建了一个初始iocp. Dispatch和post的区别 Post一定是PostQueuedCompletionSta ...
- boost timer代码学习笔记
socket连接中需要判断超时 所以这几天看了看boost中计时器的文档和示例 一共有五个例子 从简单的同步等待到异步调用超时处理 先看第一个例子 // timer1.cpp: 定义控制台应用程序的入 ...
- 初探boost之noncopyable学习笔记
noncopyable 功能 同意程序轻松实现一个不可复制的类. 需包括头文件 #include<boost/noncopyable.hpp> 或 #include<boos ...
- [Boost]boost的时间和日期处理-(1)日期的操作
<开篇> Boost.DateTime库提供了时间日期相关的计算.格式化.转换.输入输出等等功能,为C++的编程提供了便利.不过它有如下特点: 1. Boost.DateTime 只支持1 ...
- [Boost]boost的时间和日期处理-(2)时间的操作
<开篇> 本篇紧接着boost上篇叙述Boost::DateTime的时间处理.在C++中,常见的时间有time_t, FILETIME和tm,而boost中用ptime. 构造ptime ...
- golang语法要点笔记
golang学习笔记 读<go学习笔记第四版> <学习go语言> <gopl-zh><Go语言实战>记录 多变量赋值时,先计算所有相关值,然后再从左到右 ...
随机推荐
- 基于TensorFlow 2与PaddlePaddle 2预测泰坦尼克号旅客生存概率的比较
目录 1,程序比较 2,训练过程对比: 3,训练结果对比 AI框架经过大浪淘沙之后,目前真正能够完整用于生产.科研.学术的只剩下了谷歌.脸书.百度三家的框架,本文通过一个泰坦尼克号旅客生存概率预 ...
- Modbus 转PROFINET 网关 TS-180在级联通讯中的应用
一.硬件连接 TS-180 具有冗余网口功能,用户可以通过级联方式连接来进行通讯,其他资料可参考说明书.将西门子 S7-300 PLC 通过网线与5台 TS-180 串联,用户可以选择下列两种连接方式 ...
- 掌握这些,轻松管理BusyBox:如何交叉编译和集成BusyBox
在嵌入式系统中,由于设备的资源限制,需要开发人员寻找一种轻量.小型且使用广泛的工具集.而 BusyBox 就是这样一个在嵌入式系统中非常实用的工具集.本文将介绍如何在 Ubuntu 22.04 平台上 ...
- 🎉开发者的福音:TinyVue 组件库文档大优化!类型更详细,描述更清晰!
你好,我是 Kagol. 前言 从今年2月份开源以来,有不少朋友给我们 TinyVue 组件库提了文档优化的建议,这些建议都非常中肯,我们也在持续对文档进行优化,并且从中总结出了大家对于文档优化的一些 ...
- 基于DotNetty实现自动发布 - 自动检测代码变化
前言 很抱歉没有实现上一篇的目标:一键发布,因为工作量超出了预期,本次只实现了 Git 代码变化检测 已完成的功能 解决方案的项目发现与配置 首次发布需要手动处理 自动检测代码变化并解析出待发布的文件 ...
- springboot的缓存和redis缓存,入门级别教程
一.springboot(如果没有配置)默认使用的是jvm缓存 1.Spring框架支持向应用程序透明地添加缓存.抽象的核心是将缓存应用于方法,从而根据缓存中可用的信息减少执行次数.缓存逻辑是透明地应 ...
- [ARC144E]GCD of Path Weights
Problem Statement You are given a directed graph $G$ with $N$ vertices and $M$ edges. The vertices a ...
- Head First Java学习:第十四章-序列化和文件
第十四章 序列化和文件的输入输出 保存对象 1.什么是序列化和反序列化 在编程的世界当中,常常有这样的需求:我们需要将本地已经实例化的某个对象,通过网络传递到其他机器当中,为了满足这种需求,就有了所谓 ...
- Mybatis-Flex核心功能之@Id
1.是什么? 在 Entity 类中,MyBatis-Flex 是使用 @Id 注解来标识主键的 2.怎么玩? public @interface Id { /** * ID 生成策略,默认为 non ...
- SpringBoot整合JavaMail
1.发送简单邮件 导入依赖 implementation 'org.springframework.boot:spring-boot-starter-mail:3.0.2' 开启相关协议,获取密码~ ...