Logging records
logging record中的所有信息,包括message text,都会被filters, formatters 和 sinks处理。
logging record特性:
- 不能复制,只能被移动boost::move()。它由logging core在filter之后创建,此时内容为空,随后attribute value会由attribute生成并添加到log record
- logging record可在formatting和sink时继续添加attributes
- 多线程环境中,logging record与创建它的线程绑定,所以logging record不能在线程中移动。
读取这些信息的方式有几种:
通过 logging::visit
和 logging::value_ref
更详细参见网页
enum severity_level { ... };
std::ostream& operator<< (std::ostream& strm, severity_level level);
struct print_visitor
{
typedef void result_type;
result_type operator() (severity_level level) const
{
std::cout << level << std::endl;
};
};
// Prints severity level through visitation API
void print_severity_visitation(logging::record const& rec)
{
logging::visit< severity_level >("Severity", rec, print_visitor());
}
// Prints severity level through extraction API
void print_severity_extraction(logging::record const& rec)
{
logging::value_ref< severity_level > level = logging::extract< severity_level >("Severity", rec);
std::cout << level << std::endl;
}
通过 attribute_values
访问所有属性
更详细参见网页
// Prints severity level by searching the attribute values
void print_severity_lookup(logging::record const& rec)
{
logging::attribute_value_set const& values = rec.attribute_values();
logging::attribute_value_set::const_iterator it = values.find("Severity");
if (it != values.end())
{
logging::attribute_value const& value = it->second;
// A single attribute value can also be visited or extracted
std::cout << value.extract< severity_level >() << std::endl;
}
}
直接通过下标方式访问
BOOST_LOG_ATTRIBUTE_KEYWORD(severity, "Severity", severity_level)
// Prints severity level by using the subscript operator
void print_severity_subscript(logging::record const& rec)
{
// Use the attribute keyword to communicate the name and type of the value
logging::value_ref< severity_level, tag::severity > level = rec[severity];
std::cout << level << std::endl;
}
Record view
与logging record相似, record用来填充信息,record view用来后续处理:
- record view不可变,可防止formatter及sink修改它
- record view可复制,因为内容不可改,使用浅复制成本很低
boost会自动在lock函数被调用时,为record创建record view:
- record view不会绑定到线程
- record 会在lock结束后变空值,因为record只被处理一次
Logging core
logging core是库的核心,提供:
- 维护全局和各线程的attribute sets
- 处理log record的全局过滤
- 应用sink的filter在sink间传递log record
- 提供全局的exception handler
- 提供全局的log record输入口
- 提供flush强制输出
访问方式
boost::shared_ptr< logging::core > core = logging::core::get();
Attribute sets
添加/删除全局属性add_global_attribute
和remove_global_attribute
添加/删除线程属性add_thread_attribute
和remove_thread_attribute
void foo()
{
boost::shared_ptr< logging::core > core = logging::core::get();
// Add a global attribute
// 返回值第一个参数是其被添加后的索引,bool代表是否添加成功
std::pair< logging::attribute_set::iterator, bool > res =
core->add_global_attribute("LineID", attrs::counter< unsigned int >());
// Do something ...
// Remove the added attribute
core->remove_global_attribute(res.first);
}
logging::core的所有方法都是线程安全的,但索引不能保证线程安全
获取/设置全局属性get_global_attributes
和set_global_attributes
获取/设置线程属性get_thread_attributes
和set_thread_attributes
Global filtering
filter读入一组参数,返回此record是否通过
设置/清除filter的函数set_filter
/ reset_filter
,filter没有设置,相当于所有log record可通过
通过set_logging_enabled
,可设置filter是否生效,比较设置filter更高效。
Sink management
添加/删除sink的函数,add_sink
和remove_sink
。添加的sink会保存到logging core中,但sink的执行顺序是不确定的。
void foo()
{
boost::shared_ptr< logging::core > core = logging::core::get();
// Set a sink that will write log records to the console
boost::shared_ptr< sinks::text_ostream_backend > backend =
boost::make_shared< sinks::text_ostream_backend >();
backend->add_stream(
boost::shared_ptr< std::ostream >(&std::clog, boost::null_deleter()));
typedef sinks::unlocked_sink< sinks::text_ostream_backend > sink_t;
boost::shared_ptr< sink_t > sink = boost::make_shared< sink_t >(backend);
core->add_sink(sink);
// ...
// Remove the sink
core->remove_sink(sink);
}
Exception handling
添加异常处理类,通过set_exception_handler
设置,其参数是无参数函数,在catch语句中被调用。
logging core中的异常处理类只应该处理通用错误。
Logging sinks 和 sources 可做更细致的异常处理,参见
sink异常处理和source异常处理
struct my_handler
{
typedef void result_type;
void operator() (std::runtime_error const& e) const
{
std::cout << "std::runtime_error: " << e.what() << std::endl;
}
void operator() (std::logic_error const& e) const
{
std::cout << "std::logic_error: " << e.what() << std::endl;
throw;
}
};
void init_exception_handler()
{
// Setup a global exception handler that will call my_handler::operator()
// for the specified exception types
logging::core::get()->set_exception_handler(logging::make_exception_handler<
std::runtime_error, /*处理的错误类型*/
std::logic_error
>(my_handler()));
}
Feeding log records
logging core最重要的功能之一就是创建和推送log record,实现函数分别为open_record
和push_record
.
-
open_record
收集global, thread-specific 和 source-specific的属性,判断是否会被filter掉,如果没有被filter掉(至少有一个sink接收这个record),函数会返回一个log record对象 -
push_record
在由open_record
获得的record对象填写完内容后调用。之后record view对象会从record对象中生成,并传给接收它的多个sink,这个过程中会发生formatting及保存到文件等操作,视情况而不同。随后record对象被销毁。
void logging_function(logging::attribute_set const& attrs)
{
boost::shared_ptr< logging::core > core = logging::core::get();
// Attempt to open a log record
logging::record rec = core->open_record(attrs);
if (rec)
{
// Ok, the record is accepted. Compose the message now.
logging::record_ostream strm(rec);
strm << "Hello, World!";
strm.flush();
// Deliver the record to the sinks.
core->push_record(boost::move(rec));
}
}