今回はログの収集についてです。
状況設定
ログを取るためにライブラリを使用する必要があるのは、複数のモジュールがあるときに
特定のモジュールからのログを選り分けたりする必要がある場合です。
最小の状況設定として以下の場合を考えます。
CMakeLists.txt
mod1/CMakeLists.txt
func.hpp
func1.cpp
func2.cpp
logger.cpp
client.cpp
あるモジュールmod1
をclient.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にあります。
loggerの定義
自作loggerを作る事によって、そのloggerによって収集されるログに情報を付加できます。
以下で深刻度付きのloggerを生成します
namespace mod1 {
enum severity_level { debug, info, warning, error, critical };
BOOST_LOG_INLINE_GLOBAL_LOGGER_DEFAULT(
logger, // loggerの名称
boost::log::sources::severity_logger_mt<severity_level> // loggerの型
);
} // namespace mod1
これでmod1::logger
が定義されます。
これは例えば以下のように使います。
namespace mod1 {
void func1() {
auto &lg = logger::get();
BOOST_LOG_SEV(lg, info) << "info in mod1::func1";
}
} // namespace mod1
loggerの実体は::get()
で取得します。
BOOST_LOG_SEV
は深刻度と一緒にログを記録するためのマクロです。
info
はmod1::info
な事に注意してください。
Tag, Scopeの追加
Boost.Logでは別のloggerで収集されたログは全て同じようにsinkに送られます。
つまりデフォルトではどのloggerから出力されたのかわかりません。
そこでloggerに、そのloggerで収集されたログに情報を付加する設定をします。
namespace mod1 {
void init() {
auto &lg = logger::get();
lg.add_attribute("Tag", attrs::constant<std::string>("mod1"));
lg.add_attribute("Scope", attrs::named_scope());
}
} // namespace mod1
モジュール自体の初期化コードでloggerを設定します。
これでmod1::logger
を通して収集されたログにはタグ"mod1"が付きます。
またログがどの関数で収集されたか、さらに言えばどのif文等のどのスコープで出力されたか、
というのは重要な情報である場合が多いです。
これを保持するのがScope
です。
これは常に値が一定("mod1")のタグと異なり、収集されるログ毎に値が変化します。
namespace mod1 {
void func1(bool flag) {
BOOST_LOG_FUNCTION(); // Scopeに関数名(void func1(boo))を登録する
auto &lg = logger::get();
if (flag) {
BOOST_LOG_NAMED_SCOPE("true case"); // Scopeに入った事を記録する
BOOST_LOG_SEV(lg, info) << "flag is true";
} else {
BOOST_LOG_NAMED_SCOPE("false case"); // Scopeに入った事を記録する
BOOST_LOG_SEV(lg, info) << "flag is false";
}
BOOST_LOG_SEV(lg, error) << "Some error occurs!!";
}
} // namespace mod1
まとめ
これでモジュール中でログを収集する事が可能になりました。
trivialの場合と比べるとloggerを作る必要があるため、少し面倒ですが、
といっても数行追加するだけで済みました。
付加情報はloggingライブラリには必須なので、是非導入しましょう。
次回は収集したログを出力する方法をまとめます。