设置接收器
BOOST_LOG_TRIVIAL不能提供足够的灵活性。例如,有时可能需要更复杂的逻辑来处理日志,而不是简单地将其打印在控制台上。为了定制这一点,你必须构造记录接收器,并在boost.log库core里面注册。这通常只需要你在应用程序启动的地方注册一次就够了。
【注意】在前面的章节中我们没有初始化任何的接收器,因为boost.log库在没有初始化任何接收器的情况下会使用一个默认的接收器,这就是为什么我们能够在控制台中看到日志的输出结果。如果你设置了自定义的接收器,那么默认的接收器将会失效,虽然你仍然可以使用BOOST_LOG_TRIVIAL来记录日志。
文件记录
下面将演示如何将记录写入到文件中:
#include <iostream>
#include <boost/log/core.hpp>
#include <boost/log/trivial.hpp>
#include <boost/log/expressions.hpp>
#include <boost/log/utility/setup/file.hpp>
void init()
{
boost::log::add_file_log("sample.log");
boost::log::core::get()->set_filter(boost::log::trivial::severity >= boost::log::trivial::info);
}
添加的代码片断是对 add_file_log 函数的调用。顾名思义,该函数初始化一个将日志记录存储到文本文件的接收器。该函数还接受了大量的自定义选项,例如文件大小限制。举个例子:
#include <iostream>
#include <boost/log/core.hpp>
#include <boost/log/trivial.hpp>
#include <boost/log/expressions.hpp>
#include <boost/log/utility/setup/file.hpp>
void init()
{
boost::log::add_file_log(
boost::log::keywords::file_name = "sample_%N.log",
boost::log::keywords::rotation_size = 10 * 1024 * 1024,
boost::log::keywords::time_based_rotation = boost::log::sinks::file::rotation_at_time_point(0, 0, 0),
boost::log::keywords::format = "[%TimeStamp%]: %Message%"
);
boost::log::core::get()->set_filter(boost::log::trivial::severity >= boost::log::trivial::info);
}
下面介绍一下add_file_log函数的参数列表:
- 参数1:文件名模板
- 参数2:超过此文件大小自动建立新文件
- 参数3:超过此时间自动建立新文件
- 参数4:日志记录格式
【注意】你可以注册多个接收器,每个接收器将接收并处理日志记录。
深入接收器
在最简单的形式中,对以上代码中的 add_file_log 函数的调用是几乎等同于此:
#include <fstream>
#include <boost/log/core.hpp>
#include <boost/smart_ptr.hpp>
#include <boost/log/trivial.hpp>
#include <boost/log/sinks/sync_frontend.hpp>
#include <boost/log/sources/record_ostream.hpp>
#include <boost/log/sinks/text_ostream_backend.hpp>
void init()
{
// 构造接收器
typedef boost::log::sinks::synchronous_sink<boost::log::sinks::text_ostream_backend > text_sink;
boost::shared_ptr<text_sink> sink = boost::make_shared<text_sink>();
// 添加一个流写入日志
sink->locked_backend()->add_stream(boost::make_shared< std::ofstream >("sample.log"));
// 注册接收器
boost::log::core::get()->add_sink(sink);
}
你可能已经注意到了接收器是由两个类组成:frontend 和 backend 。 frontend (上述片段中的boost::log::sinks::synchronous_sink模板类) 负责所有接收器常见的各种任务,如线程同步模型、 过滤和基于文本的接收器,格式。 backend (上述片段中的boost::log::sinks::text_ostream_backend) 实现接收器所有具体的功能,如在这种情况下写入一个文件。log库提供大量的 frontend 和 backend ,它们是现成的,可以彼此一起组合使用。
boost::log::sinks::synchronous_sink 表示接收器是同步的,它允许多个线程在争用的情况下写入日志。这意味着后端 boost::log::sinks::text_ostream_backend不必担心多线程问题。
boost::log::sinks::text_ostream_backend 类写入格式化日志记录到 STL 兼容的流。上面我们使用了一个文件流,但是我们也可以使用一个任何类型的流。例如,添加到控制台输出:
#include <boost/log/core.hpp>
#include <boost/smart_ptr.hpp>
#include <boost/log/trivial.hpp>
#include <boost/core/null_deleter.hpp>
#include <boost/log/sinks/sync_frontend.hpp>
#include <boost/log/sinks/text_ostream_backend.hpp>
void init()
{
// 构造接收器
typedef boost::log::sinks::synchronous_sink<boost::log::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::null_deleter());
sink->locked_backend()->add_stream(stream);
// 注册接收器
boost::log::core::get()->add_sink(sink);
}
boost::log::sinks::text_ostream_backend支持添加多个流,这这种情况下,其输出将被赋值到所有加入的流之中。所有它可以同时在控制台或者是文件中输出结果。如果开启了过滤,那么boost.log库只会在记录没有被过滤掉的日志时才会产生开销。
【注意】注册几个不同接收器与多个目标流注册到一个接收器的区别。前者允许独立定制每个接收器的输出,后者如果不需要这样的定制将工作相当快,此特性是特定于这个特定的 backend 。
boost.log库通过提供一系列的 backend ,来提供不同的日志处理的逻辑。例如,通过指定系统日志的backend 可以网络日志记录把发送到日志服务器,或通过设置Windows NT事件日志的backend 可以使用Windows应用程序的运行时监控工具,使应用程序运行时发出的日志记录。
最后要说的是调用成员函数 locked_backend() 来访问接收器backend 。它被所有接收器的frontend 提供,用于获取到backend 的线程安全访问。此函数返回一个backend 的智能指针,并且它存在一个backend 锁 (这意味着如果另一个线程此时将日志记录传递到接收器,它将被阻塞直到释放backend 后)。唯一的例外是 unlocked_sink类型的frontend 根本不同步,只是返回一个解锁的backend指针。
关于接收器的更多信息:
Sink frontends:http://www.boost.org/doc/libs/1_58_0/libs/log/doc/html/log/detailed/sink_frontends.html
Sink backends:http://www.boost.org/doc/libs/1_58_0/libs/log/doc/html/log/detailed/sink_backends.html