boost.log教程:loggers
logger是用户接触最多的类
- 可分为无保护和线程安全两类,线程安全的以
_mt
结尾 - logger有窄字符和宽字符的,宽字符的以
w
开头,如wlogger_mt
- logger类可复制,可创建的,可作为自定义类的成员
- boost.log提供多种logger,参见网页
直接使用
如下即可:
#include <boost/log/trivial.hpp>
int main(int, char*[])
{
BOOST_LOG_TRIVIAL(trace) << "A trace severity message";
BOOST_LOG_TRIVIAL(debug) << "A debug severity message";
BOOST_LOG_TRIVIAL(info) << "An informational severity message";
BOOST_LOG_TRIVIAL(warning) << "A warning severity message";
BOOST_LOG_TRIVIAL(error) << "An error severity message";
BOOST_LOG_TRIVIAL(fatal) << "A fatal severity message";
return 0;
}
全局logger
BOOST_LOG_INLINE_GLOBAL_LOGGER_DEFAULT(my_logger, src::logger_mt)
my_logger
是用户自定义的logger名src::logger_mt
是logger类型- 可以注册多个全局对象
注册全局logger后,可通过以下语句获取该对象:
src::logger_mt& lg = my_logger::get(); // my_logger是自己注册的全局对象名
写logger
写log的方法是通用的,如下:
logging::record rec = lg.open_record(); // lg是logger对象,logging record见后文
if (rec)
{
logging::record_ostream strm(rec);
strm << "Hello, World!";
strm.flush();
lg.push_record(boost::move(rec));
}
open_record
相当于调用了logging core的filter (如本页最开头的severity),通过检测才会返回有效的logging::record对象push_record
在logging::record对象在信息填写完成后将消息推送出去
以上代码有更简单的替换版本:
BOOST_LOG(lg) << "Hello, World!";
配合attribute写log
attribute添加在logger上和record上可实现自定义的效果,下例中:
RemoteAddress
添加到logger上,所有由这个logger发出的record都可使用```RemoteAddress``标签Message
添加在record上,那就只有这一条record有这个attribute
class network_connection
{
src::logger m_logger;
logging::attribute_set::iterator m_remote_addr;
public:
void on_connected(std::string const& remote_addr)
{
// Put the remote address into the logger to automatically attach it
// to every log record written through the logger
m_remote_addr = m_logger.add_attribute("RemoteAddress",
attrs::constant< std::string >(remote_addr)).first;
// The straightforward way of logging
if (logging::record rec = m_logger.open_record())
{
rec.attribute_values().insert("Message",
attrs::make_attribute_value(std::string("Connection established")));
m_logger.push_record(boost::move(rec));
}
}
void on_disconnected()
{
// The simpler way of logging: the above "if" condition is wrapped into a neat macro
BOOST_LOG(m_logger) << "Connection shut down";
// Remove the attribute with the remote address
m_logger.remove_attribute(m_remote_addr);
}
void on_data_received(std::size_t size)
{
// Put the size as an additional attribute
// so it can be collected and accumulated later if needed.
// The attribute will be attached only to this log record.
BOOST_LOG(m_logger) << logging::add_value("ReceivedSize", size) << "Some data received";
}
void on_data_sent(std::size_t size)
{
BOOST_LOG(m_logger) << logging::add_value("SentSize", size) << "Some data sent";
}
};
Loggers 配合 severity
相关的类共有severity_logger
、severity_logger_mt
、 wseverity_logger
和wseverity_logger_mt
4个。
这4个类都有Severity
属性,在调用open_record
函数时会先检查是否通过Severity
属性检测,通过了就会返回record。
Severity
属性说明:
- int类型
- 最好以0为起点,方便大小判断
- 全局最好使用统一的级别
Severity
可使用各种类型
// We define our own severity levels
enum severity_level
{
normal,
notification,
warning,
error,
critical
};
void logging_function()
{
// The logger implicitly adds a source-specific attribute 'Severity'
// of type 'severity_level' on construction
src::severity_logger< severity_level > slg;
BOOST_LOG_SEV(slg, normal) << "A regular message";
BOOST_LOG_SEV(slg, warning) << "Something bad is going on but I can handle it";
BOOST_LOG_SEV(slg, critical) << "Everything crumbles, shoot me now!";
}
也可如下使用:
void default_severity()
{
// The default severity can be specified in constructor.
src::severity_logger< severity_level > error_lg(keywords::severity = error);
BOOST_LOG(error_lg) << "An error level log record (by default)";
// The explicitly specified level overrides the default
BOOST_LOG_SEV(error_lg, warning) << "A warning level log record (overrode the default)";
}
不使用宏的情况:
void manual_logging()
{
src::severity_logger< severity_level > slg;
logging::record rec = slg.open_record(keywords::severity = normal);
if (rec)
{
logging::record_ostream strm(rec);
strm << "A regular message";
strm.flush();
slg.push_record(boost::move(rec));
}
}
logger配合channel
相关的类共有channel_logger
、channel_logger_mt
、 wchannel_logger
和wchannel_logger_mt
4类
这4个类都有Channel
属性
这个类可用来区分不同的log
示例代码:
class network_connection
{
src::channel_logger< > m_net, m_stat;
logging::attribute_set::iterator m_net_remote_addr, m_stat_remote_addr;
public:
network_connection() :
// We can dump network-related messages through this logger
// and be able to filter them later
m_net(keywords::channel = "net"),
// We also can separate statistic records in a different channel
// in order to route them to a different sink
m_stat(keywords::channel = "stat")
{
}
void on_connected(std::string const& remote_addr)
{
// Add the remote address to both channels
attrs::constant< std::string > addr(remote_addr);
m_net_remote_addr = m_net.add_attribute("RemoteAddress", addr).first;
m_stat_remote_addr = m_stat.add_attribute("RemoteAddress", addr).first;
// Put message to the "net" channel
BOOST_LOG(m_net) << "Connection established";
}
void on_disconnected()
{
// Put message to the "net" channel
BOOST_LOG(m_net) << "Connection shut down";
// Remove the attribute with the remote address
m_net.remove_attribute(m_net_remote_addr);
m_stat.remove_attribute(m_stat_remote_addr);
}
void on_data_received(std::size_t size)
{
BOOST_LOG(m_stat) << logging::add_value("ReceivedSize", size) << "Some data received";
}
void on_data_sent(std::size_t size)
{
BOOST_LOG(m_stat) << logging::add_value("SentSize", size) << "Some data sent";
}
};
使用宏的简化版本
// Define a global logger
BOOST_LOG_INLINE_GLOBAL_LOGGER_CTOR_ARGS(my_logger, src::channel_logger_mt< >, (keywords::channel = "general"))
class network_connection
{
std::string m_remote_addr;
public:
void on_connected(std::string const& remote_addr)
{
m_remote_addr = remote_addr;
// Put message to the "net" channel
BOOST_LOG_CHANNEL(my_logger::get(), "net")
<< logging::add_value("RemoteAddress", m_remote_addr)
<< "Connection established";
}
void on_disconnected()
{
// Put message to the "net" channel
BOOST_LOG_CHANNEL(my_logger::get(), "net")
<< logging::add_value("RemoteAddress", m_remote_addr)
<< "Connection shut down";
m_remote_addr.clear();
}
void on_data_received(std::size_t size)
{
BOOST_LOG_CHANNEL(my_logger::get(), "stat")
<< logging::add_value("RemoteAddress", m_remote_addr)
<< logging::add_value("ReceivedSize", size)
<< "Some data received";
}
void on_data_sent(std::size_t size)
{
BOOST_LOG_CHANNEL(my_logger::get(), "stat")
<< logging::add_value("RemoteAddress", m_remote_addr)
<< logging::add_value("SentSize", size)
<< "Some data sent";
}
};
logger另有处理异常的版本和自定义混合类别的功能
再谈全局logger
使用全局logger,而在namespace内使用logger的原因:
- c++没有规定namespace的初始化顺序
- namespace的初始化并不是线程安全的
- 在头文件的namespace中设定logger十分麻烦,因为还需要一个cpp文件配合
- namespace内的变量在其内可访问,换句话说,模块B引用模块A,模块B内会创建同名的变量
使用全局logger可避免这些问题。创建全局logger:
BOOST_LOG_INLINE_GLOBAL_LOGGER_DEFAULT(my_logger, src::severity_logger_mt< >)
如果创建logger时需要传递参数,那么使用如下的宏,宏中的CTOR
代表constructor,ARGS
代表arguments
BOOST_LOG_INLINE_GLOBAL_LOGGER_CTOR_ARGS(
my_logger,
src::severity_channel_logger< >,
(keywords::severity = error)(keywords::channel = "my_channel"))
如果前两个宏不能满足要求,还有第三个宏
BOOST_LOG_INLINE_GLOBAL_LOGGER_INIT(my_logger, src::severity_logger_mt)
{
// Do something that needs to be done on logger initialization,
// e.g. add a stop watch attribute.
src::severity_logger_mt< > lg;
lg.add_attribute("StopWatch", attrs::timer());
// The initializing routine must return the logger instance
return lg;
}
分开头文件和CPP文件设置全局logger
虽然上一节的宏可以设置全局logger,但在头文件中定义还是会有些麻烦。于是boost.log提供了在头文件和CPP文件中配合使用的宏:
BOOST_LOG_GLOBAL_LOGGER
声明logger,类似于前文的BOOST_LOG_INLINE_GLOBAL_LOGGER*
BOOST_LOG_GLOBAL_LOGGER_INIT
, BOOST_LOG_GLOBAL_LOGGER_DEFAULT
和 BOOST_LOG_GLOBAL_LOGGER_CTOR_ARGS
使用类似于BOOST_LOG_INLINE_GLOBAL_LOGGER*
,只不过要用在CPP文件中
// my_logger.h
// ===========
BOOST_LOG_GLOBAL_LOGGER(my_logger, src::severity_logger_mt)
// my_logger.cpp
// =============
#include "my_logger.h"
BOOST_LOG_GLOBAL_LOGGER_INIT(my_logger, src::severity_logger_mt)
{
src::severity_logger_mt< > lg;
lg.add_attribute("StopWatch", attrs::timer());
return lg;
}
官方简单教程
官方logger高级教程
转自:https://blog.csdn.net/LaineGates/article/details/90137804