5
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Boost.Logの使い方(3. ログの出力)

Last updated at Posted at 2015-03-14
  1. 概略
  2. ログの収集
  3. ログの出力
  4. cmakeによるコンパイル

今回はログの出力についてです。

状況設定

前回と同様以下の状況を考えます。

CMakeLists.txt
mod1/CMakeLists.txt
     func.hpp
     func1.cpp
     func2.cpp
     logger.cpp
client.cpp

あるモジュールmod1client.cppから使う場合を考えます。
また全てcmakeを使用してコンパイルします。

尚文章中に出現する略したnamespaceは以下の通りです:

namespace logging = boost::log;
namespace keywords = logging::keywords;
namespace sinks = logging::sinks;
namespace src = logging::sources;
namespace attrs = logging::attributes;
namespace expr = logging::expressions;

またサンプルコードはtermoshtt/boost_log_sampleにあります。

出力やフィルターの設定

上述の方法で収集したログを出力しましょう。

client.cpp
void init() {
  mod1::init();
  logging::add_common_attributes();
  logging::add_file_log(
      keywords::file_name = "client.log", // logを出力するファイル名
      keywords::format =
          "%Tag%: [%TimeStamp%] [%Scope%] %Message%" // logのフォーマット
      );
}

int main(int argc, char const *argv[]) {
  init();
  mod1::func1(true);
  mod1::func1(false);
  return 0;
}

add_common_attributes()はコアに標準の属性
(TimeStamp, LineID, ThreadID, ProcessID)を記録する様に命令します。
上でloggerに対して"Tag"や"Scope"を記録するように命令したのと同じイメージですが、
こちらは全てのログに対して有効になります。

add_file_log()でファイルへ出力するsinkを作成します。
上の図のように収集されたすべてのログがこのsinkに流れこみます。
ファイルへの出力の形式はkeywords::formatで調整されます。
%...%が展開される事で、出力は

client.log
mod1: [2015-Mar-04 01:38:57.711251] [void mod1::func1(bool)->true case] flag is true
mod1: [2015-Mar-04 01:38:57.711620] [void mod1::func1(bool)] Some error occurs!!
mod1: [2015-Mar-04 01:38:57.711667] [void mod1::func1(bool)->false case] flag is false
mod1: [2015-Mar-04 01:38:57.711698] [void mod1::func1(bool)] Some error occurs!!

のようになります。

placeholderの設定

上ではフォーマットを%...%のテンプレートで生成しましたが、
C++的なstreamを使用する事もできます。
文字列テンプレートの場合の"Tag", "Scope"等の名前は定義時に指定されました

lg.add_attribute("Tag", attrs::constant<std::string>("mod1"));
lg.add_attribute("Scope", attrs::named_scope());

streamを使用する場合にはまず、モジュール側でplaceholderを設定しておく必要があります。

mod1/func.hpp
namespace mod1 {
BOOST_LOG_ATTRIBUTE_KEYWORD(line_id, "LineID", unsigned int)
BOOST_LOG_ATTRIBUTE_KEYWORD(severity, "Severity", severity_level)
BOOST_LOG_ATTRIBUTE_KEYWORD(tag_attr, "Tag", std::string)
BOOST_LOG_ATTRIBUTE_KEYWORD(scope, "Scope", attrs::named_scope::value_type)
} // namespace mod1

tag_attr, scope等がplaceholderになります。
ユーザー側では以下のように使います:

client.cpp
void init() {
  mod1::init();
  logging::add_common_attributes();
  logging::add_file_log(
      keywords::file_name = "client.log",
      keywords::format = "%Tag%: [%TimeStamp%] [%Scope%] %Message%"
      );
  logging::add_file_log(
    keywords::file_name = "stream_format.log",
    keywords::format = (expr::stream << mod1::tag_attr << mod1::line_id
                                     << ": <" << mod1::severity << "> ["
                                     << mod1::scope << "] "
                                     << expr::smessage));
}

この場合のkeywords::formatにはplaceholderにより生成されたラムダ式が入りますが、
見た目的に挙動は理解して頂けるでしょう。
この場合の<<operator<<(std::ostream&, T)が呼ばれますので、

mod1/func.hpp
namespace mod1 {
enum severity_level { debug, info, warning, error, critical };
std::ostream &operator<<(std::ostream &ost, severity_level l);
} // namespace mod1

のようにあらかじめ出力を調整しておく事が可能です。

Boost.Logは多数の出力の設定方法を提供しています。

まとめ

これまででログの収集と出力の方法をまとめました。
これでtrivialなログに比べ格段に自由度が高くなりました。
次回はcmakeによるコンパイルの方法についてまとめます。

5
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?