読者です 読者をやめる 読者になる 読者になる

kkAyatakaのメモ帳。

誰かの役に立つかもしれない備忘録。

Boost.Logのtext_ostream_backend

BOOST_LOG_TRIVIALは何の設定も無くログをコンソールに出力できますが、新しいbackend(のためのsink)を設定すると出力されなくなります。これでは少し都合が悪いので、自前でコンソール用のbackend(sink)を用意します。

ストリームへの出力なので、次を使います。

  • text_ostream_backend

std::ostreamの派生なら使えるため、std::coutでも、自前で用意したstreamでも何でも使えます。std::fstreamも使えるので、簡易にファイルへ落とし込むこともできますが、ファイルへの出力はログファイルローテンションを行ってくれるtext_file_backendを使うほうがよいでしょう。

text_ostream_backend

backendの使い方は型が違う程度で、基本的には同じなので、backend -> sink -> loggerへ追加の順に準備します。logging::add_common_attributes()も忘れずに。

shared_ptr<sinks::text_ostream_backend> backend =
  make_shared<sinks::text_ostream_backend>();

backend->add_stream(shared_ptr<std::ostream>(
  &std::clog, logging::empty_deleter()));
backend->auto_flush(true);

typedef sinks::synchronous_sink<sinks::text_ostream_backend> sink_t;
shared_ptr<sink_t> sink(new sink_t(backend));

sink->set_formatter(
  expr::format("%1% [%2%] %3%")
  % expr::format_date_time<posix_time::ptime>(
   "TimeStamp", "%Y-%m-%d %H:%M:%S")
  % logging::trivial::severity
  % expr::message
  );

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

logging::add_common_attributes();

std::clog、std::cout、std::cerrは使い分けたことが無いのでいまいちシステムへの影響がわからなかったりしますが...

debug_output_backendと組み合わせる

sinkは複数登録できるので、以前作成したdebug_output_backendと組み合わせます。debug_output_backendの使用後、コンソールに表示されなくなりましたが、これでコンソールとVisual Studioに表示されるようになります。

まあ、それだけだとあまり意味は無いのですが、Windows以外ではtext_ostream_backendが使用されるので、クロスプラットフォームで使用できると思ったほうがよいですかね。ただ、このままのコードだとMac、Linuxではdebug_output_backendの部分でコンパイル通りませんが。

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

#include <boost/log/expressions.hpp>
#include <boost/log/sinks.hpp>
#include <boost/log/sinks/debug_output_backend.hpp>
#include <boost/log/support/date_time.hpp>
#include <boost/log/utility/empty_deleter.hpp>
#include <boost/log/utility/setup/common_attributes.hpp>
#include <boost/log/trivial.hpp>

int main() {
  using namespace boost;
  namespace logging = boost::log;
  namespace expr = boost::log::expressions;
  namespace sinks = boost::log::sinks;

  { // for Visual Studio
    shared_ptr<sinks::debug_output_backend> backend =
      make_shared<sinks::debug_output_backend>();
    
    typedef sinks::synchronous_sink<sinks::debug_output_backend> sink_t;
    shared_ptr<sink_t> sink(new sink_t(backend));

    sink->set_formatter(
    expr::format("%1%\t%2%\t%3%\n")
    % expr::format_date_time<posix_time::ptime>(
      "TimeStamp", "%H:%M:%S")
    % logging::trivial::severity
    % expr::message
    );

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

  { // for std::clog
    shared_ptr<sinks::text_ostream_backend> backend =
      make_shared<sinks::text_ostream_backend>();
    backend->add_stream(shared_ptr<std::ostream>(
      &std::clog, logging::empty_deleter()));
    backend->auto_flush(true);

    typedef sinks::synchronous_sink<sinks::text_ostream_backend> sink_t;
    shared_ptr<sink_t> sink(new sink_t(backend));

    sink->set_formatter(
      expr::format("%1% [%2%] %3%")
      % expr::format_date_time<posix_time::ptime>(
        "TimeStamp", "%Y-%m-%d %H:%M:%S")
      % logging::trivial::severity
      % expr::message
      );

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

  logging::add_common_attributes();

#ifdef _DEBUG
  // do nothing
#else
  logging::core::get()->set_filter(
    logging::trivial::severity >= logging::trivial::info
    );
#endif

  BOOST_LOG_TRIVIAL(trace) << "trace message";
  BOOST_LOG_TRIVIAL(debug) << "debug";
  BOOST_LOG_TRIVIAL(info) << "info message";
  BOOST_LOG_TRIVIAL(warning) << "warning message";
  BOOST_LOG_TRIVIAL(error) << "error message";
  BOOST_LOG_TRIVIAL(fatal) << "fatal message";
}