C++ Boost log日志库超详细讲解

目录
  • 一、说明
  • 二、库Boost.Log

一、说明

应用程序库是指通常专门用于独立应用程序开发而不用于库开发的库。

  • Boost.Log 是一个日志库。
  • Boost.ProgramOptions 是一个用于定义和解析命令行选项的库。
  • Boost.Serialization 允许您序列化对象,例如,将它们保存到文件或从文件加载它们。
  • Boost.Uuid 支持使用 UUID。

具体内容

二、库Boost.Log

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();
}

Example 62.1

示例 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();
}

Example 62.2

示例 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::r​​ecord 是另一种日志条目类型,类似于 boost::log::attribute_value_set 的包装器。此类型提供成员函数 attribute_values(),它检索对 boost::log::attribute_value_set 的引用。过滤器函数直接接收 boost::log::attribute_value_set 而没有 boost::log::r​​ecord。 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::r​​untime_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();
}

Example 62.3

日志条目由属性组成。属性有名称和值。您可以自己创建属性。它们也可以自动创建——例如由记录器创建。事实上,这就是 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::r​​untime_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();
}

Example 62.4

示例 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();
}

Example 62.8

示例 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 文件中序列化,所以可以将配置存储在文本文件中并使用该文件初始化日志记录框架。

到此这篇关于C++ Boost log日志库超详细讲解的文章就介绍到这了,更多相关C++ Boost log内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • C++ Boost MetaStateMachine定义状态机超详细讲解

    目录 一.说明 二.示例和代码 一.说明 Boost.MetaStateMachine 用于定义状态机.状态机通过对象的状态来描述对象.它们描述了存在哪些状态以及状态之间可能存在哪些转换. Boost.MetaStateMachine 提供了三种不同的方式来定义状态机.创建状态机所需编写的代码取决于前端. 如果使用基本前端或函数前端,则可以用常规方式定义状态机:创建类,从 Boost.MetaStateMachine 提供的其他类派生它们,定义所需的成员变量,并编写所需的 C++自己编码.基本前

  • C++ Boost Uuid超详细讲解

    目录 一.说明 二.Boost.Uuid库示例和代码 一.说明 Boost.Uuid 为 UUID 提供生成器. UUID 是不依赖于中央协调实例的通用唯一标识符.例如,没有数据库存储所有生成的 UUID,可以检查这些 UUID 是否使用了新的 UUID. UUID 由必须唯一标识组件的分布式系统使用.例如,Microsoft 使用 UUID 来识别 COM 世界中的接口.对于为 COM 开发的新接口,可以轻松分配唯一标识符. UUID 是 128 位数字.存在多种生成 UUID 的方法.例如,

  • C++ Boost ProgramOptions超详细讲解

    目录 一.说明 二.示例Boost.ProgramOptions 一.说明 Boost.ProgramOptions Boost.ProgramOptions 是一个可以轻松解析命令行选项的库,例如,控制台应用程序.如果您使用图形用户界面开发应用程序,命令行选项通常并不重要. 要使用 Boost.ProgramOptions 解析命令行选项,需要以下三个步骤: 定义命令行选项.您给它们命名并指定哪些可以设置为一个值.如果命令行选项被解析为键/值对,您还可以设置值的类型——例如,它是字符串还是数字

  • C++ Boost Utility超详细讲解

    目录 一.说明 二.Boost.Utility库示例和代码 一.说明 Boost.Utility 库是杂项.有用的类和函数的集合,它们太小而无法在独立库中维护.虽然实用程序很小并且可以快速学习,但它们完全无关.与其他章节中的示例不同,此处的代码示例不是相互构建的,因为它们是独立的实用程序. 虽然大多数实用程序都在 boost/utility.hpp 中定义,但有些实用程序有自己的头文件.以下示例包括所介绍的实用程序的相应头文件. 二.Boost.Utility库示例和代码 示例 69.1.使用

  • C++ Boost Archive超详细讲解

    目录 一.说明 二.关于Archive库 一.说明 对Boost.Serialization库的应用,存在如下内容: Archive Pointers and References Serialization of Class Hierarchy Objects Wrapper Functions for Optimization Boost.Serialization 库可以将 C++ 程序中的对象转换为可以保存和加载以恢复对象的字节序列.有不同的数据格式可用于定义生成字节序列的规则. Boo

  • C++ Boost Flyweight库使用介绍

    目录 一.说明 二.库Boost.Flyweight 炼习 一.说明 以下库用于设计模式. Boost.Flyweight 有助于在程序中使用许多相同的对象并且需要减少内存消耗的情况. Boost.Signals2 使得使用观察者设计模式变得容易.这个库被称为 Boost.Signals2 因为它实现了信号/槽的概念. Boost.MetaStateMachine 使得将状态机从 UML 转移到 C++ 成为可能. 本节内容 66. Boost.Flyweight 67. Boost.Signa

  • C++ Boost.Signals2信号/槽概念

    目录 一.关于Boost.Signals2 二.关于Signals库 练习 一.关于Boost.Signals2 Boost.Signals2 实现了信号/槽的概念.一个或多个函数(称为槽)与可以发出信号的对象相关联.每次发出信号时,都会调用链接的函数. 信号/槽概念在开发具有图形用户界面的应用程序时非常有用.可以对按钮进行建模,以便在用户单击它们时发出信号.它们可以支持指向许多函数的链接以处理用户输入.这样就可以灵活地处理事件. std::function 也可用于事件处理. std::fun

  • C++ Boost log日志库超详细讲解

    目录 一.说明 二.库Boost.Log 一.说明 应用程序库是指通常专门用于独立应用程序开发而不用于库开发的库. Boost.Log 是一个日志库. Boost.ProgramOptions 是一个用于定义和解析命令行选项的库. Boost.Serialization 允许您序列化对象,例如,将它们保存到文件或从文件加载它们. Boost.Uuid 支持使用 UUID. 具体内容 62. Boost.Log 63. Boost.ProgramOptions 64. Boost.Serializ

  • C++ Boost weak_ptr智能指针超详细讲解

    目录 一.提要 二.特别智能指针(Special Smart Pointers) 一.提要 在 C++11 中,boost::weak_ptr是另一类智能指针,一般是用COM组件生成.调用,本文阐述这种指针的特点和用法. 二.特别智能指针(Special Smart Pointers) 到目前为止介绍的每个智能指针都可以在不同的场景中单独使用.但是,boost::weak_ptr 仅在与 boost::shared_ptr 结合使用时才有意义. boost::weak_ptr 在 boost/w

  • C++ Boost PropertyTree示例超详细讲解

    目录 一.提要 二.应用示例 练习 一.提要 借助类 boost::property_tree::ptree,Boost.PropertyTree 提供了一个树结构来存储键/值对.树形结构意味着一个树干存在许多分支,其中有许多树枝.文件系统是树结构的一个很好的例子.文件系统有一个带有子目录的根目录,这些子目录本身可以有子目录等等. 二.应用示例 要使用 boost::property_tree::ptree,请包含头文件 boost/property_tree/ptree.hpp.这是一个主头文

  • C++ Boost Optional示例超详细讲解

    目录 一.概述 二.Boost.Optional 一.概述 数据结构类似于容器,因为它们可以存储一个或多个元素.但是,它们与容器不同,因为它们不支持容器通常支持的操作.例如,使用本部分介绍的数据结构,不可能在一次迭代中访问所有元素. Boost.Optional 可以很容易地标记可选的返回值.使用 Boost.Optional 创建的对象要么是空的,要么包含单个元素.使用 Boost.Optional,您无需使用空指针或 -1 等特殊值来指示函数可能没有返回值. Boost.Tuple 提供了

  • C++ Boost Lockfree超详细讲解使用方法

    目录 一.说明 二.示例和代码 Boost.Lockfree 一.说明 Boost.Lockfree 提供线程安全和无锁容器.可以从多个线程访问此库中的容器,而无需同步访问. 在 1.56.0 版本中,Boost.Lockfree 只提供了两个容器:boost::lockfree::queue 类型的队列和 boost::lockfree::stack 类型的栈.对于队列,可以使用第二个实现:boost::lockfree::spsc_queue.此类针对只有一个线程写入队列和只有一个线程从队列

  • C++ Boost ScopeExit超详细讲解

    目录 一.提要 二.退出作用域(Boost.ScopeExit) 2.1 范例1.UsingBOOST_SCOPE_EXIT 2.2 示例2.Boost.ScopeExit和C++11的lambda函数 2.3 示例3.特点BOOST_SCOPE_EXIT 三.练习 一.提要 资源有很多种,每种都封装一套,还是挺繁琐的!对于比较少使用或者一个程序很可能只会用一次的资源,我们不想封装,在这种情况下用Boost.ScopeExit. 二.退出作用域(Boost.ScopeExit) 库 Boost.

  • C++ Boost System超详细讲解

    目录 一.说明 二.关于 Boost.System库 一.说明 以下库支持错误处理. Boost.System 提供类来描述和识别错误.自 C++11 以来,这些类已成为标准库的一部分. Boost.Exception 使得在抛出异常后附加数据成为可能. 二.关于 Boost.System库 Boost.System Boost.System 是一个库,本质上定义了四个类来识别错误.所有四个类都已添加到 C++11 的标准库中.如果您的开发环境支持 C++11,则无需使用 Boost.Syste

随机推荐