C++のちょっとしたアプリでさっと使いやすい簡易ロガーの実装例


概要

「あるある」と言われたトアルあるある話:

小さなサンプルアプリ作る
↓
でもまあロガーくらい入れて作りたい
↓
boost::log入れるのめんどくさいしちょっとしたやつ
↓
気づけばいつものロガーコードを書いている

こんな時に書いている簡易ロガーの実装例を紹介したい。

実装例

ちょっと実用上器用にするための呪文も入れても150行くらいなもの。本質的には100行くらい。

要点は後述として、とりあえず使い方↓。

使い方

//↓これを定義すると easy_logger は LOGI などで何も出力しなくなります。
//#define DISABLE_USAGI_LOG_EASY_LOGGER
#include <usagi/log/easy_logger.hxx>

#include <thread>
#include <random>

auto main() -> int
{
  // 単純な使い方
  LOGI << "test1";

  // 複数の operator<< で繋いでも綺麗に出力されます。
  LOGD << "test2 multiple output operators in the one line " << 12345 << ' ' << 1.2345f;

  // マルチスレッドで競争的にログ出力しても分断されずに綺麗に出力されます。
  std::random_device r;
  auto a = std::thread( [&]{ for ( auto n = 0; n < 16; ++n ) LOGW << "/(^o^)\ " << r() << ' ' << r()<< ' ' << r() << ' ' << ' ' << r(); } );
  std::thread( [&]{ for ( auto n = 0; n < 16; ++n ) LOGE << "\(^o^)/ " << r() << ' ' << r()<< ' ' << r() << ' ' << ' ' << r(); } ).join();
  a.join();
}

実行結果

ANSI escape codeに対応したモダンな端末だとカラフルに表示されます。

未対応端末だと余計な呪文がちらっと表示されるかもしれませんが、実用上はどうってことはないでしょう(´・ω・`)

実装の要点

  • log( "hoge", 123, ... ); だとなんとなくダサい気がする( variadic template を使えば簡単に実装できるし、安全で無駄なオブジェクトも不要なのは良いけれど...)
    • cout へ出力するように operator<< で見た目キレイにログを出力したい。
      • operator<< を受けてログを出力できるオブジェクトが必要(≃operator<<を持つclassが必要)
  • デバッグ等の助けになる情報を自動的に付加したい
    • __FILE__ __LINE__ __PRETTY_FUNCTION__ (←処理系によって使用できない事もあるので必要に応じて注意)
    • 付加情報をログの前の方に付けると邪魔で読み難くなる → 後ろに付ける
    • operator<< の結合性 → 直接 cout 等へログを整形しながら流さずに一旦ログオブジェクト内のバッファーへ溜め込んでから、 dtor で付加情報も付けて cout 等へ流す必要がある
  • 実行時間もログに出力したい
    • std::chrono::steady_clock は処理系によって分解能が不十分
      • boost::timer::cpu_timerboost::chrono::steady_clock を使う → 外部ライブラリーのリンクが必要になって「さっと使える」度がダウン(´・ω・`)
      • std::steady_clock or QueryPerformanceCounter ( Windows ) を使い分ければ実用上わりと困らなくなる → usagi::chrono::default_clock (こんなこともあろうかと)
  • info, warn, error, debug くらいはログの種類分けが欲しい、ついでに種類ごとに色も変えてわかりやすく出したい。
  • 一応ログ無効化手段は欲しい → 無効化をマクロ定義されていれば operator<< はあるけれど何もしないログオブジェクトに << が接続されるようにする
  • 「さっと」使えて「便利」で「見た目かっこいい」のが目的なので、器用な出力切り替えだとか、実行速度上のデメリットだとか、こまかいことは気にしない。とりあえずざっくり動いてさっくり使えればOK。

初稿後に追加した変更

  • マルチスレッドで使っても崩れずキレイに出力される。