C++ Boost log日志库超详细讲解
无水先生 人气:0一、说明
应用程序库是指通常专门用于独立应用程序开发而不用于库开发的库。
- Boost.Log 是一个日志库。
- Boost.ProgramOptions 是一个用于定义和解析命令行选项的库。
- Boost.Serialization 允许您序列化对象,例如,将它们保存到文件或从文件加载它们。
- Boost.Uuid 支持使用 UUID。
具体内容
二、库Boost.Log
Boost.Log 是 Boost 中的日志记录库。它支持众多后端以各种格式记录数据。通过以不同方式捆绑服务和转发日志条目的前端访问后端。例如,有一个前端使用线程异步转发日志条目。前端可以有过滤器来忽略某些日志条目。他们定义了如何将日志条目格式化为字符串。所有这些功能都是可扩展的,这使得 Boost.Log 成为一个强大的库。
示例 62.1。后端、前端、核心和记录器
#include <boost/log/common.hpp> #include <boost/log/sinks.hpp> #include <boost/log/sources/logger.hpp> #include <boost/utility/empty_deleter.hpp> #include <boost/shared_ptr.hpp> #include <iostream> using namespace boost::log; int main() { typedef sinks::asynchronous_sink<sinks::text_ostream_backend> text_sink; boost::shared_ptr<text_sink> sink = boost::make_shared<text_sink>(); boost::shared_ptr<std::ostream> stream{&std::clog, boost::empty_deleter{}}; sink->locked_backend()->add_stream(stream); core::get()->add_sink(sink); sources::logger lg; BOOST_LOG(lg) << "note"; sink->flush(); }
示例 62.1 介绍了 Boost.Log 的基本组件。 Boost.Log 使您可以访问后端、前端、核心和记录器:
后端决定数据写入的位置。 boost::log::sinks::text_ostream_backend 使用 std::ostream 类型的流进行初始化,并将日志条目写入其中。
前端是核心和后端之间的连接。它们实现了不需要由每个单独的后端实现的各种功能。例如,可以将过滤器添加到前端以选择将哪些日志条目转发到后端,哪些不转发。
示例 62.1 使用前端 boost::log::sinks::asynchronous_sink。即使不使用过滤器,也必须使用前端。 boost::log::sinks::asynchronous_sink 使用一个线程将日志条目异步转发到后端。这可以提高性能但会延迟写入操作。
核心是所有日志条目路由通过的中央组件。它是作为单例实现的。要获取指向核心的指针,请调用 boost::log::core::get()。
必须将前端添加到核心才能接收日志条目。日志条目是否转发到前端取决于核心中的过滤器。过滤器可以在前端或核心中注册。在核心注册的过滤器是全局的,在前端注册的过滤器是本地的。如果日志条目被核心过滤掉,则不会转发到任何前端。如果它被一个前端过滤了,它仍然可以被其他前端处理并转发给它们的后端。
记录器是 Boost.Log 中您最常使用的组件。虽然只有在初始化日志库时才能访问后端、前端和核心,但每次写入日志条目时都会使用一个记录器。记录器将条目转发给核心。
示例 62.1 中的记录器属于 boost::log::sources::logger 类型。这是最简单的记录器。当你想写一个日志条目时,使用宏 BOOST_LOG 并将记录器作为参数传递。日志条目是通过将数据写入宏来创建的,就好像它是 std::ostream 类型的流一样。
后端、前端、核心和记录器协同工作。 boost::log::sinks::asynchronous_sink 是一个前端,它是一个接收后端 boost::log::sinks::text_ostream_backend 作为参数的模板。之后,前端使用 boost::shared_ptr 实例化。智能指针需要在核心中注册前端:对 boost::log::core::add_sink() 的调用需要一个 boost::shared_ptr。
因为后端是前端的模板参数,所以只能在前端实例化后配置。后端决定这是如何完成的。后端 boost::log::sinks::text_ostream_backend 提供成员函数 add_stream() 添加流。您可以向 boost::log::sinks::text_ostream_backend 添加多个流。其他后端提供不同的成员函数进行配置。有关详细信息,请参阅文档。
为了访问后端,所有前端都提供成员函数 locked_backend()。此成员函数称为 locked_backend(),因为它返回一个指针,只要该指针存在,该指针就会提供对后端的同步访问。您可以通过 locked_backend() 返回的指针从多个线程访问后端,而无需自己同步访问。
您可以使用默认构造函数实例化一个记录器,例如 boost::log::sources::logger。记录器自动调用 boost::log::core::get() 将日志条目转发到核心。
您可以在没有宏的情况下访问记录器。记录器是具有您可以调用的成员函数的对象。但是,像 BOOST_LOG 这样的宏可以更轻松地编写日志条目。如果没有宏,就不可能用一行代码编写日志条目。
示例 62.1 在 main() 的末尾调用 boost::log::sinks::asynchronous_sink::flush()。此调用是必需的,因为前端是异步的并且使用线程来转发日志条目。该调用确保所有缓冲的日志条目都传递到后端并被写入。如果不调用 flush(),该示例可能会在不显示注释的情况下终止。
示例 62.2。带有过滤器的 boost::sources::severity_logger
#include <boost/log/common.hpp> #include <boost/log/sinks.hpp> #include <boost/log/sources/severity_logger.hpp> #include <boost/utility/empty_deleter.hpp> #include <boost/shared_ptr.hpp> #include <iostream> using namespace boost::log; bool only_warnings(const attribute_value_set &set) { return set["Severity"].extract<int>() > 0; } int main() { typedef sinks::asynchronous_sink<sinks::text_ostream_backend> text_sink; boost::shared_ptr<text_sink> sink = boost::make_shared<text_sink>(); boost::shared_ptr<std::ostream> stream{&std::clog, boost::empty_deleter{}}; sink->locked_backend()->add_stream(stream); sink->set_filter(&only_warnings); core::get()->add_sink(sink); sources::severity_logger<int> lg; BOOST_LOG(lg) << "note"; BOOST_LOG_SEV(lg, 0) << "another note"; BOOST_LOG_SEV(lg, 1) << "warning"; sink->flush(); }
示例 62.2 基于示例 62.1,但它用记录器 boost::sources::severity_logger 替换了 boost::sources::logger。此记录器将日志级别的属性添加到每个日志条目。您可以使用宏 BOOST_LOG_SEV 来设置日志级别。
日志级别的类型取决于传递给 boost::sources::severity_logger 的模板参数。示例 62.2 使用 int。这就是将 0 和 1 之类的数字传递给 BOOST_LOG_SEV 的原因。如果使用 BOOST_LOG,日志级别设置为 0。
示例 62.2 还调用 set_filter() 在前端注册过滤器。为每个日志条目调用过滤器函数。如果该函数返回 true,日志条目将转发到后端。示例 62.2 定义了函数 only_warnings(),其返回值为 bool 类型。
only_warnings() 需要一个类型为 boost::log::attribute_value_set 的参数。此类型表示在日志记录框架中传递的日志条目。 boost::log::record 是另一种日志条目类型,类似于 boost::log::attribute_value_set 的包装器。此类型提供成员函数 attribute_values(),它检索对 boost::log::attribute_value_set 的引用。过滤器函数直接接收 boost::log::attribute_value_set 而没有 boost::log::record。 boost::log::attribute_value_set 存储键/值对。将其视为 std::unordered_map。
日志条目由属性组成。属性有名称和值。您可以自己创建属性。它们也可以自动创建——例如由记录器创建。事实上,这就是 Boost.Log 提供多个记录器的原因。 boost::log::sources::severity_logger 向每个日志条目添加一个名为 Severity 的属性。该属性存储日志级别。这样过滤器就可以检查日志条目的日志级别是否大于 0。
boost::log::attribute_value_set 提供了几个成员函数来访问属性。成员函数类似于 std::unordered_map 提供的成员函数。例如,boost::log::attribute_value_set 重载运算符 operator[]。此运算符返回其名称作为参数传递的属性的值。如果该属性不存在,则会创建它。
属性名称的类型是 boost::log::attribute_name。此类提供了一个接受字符串的构造函数,因此您可以将字符串直接传递给 operator[],如示例 62.2 所示。
属性值的类型是 boost::log::attribute_value。此类提供成员函数来接收属性原始类型的值。因为日志级别是一个 int 值,所以 int 作为模板参数传递给 extract()。
boost::log::attribute_value 还定义了成员函数 extract_or_default() 和 extract_or_throw()。如果类型转换失败,extract() 会返回一个使用默认构造函数创建的值——例如,如果是 int,则为 0。 extract_or_default() 返回一个默认值,该值作为另一个参数传递给该成员函数。 extract_or_throw() 在发生错误时抛出类型为 boost::log::runtime_error 的异常。
对于类型安全的转换,Boost.Log 提供访问者函数 boost::log::visit(),您可以使用它代替 extract()。
示例 62.2 显示警告。此日志条目的日志级别大于 0,因此未被过滤。
示例 62.3。使用 set_formatter() 更改日志条目的格式
#include <boost/log/common.hpp> #include <boost/log/sinks.hpp> #include <boost/log/sources/severity_logger.hpp> #include <boost/utility/empty_deleter.hpp> #include <boost/shared_ptr.hpp> #include <iostream> using namespace boost::log; void severity_and_message(const record_view &view, formatting_ostream &os) { os << view.attribute_values()["Severity"].extract<int>() << ": " << view.attribute_values()["Message"].extract<std::string>(); } int main() { typedef sinks::asynchronous_sink<sinks::text_ostream_backend> text_sink; boost::shared_ptr<text_sink> sink = boost::make_shared<text_sink>(); boost::shared_ptr<std::ostream> stream{&std::clog, boost::empty_deleter{}}; sink->locked_backend()->add_stream(stream); sink->set_formatter(&severity_and_message); core::get()->add_sink(sink); sources::severity_logger<int> lg; BOOST_LOG_SEV(lg, 0) << "note"; BOOST_LOG_SEV(lg, 1) << "warning"; sink->flush(); }
日志条目由属性组成。属性有名称和值。您可以自己创建属性。它们也可以自动创建——例如由记录器创建。事实上,这就是 Boost.Log 提供多个记录器的原因。 boost::log::sources::severity_logger 向每个日志条目添加一个名为 Severity 的属性。该属性存储日志级别。这样过滤器就可以检查日志条目的日志级别是否大于 0。
boost::log::attribute_value_set 提供了几个成员函数来访问属性。成员函数类似于 std::unordered_map 提供的成员函数。例如,boost::log::attribute_value_set 重载运算符 operator[]。此运算符返回其名称作为参数传递的属性的值。如果该属性不存在,则会创建它。
属性名称的类型是 boost::log::attribute_name。此类提供了一个接受字符串的构造函数,因此您可以将字符串直接传递给 operator[],如示例 62.2 所示。
属性值的类型是 boost::log::attribute_value。此类提供成员函数来接收属性原始类型的值。因为日志级别是一个 int 值,所以 int 作为模板参数传递给 extract()。
boost::log::attribute_value 还定义了成员函数 extract_or_default() 和 extract_or_throw()。如果类型转换失败,extract() 会返回一个使用默认构造函数创建的值——例如,如果是 int,则为 0。 extract_or_default() 返回一个默认值,该值作为另一个参数传递给该成员函数。 extract_or_throw() 在发生错误时抛出类型为 boost::log::runtime_error 的异常。
对于类型安全的转换,Boost.Log 提供访问者函数 boost::log::visit(),您可以使用它代替 extract()。
示例 62.2 显示警告。此日志条目的日志级别大于 0,因此未被过滤。
示例 62.3。使用 set_formatter() 更改日志条目的格式
#include <boost/log/common.hpp> #include <boost/log/sinks.hpp> #include <boost/log/sources/severity_logger.hpp> #include <boost/log/expressions.hpp> #include <boost/utility/empty_deleter.hpp> #include <boost/shared_ptr.hpp> #include <iostream> using namespace boost::log; int main() { typedef sinks::asynchronous_sink<sinks::text_ostream_backend> text_sink; boost::shared_ptr<text_sink> sink = boost::make_shared<text_sink>(); boost::shared_ptr<std::ostream> stream{&std::clog, boost::empty_deleter{}}; sink->locked_backend()->add_stream(stream); sink->set_filter(expressions::attr<int>("Severity") > 0); sink->set_formatter(expressions::stream << expressions::attr<int>("Severity") << ": " << expressions::smessage); core::get()->add_sink(sink); sources::severity_logger<int> lg; BOOST_LOG_SEV(lg, 0) << "note"; BOOST_LOG_SEV(lg, 1) << "warning"; BOOST_LOG_SEV(lg, 2) << "error"; sink->flush(); }
示例 62.4 同时使用了过滤器和格式化函数。这次函数作为 lambda 函数实现——不是 C++11 lambda 函数,而是 Boost.Phoenix lambda 函数。
Boost.Log 为命名空间 boost::log::expressions 中的 lambda 函数提供助手。例如,boost::log::expressions::stream 代表流。 boost::log::expressions::smessage 提供对 BOOST_LOG 等宏右侧所有内容的访问。您可以使用 boost::log::expressions::attr() 来访问任何属性。示例 62.4 可以使用 attr<std::string>("Message") 而不是消息。
示例 62.4 显示 1:警告和 2:错误。
示例 62.5。为属性定义关键字
#include <boost/log/common.hpp> #include <boost/log/sinks.hpp> #include <boost/log/sources/severity_logger.hpp> #include <boost/log/expressions.hpp> #include <boost/utility/empty_deleter.hpp> #include <boost/shared_ptr.hpp> #include <iostream> using namespace boost::log; BOOST_LOG_ATTRIBUTE_KEYWORD(severity, "Severity", int) int main() { typedef sinks::asynchronous_sink<sinks::text_ostream_backend> text_sink; boost::shared_ptr<text_sink> sink = boost::make_shared<text_sink>(); boost::shared_ptr<std::ostream> stream{&std::clog, boost::empty_deleter{}}; sink->locked_backend()->add_stream(stream); sink->set_filter(severity > 0); sink->set_formatter(expressions::stream << severity << ": " << expressions::smessage); core::get()->add_sink(sink); sources::severity_logger<int> lg; BOOST_LOG_SEV(lg, 0) << "note"; BOOST_LOG_SEV(lg, 1) << "warning"; BOOST_LOG_SEV(lg, 2) << "error"; sink->flush(); }
Boost.Log 支持用户定义的关键字。您可以使用宏 BOOST_LOG_ATTRIBUTE_KEYWORD 定义关键字来访问属性,而不必将属性名称作为字符串重复传递给 boost::log::expressions::attr()。
示例 62.5 使用宏 BOOST_LOG_ATTRIBUTE_KEYWORD 来定义关键字严重性。该宏需要三个参数:关键字名称、字符串形式的属性名称和属性类型。 new 关键字可用于过滤和格式化 lambda 函数。这意味着您不限于使用由 Boost.Log 提供的关键字,例如 boost::log::expressions::smessage – 您还可以定义新的关键字。
到目前为止,在所有示例中,使用的属性都是在 Boost.Log 中定义的。示例 62.6 显示了如何创建用户定义的属性。
示例 62.6。定义属性
#include <boost/log/common.hpp> #include <boost/log/sinks.hpp> #include <boost/log/sources/severity_logger.hpp> #include <boost/log/expressions.hpp> #include <boost/log/attributes.hpp> #include <boost/log/support/date_time.hpp> #include <boost/utility/empty_deleter.hpp> #include <boost/shared_ptr.hpp> #include <iostream> using namespace boost::log; BOOST_LOG_ATTRIBUTE_KEYWORD(severity, "Severity", int) BOOST_LOG_ATTRIBUTE_KEYWORD(counter, "LineCounter", int) BOOST_LOG_ATTRIBUTE_KEYWORD(timestamp, "Timestamp", boost::posix_time::ptime) int main() { typedef sinks::asynchronous_sink<sinks::text_ostream_backend> text_sink; boost::shared_ptr<text_sink> sink = boost::make_shared<text_sink>(); boost::shared_ptr<std::ostream> stream{&std::clog, boost::empty_deleter{}}; sink->locked_backend()->add_stream(stream); sink->set_filter(severity > 0); sink->set_formatter(expressions::stream << counter << " - " << severity << ": " << expressions::smessage << " (" << timestamp << ")"); core::get()->add_sink(sink); core::get()->add_global_attribute("LineCounter", attributes::counter<int>{}); sources::severity_logger<int> lg; BOOST_LOG_SEV(lg, 0) << "note"; BOOST_LOG_SEV(lg, 1) << "warning"; { BOOST_LOG_SCOPED_LOGGER_ATTR(lg, "Timestamp", attributes::local_clock{}) BOOST_LOG_SEV(lg, 2) << "error"; } BOOST_LOG_SEV(lg, 2) << "another error"; sink->flush(); }
您可以通过在核心上调用 add_global_attribute() 来创建全局属性。该属性是全局的,因为它会自动添加到每个日志条目中。
add_global_attribute() 需要两个参数:新属性的名称和类型。名称作为字符串传递。对于您使用命名空间 boost::log::attributes 中的类的类型,它提供类来定义不同的属性。示例 62.6 使用 boost::log::attributes::counter 来定义属性 LineCounter,它为每个日志条目添加一个行号。此属性将从 1 开始对日志条目进行编号。
add_global_attribute() 不是函数模板。 boost::log::attributes::counter 不作为模板参数传递。属性类型必须实例化并作为对象传递。
示例 62.6 使用名为时间戳的第二个属性。这是一个使用 BOOST_LOG_SCOPED_LOGGER_ATTR 创建的范围属性。此宏将属性添加到记录器。第一个参数是logger,第二个是属性名,第三个是属性对象。属性对象的类型是 boost::log::attribute::local_clock。该属性设置为每个日志条目的当前时间。
属性时间戳仅添加到日志条目“错误”。时间戳仅存在于使用 BOOST_LOG_SCOPED_LOGGER_ATTR 的范围内。当范围结束时,该属性将被删除。 BOOST_LOG_SCOPED_LOGGER_ATTR 类似于对 add_attribute() 和 remove_attribute() 的调用。
与示例 62.5 一样,示例 62.6 使用宏 BOOST_LOG_ATTRIBUTE_KEYWORD 为新属性定义关键字。 format 函数访问关键字以写入行号和当前时间。对于那些未定义属性时间戳的日志条目,时间戳的值将为空字符串。
示例 62.7。过滤器和格式的辅助函数
#include <boost/log/common.hpp> #include <boost/log/sinks.hpp> #include <boost/log/sources/severity_logger.hpp> #include <boost/log/expressions.hpp> #include <boost/log/attributes.hpp> #include <boost/log/support/date_time.hpp> #include <boost/utility/empty_deleter.hpp> #include <boost/shared_ptr.hpp> #include <iostream> #include <iomanip> using namespace boost::log; BOOST_LOG_ATTRIBUTE_KEYWORD(severity, "Severity", int) BOOST_LOG_ATTRIBUTE_KEYWORD(counter, "LineCounter", int) BOOST_LOG_ATTRIBUTE_KEYWORD(timestamp, "Timestamp", boost::posix_time::ptime) int main() { typedef sinks::asynchronous_sink<sinks::text_ostream_backend> text_sink; boost::shared_ptr<text_sink> sink = boost::make_shared<text_sink>(); boost::shared_ptr<std::ostream> stream{&std::clog, boost::empty_deleter{}}; sink->locked_backend()->add_stream(stream); sink->set_filter(expressions::is_in_range(severity, 1, 3)); sink->set_formatter(expressions::stream << std::setw(5) << counter << " - " << severity << ": " << expressions::smessage << " (" << expressions::format_date_time(timestamp, "%H:%M:%S") << ")"); core::get()->add_sink(sink); core::get()->add_global_attribute("LineCounter", attributes::counter<int>{}); sources::severity_logger<int> lg; BOOST_LOG_SEV(lg, 0) << "note"; BOOST_LOG_SEV(lg, 1) << "warning"; { BOOST_LOG_SCOPED_LOGGER_ATTR(lg, "Timestamp", attributes::local_clock{}) BOOST_LOG_SEV(lg, 2) << "error"; } BOOST_LOG_SEV(lg, 2) << "another error"; sink->flush(); }
Boost.Log 为过滤器和格式提供了大量的辅助函数。示例 62.7 调用助手 boost::log::expressions::is_in_range() 来过滤日志级别超出范围的日志条目。 boost::log::expressions::is_in_range() 期望属性作为它的第一个参数,下限和上限作为它的第二和第三个参数。与迭代器一样,上限是唯一的,不属于范围。
boost::log::expressions::format_date_time() 在格式函数中被调用。它用于格式化时间点。示例 62.7 使用 boost::log::expressions::format_date_time() 来写入没有日期的时间。您还可以在格式函数中使用标准库中的操纵器。示例 62.7 使用 std::setw() 设置计数器的宽度。
示例 62.8。几个记录器、前端和后端
#include <boost/log/common.hpp> #include <boost/log/sinks.hpp> #include <boost/log/sources/severity_logger.hpp> #include <boost/log/sources/channel_logger.hpp> #include <boost/log/expressions.hpp> #include <boost/log/attributes.hpp> #include <boost/log/utility/string_literal.hpp> #include <boost/utility/empty_deleter.hpp> #include <boost/shared_ptr.hpp> #include <iostream> #include <string> using namespace boost::log; BOOST_LOG_ATTRIBUTE_KEYWORD(severity, "Severity", int) BOOST_LOG_ATTRIBUTE_KEYWORD(channel, "Channel", std::string) int main() { typedef sinks::asynchronous_sink<sinks::text_ostream_backend> ostream_sink; boost::shared_ptr<ostream_sink> ostream = boost::make_shared<ostream_sink>(); boost::shared_ptr<std::ostream> clog{&std::clog, boost::empty_deleter{}}; ostream->locked_backend()->add_stream(clog); core::get()->add_sink(ostream); typedef sinks::synchronous_sink<sinks::text_multifile_backend> multifile_sink; boost::shared_ptr<multifile_sink> multifile = boost::make_shared<multifile_sink>(); multifile->locked_backend()->set_file_name_composer( sinks::file::as_file_name_composer(expressions::stream << channel.or_default<std::string>("None") << "-" << severity.or_default(0) << ".log")); core::get()->add_sink(multifile); sources::severity_logger<int> severity_lg; sources::channel_logger<> channel_lg{keywords::channel = "Main"}; BOOST_LOG_SEV(severity_lg, 1) << "severity message"; BOOST_LOG(channel_lg) << "channel message"; ostream->flush(); }
示例 62.8 使用了多个记录器、前端和后端。除了使用类 boost::log::sinks::asynchronous_sink、boost::log::sinks::text_ostream_backend 和 boost::log::sources::severity_logger,该示例还使用了前端 boost:: log::sinks::synchronous_sink、后端 boost::log::sinks::text_multifile_backend 和记录器 boost::log::sources::channel_logger。
前端 boost::log::sinks::synchronous_sink 提供对后端的同步访问,即使后端不是线程安全的,它也允许您在多线程应用程序中使用后端。
boost::log::sinks::asynchronous_sink 和 boost::log::sinks::synchronous_sink 这两个前端的区别在于后者不基于线程。日志条目在同一线程中传递到后端。
示例 62.8 使用前端 boost::log::sinks::synchronous_sink 和后端 boost::log::sinks::text_multifile_backend。该后端将日志条目写入一个或多个文件。文件名是根据 set_file_name_composer() 传递给后端的规则创建的。如果您使用独立函数 boost::log::sinks::file::as_file_name_composer(),如示例中所示,则可以将规则创建为 lambda 函数,并使用与格式函数相同的构建块。但是,这些属性不用于创建写入后端的字符串。相反,该字符串将是日志条目将写入的文件的名称。
示例 62.8 使用关键字 channel 和 severity,它们是用宏 BOOST_LOG_ATTRIBUTE_KEYWORD 定义的。它们指的是属性 Channel 和 Severity。如果未设置属性,则对关键字调用成员函数 or_default() 以传递默认值。如果写入日志条目但未设置通道和严重性,则该条目将写入文件 None-0.log。如果日志条目以日志级别 1 写入,它将存储在文件 None-1.log 中。如果日志级别为 1 且通道名为 Main,则日志条目将保存在文件 Main-1.log 中。
属性 Channel 由记录器 boost::log::sources::channel_logger 定义。构造函数需要一个通道名称。名称不能作为字符串直接传递。相反,它必须作为命名参数传递。这就是为什么该示例使用 keywords::channel = "Main",即使 boost::log::sources::channel_logger 不接受任何其他参数。
请注意,命名参数 boost::log::keywords::channel 与您使用宏 BOOST_LOG_ATTRIBUTE_KEYWORD 创建的关键字无关。
boost::log::sources::channel_logger 识别来自程序不同组件的日志条目。组件可以使用它们自己的 boost::log::sources::channel_logger 类型的对象,为它们指定唯一的名称。如果组件只访问它们自己的记录器,那么特定日志条目来自哪个组件就很清楚了。
示例 62.9。集中处理异常
#include <boost/log/common.hpp> #include <boost/log/sinks.hpp> #include <boost/log/sources/logger.hpp> #include <boost/log/utility/exception_handler.hpp> #include <boost/log/exceptions.hpp> #include <boost/utility/empty_deleter.hpp> #include <boost/shared_ptr.hpp> #include <iostream> #include <exception> using namespace boost::log; struct handler { void operator()(const runtime_error &ex) const { std::cerr << "boost::log::runtime_error: " << ex.what() << '\n'; } void operator()(const std::exception &ex) const { std::cerr << "std::exception: " << ex.what() << '\n'; } }; int main() { typedef sinks::synchronous_sink<sinks::text_ostream_backend> text_sink; boost::shared_ptr<text_sink> sink = boost::make_shared<text_sink>(); boost::shared_ptr<std::ostream> stream{&std::clog, boost::empty_deleter{}}; sink->locked_backend()->add_stream(stream); core::get()->add_sink(sink); core::get()->set_exception_handler( make_exception_handler<runtime_error, std::exception>(handler{})); sources::logger lg; BOOST_LOG(lg) << "note"; }
Boost.Log 提供了在日志框架中集中处理异常的选项。这意味着您不需要将每个 BOOST_LOG 包装在一个 try 块中来处理 catch 中的异常。
示例 62.9 调用成员函数 set_exception_handler()。核心提供此成员函数来注册处理程序。日志框架中的所有异常都将传递给该处理程序。处理程序作为函数对象实现。它必须为每个预期的异常类型重载 operator()。该函数对象的实例通过函数模板 boost::log::make_exception_handler() 传递给 set_exception_handler()。您要处理的所有异常类型都必须作为模板参数传递给 boost::log::make_exception_handler()。
函数 boost::log::make_exception_suppressor() 让您丢弃日志框架中的所有异常。您调用此函数而不是 boost::log::make_exception_handler()。
示例 62.10。定义全局记录器的宏
#include <boost/log/common.hpp> #include <boost/log/sinks.hpp> #include <boost/log/sources/logger.hpp> #include <boost/utility/empty_deleter.hpp> #include <boost/shared_ptr.hpp> #include <iostream> #include <exception> using namespace boost::log; BOOST_LOG_INLINE_GLOBAL_LOGGER_DEFAULT(lg, sources::wlogger_mt) int main() { typedef sinks::synchronous_sink<sinks::text_ostream_backend> text_sink; boost::shared_ptr<text_sink> sink = boost::make_shared<text_sink>(); boost::shared_ptr<std::ostream> stream{&std::clog, boost::empty_deleter{}}; sink->locked_backend()->add_stream(stream); core::get()->add_sink(sink); BOOST_LOG(lg::get()) << L"note"; }
本章中的所有示例都使用本地记录器。如果要定义全局记录器,请使用宏 BOOST_LOG_INLINE_GLOBAL_LOGGER_DEFAULT,如示例 62.10 所示。您将记录器的名称作为第一个参数传递,将类型作为第二个参数传递。您不通过其名称访问记录器。相反,您调用 get(),它返回一个指向单例的指针。
Boost.Log 提供了额外的宏,例如 BOOST_LOG_INLINE_GLOBAL_LOGGER_CTOR_ARGS。它们让您初始化全局记录器。 BOOST_LOG_INLINE_GLOBAL_LOGGER_CTOR_ARGS 允许您将参数传递给全局记录器的构造函数。所有这些宏都保证全局记录器将被正确初始化。
Boost.Log 提供了更多值得一看的功能。例如,您可以通过将键/值对作为字符串的容器来配置日志记录框架。然后,您不需要实例化类和调用成员函数。例如,可以将一个关键的 Destination 设置为 Console,这将自动使日志记录框架使用后端 boost::log::sinks::text_ostream_backend。后端可以通过额外的键/值对进行配置。因为容器也可以在 INI 文件中序列化,所以可以将配置存储在文本文件中并使用该文件初始化日志记录框架。
加载全部内容