Как организовать потокобезопасное чтение из лог-приемника boost?

Я ищу правильный способ безопасного получения текстовых данных из boost::log::sinks::text_ostream_backend. В настоящее время я получаю данные только после того, как все было записано в бэкэнд приемника. Я хочу получить копию внутреннего буфера бэкэнда (m_ss), пока данные еще могут быть созданы.

using Logger = boost::log::sources::severity_channel_logger_mt<boost::log::trivial::severity_level, std::string>;

class MyClass
{
  mutable std::mutex  m_mutex;
  mutable Logger      m_logger {boost::log::keywords::channel = "MyClass"};
  std::stringstream   m_ss;
  bool                m_completed {false};

public:
  void initLogging(const std::string& id)
  {
    using namespace boost::log;
    using Sink = sinks::synchronous_sink<sinks::text_ostream_backend>;

    auto backend = boost::make_shared<sinks::text_ostream_backend>();
    backend->add_stream(boost::shared_ptr<std::stringstream>(&m_ss, boost::null_deleter()));
    auto sink = boost::make_shared<Sink>(backend);
    sink->set_filter(expressions::has_attr<std::string>("ID") && expressions::attr<std::string>("ID") == id);

    core::get()->add_sink(sink);

    m_logger.add_attribute("ID", attributes::constant<std::string>(id));
  }

  void doSomething()
  {
    BOOST_LOG_SEV(logger, boost::log::trivial::severity_level::debug) << "TEST";
    BOOST_LOG_SEV(logger, boost::log::trivial::severity_level::error) << "TEST";

    // Stop write logs
    std::lock_guard<std::mutex> lock(m_mutex);
    m_completed = true;
  }

  void access()
  {
    std::lock_guard<std::mutex> lock(m_mutex);

    if (m_completed) {
      // Can read from stream
      useStreamData(m_ss.str());
    }
  }
};

person sba    schedule 14.08.2018    source источник


Ответы (1)


Если к потоку обращается только серверная часть приемника, то самый простой способ синхронизировать доступ — использовать locked_backend.

auto locked_backend = sink->locked_backend();

Здесь объект locked_backend является интеллектуальным указателем, который блокирует интерфейс приемника и, следовательно, предотвращает доступ потоков журналирования к серверу и, следовательно, к потоку m_ss. Вы можете безопасно использовать m_ss, пока существует locked_backend.

Есть и другие способы добиться этого. Например, вы можете реализовать настраиваемый бэкенд-приемник или реализовать буфер потока, который позволит синхронизировать доступ к накопленным данным. Существует ряд статей и сообщений в блогах о написании пользовательских буферов потока, здесь один пример.

person Andrey Semashev    schedule 14.08.2018