boost :: log保存容器中的消息,然后将所有消息发送到后端

时间:2015-08-14 12:49:20

标签: c++ boost boost-log

我想在内存中保存实际格式化的消息,例如memory_sink,然后在flush上发送消息。但是有一个问题,即保存的record_view的属性被更改为最后创建的record_view的属性,我不知道为什么会出现这种行为。但也许有人可以说我,我可以实现我想要的东西吗?

非常简单的例子:

#define BOOST_LOG_DLL 1
#include <boost/log/core.hpp>
#include <boost/log/utility/setup/common_attributes.hpp>
#include <boost/log/sinks/sync_frontend.hpp>
#include <boost/log/sinks/basic_sink_backend.hpp>
#include <boost/log/expressions/keyword.hpp>
#include <boost/log/trivial.hpp>
#undef BOOST_LOG_DLL

#include <boost/shared_ptr.hpp>
#include <queue>

namespace logging = boost::log;
namespace sinks = boost::log::sinks;

typedef sinks::combine_requirements<sinks::synchronized_feeding, sinks::flushing>::type sync_flushing;

struct message_t
{
   message_t(const logging::record_view& r, const std::string& f) :
      record(r), fstring(f)
   {
   }
   logging::record_view record;
   std::string fstring;
};

template<typename Sink>
class memory_sink : public sinks::basic_formatted_sink_backend<char, sync_flushing>
{
public:
   memory_sink(const boost::shared_ptr<Sink>& sink) : sink_(sink)
   {
   }

   void consume(const logging::record_view& rec, const string_type& fstring)
   {
      const message_t msg(rec, fstring);
      messages_.push(msg);
   }

   void flush()
   {
      while (!messages_.empty())
      {
         const message_t& msg = messages_.front();
         sink_->consume(msg.record, msg.fstring);
         messages_.pop();
      }
   }
private:
   typedef std::queue<message_t> buffer_t;
   buffer_t messages_;
   const boost::shared_ptr<Sink> sink_;
};

std::ostream& operator << (std::ostream& stream, logging::trivial::severity_level lvl)
{
   return stream << boost::log::trivial::to_string(lvl);
}

class cout_sink : public sinks::basic_formatted_sink_backend< char, sinks::synchronized_feeding >
{
public:
   std::string format(const logging::record_view& rec, const std::string& fstring) const
   {
      return fstring;
   }
   void consume(const logging::record_view& rec, const std::string& fstring)
   {
      std::cout << "[" << rec[boost::log::trivial::severity] << "] " << fstring << std::endl;
   }
};

void init_cout()
{
   typedef sinks::synchronous_sink<memory_sink<cout_sink> > sink_t;

   boost::shared_ptr< logging::core > core = logging::core::get();
   core->remove_all_sinks();

   boost::shared_ptr< cout_sink > tsink = boost::make_shared<cout_sink>();
   boost::shared_ptr<memory_sink<cout_sink> > backend = boost::make_shared<memory_sink<cout_sink> >(tsink);
   boost::shared_ptr< sink_t > sink = boost::make_shared<sink_t>(tsink);

   core->add_sink(sink);
}

void flush_logs()
{
   logging::core::get()->flush();
}

int main()
{
   logging::add_common_attributes();
   init_cout();
   BOOST_LOG_TRIVIAL(warning) << "warning message";
   BOOST_LOG_TRIVIAL(error) << "error message";
   flush_logs();
}

Live version

正如您所看到的,两个记录的严重性都是error,但我希望warningerror。可能有更好的方法来做到这一点?

我知道格式化程序,此处严重程度打印在backend中,仅作为示例,因为实际代码较大且接收消耗接收record_view,而不是仅将其发送到后端,该接收仅仅接收record_view

1 个答案:

答案 0 :(得分:1)

您观察到的行为是由库使用的优化技术引起的。在创建日志记录时,Boost.Log有时可以通过引用包含原始值的特定于线程的数据来避免将属性值复制到记录中。特定于线程的数据应该在处理记录时保持不变。显然需要在线程之间传递记录的异步接收器有一种方法可以将其传递给日志记录核心,因此禁用此优化并且在传递给接收器之前将日志记录与原始线程分离。详细说明here,请参阅有关detach_from_thread的说明。

问题是只有接收器前端决定是否必须禁用此优化,并且只有asynchronous_sink才能执行此操作。没有办法为其他前端定制。因此,您必须使用asynchronous_sink后端或者必须编写前端。

要实现接收器前端,您需要一个派生自sink基类的类,并执行过滤,格式化(如果需要)并将记录传递给后端。您可以使用synchronous_sink实现作为示例。与synchronous_sink的重要区别在于您必须将true传递给sink构造函数。这将告诉日志核心您的接收器需要分离的日志记录。