使用 Boost.Log 时如何停止所有异步接收器
How to stop all asynchronous sinks when using Boost.Log
我正在使用 Boost.Log 异步接收器(参见 Asynchronous sink frontend)。要正确关闭,必须优雅地停止并将记录馈送刷新到异步接收器。核心有添加和删除接收器的方法,但似乎没有办法让客户端获取或访问接收器。文档有一个 stop_logging
方法,
void stop_logging(boost::shared_ptr< sink_t >& sink)
{
boost::shared_ptr< logging::core > core = logging::core::get();
// Remove the sink from the core, so that no records are passed to it
core->remove_sink(sink);
// Break the feeding loop
sink->stop();
// Flush all log records that may have left buffered
sink->flush();
sink.reset();
}
但它需要特定的 sink_t
类型。 asynchronous_sink 前端 class 具有用于接收器后端和排队策略的模板参数。
template<typename SinkBackendT,
typename QueueingStrategyT = unbounded_fifo_queue>
class asynchronous_sink;
我会有几种不同类型的接收器,所以我想要一个通用容器来容纳它们,这样我就可以简单地迭代它并为容器中的每个接收器调用 stop_logging
。
由于 Boost.Log 中提供的接口,这确实是我需要解决的关于 C++ 模板化数据结构的一般性问题。什么是用于跟踪我添加到 Boost.Log 核心的异步接收器的良好数据结构?我需要一个,这样我就可以在关机时调用 stop_logging
。
我第一个头脑简单的方法是使用 boost::any
个对象的向量。但这是相当麻烦和不优雅的。我怀疑一个合理的方法是拥有一个函数对象向量,这些函数对象是调用 stop_logging
的 lambda 方法。但是我迷失在模板类型中,不知道该怎么做。
感谢您的帮助。
谢谢!
最直接的解决方案是像您建议的那样拥有一个包含函数对象的容器。例如:
std::vector< std::function< void() > > stop_functions;
// For every asynchronous sink you add
stop_functions.emplace_back([sink]()
{
sink->flush();
sink->stop();
});
在此示例中,sink
可以是指向您碰巧添加到日志记录核心的 asynchronous_sink
的任何实例的指针。当您的应用程序终止时,您只需调用容器中所有保存的函数:
for (auto& stop : stop_functions)
stop();
但是,有一个 Boost.Signals2 库 allows 可以稍微简化这个过程。您可以创建一个信号,然后像这样将函数连接到它:
boost::signals2::signal< void() > stop_signal;
// For every asynchronous sink you do
stop_signal.connect([sink]()
{
sink->flush();
sink->stop();
});
然后通过调用信号,您将调用每个连接的函数对象,有效地停止每个接收器。
stop_signal();
在任何一种情况下,您都可以使用 std::bind
或任何其他方式来创建您喜欢的函数对象。关键部分是将指向接收器前端的指针及其类型保存到函数对象中。
我正在使用 Boost.Log 异步接收器(参见 Asynchronous sink frontend)。要正确关闭,必须优雅地停止并将记录馈送刷新到异步接收器。核心有添加和删除接收器的方法,但似乎没有办法让客户端获取或访问接收器。文档有一个 stop_logging
方法,
void stop_logging(boost::shared_ptr< sink_t >& sink)
{
boost::shared_ptr< logging::core > core = logging::core::get();
// Remove the sink from the core, so that no records are passed to it
core->remove_sink(sink);
// Break the feeding loop
sink->stop();
// Flush all log records that may have left buffered
sink->flush();
sink.reset();
}
但它需要特定的 sink_t
类型。 asynchronous_sink 前端 class 具有用于接收器后端和排队策略的模板参数。
template<typename SinkBackendT,
typename QueueingStrategyT = unbounded_fifo_queue>
class asynchronous_sink;
我会有几种不同类型的接收器,所以我想要一个通用容器来容纳它们,这样我就可以简单地迭代它并为容器中的每个接收器调用 stop_logging
。
由于 Boost.Log 中提供的接口,这确实是我需要解决的关于 C++ 模板化数据结构的一般性问题。什么是用于跟踪我添加到 Boost.Log 核心的异步接收器的良好数据结构?我需要一个,这样我就可以在关机时调用 stop_logging
。
我第一个头脑简单的方法是使用 boost::any
个对象的向量。但这是相当麻烦和不优雅的。我怀疑一个合理的方法是拥有一个函数对象向量,这些函数对象是调用 stop_logging
的 lambda 方法。但是我迷失在模板类型中,不知道该怎么做。
感谢您的帮助。 谢谢!
最直接的解决方案是像您建议的那样拥有一个包含函数对象的容器。例如:
std::vector< std::function< void() > > stop_functions;
// For every asynchronous sink you add
stop_functions.emplace_back([sink]()
{
sink->flush();
sink->stop();
});
在此示例中,sink
可以是指向您碰巧添加到日志记录核心的 asynchronous_sink
的任何实例的指针。当您的应用程序终止时,您只需调用容器中所有保存的函数:
for (auto& stop : stop_functions)
stop();
但是,有一个 Boost.Signals2 库 allows 可以稍微简化这个过程。您可以创建一个信号,然后像这样将函数连接到它:
boost::signals2::signal< void() > stop_signal;
// For every asynchronous sink you do
stop_signal.connect([sink]()
{
sink->flush();
sink->stop();
});
然后通过调用信号,您将调用每个连接的函数对象,有效地停止每个接收器。
stop_signal();
在任何一种情况下,您都可以使用 std::bind
或任何其他方式来创建您喜欢的函数对象。关键部分是将指向接收器前端的指针及其类型保存到函数对象中。