Edited at

Rustでのロギング

Rustで使えるロガーを調べてみます。この記事ではいくつかある実装のうち、


  • env_logger

  • simple_logger

  • stderrlog

を動かしてみました。


log crate

Rustのlog crateinfo!等のマクロが定義されてますが、用途に応じてその実装を選べる作りになっているようです。


log実装の一覧

Available loggin implementationsの転載です。


  • Simple minimal loggers:


    • env_logger

    • simple_logger

    • simplelog

    • pretty_env_logger

    • stderrlog

    • flexi_logger



  • Complex configurable frameworks:


    • log4rs

    • fern



  • Adaptors for other facilities:


    • syslog

    • slog-stdlog_




env_logger

logの実装でどれを使えばいいのか分かりませんが、crates.ioによるとenv_loggerのダウンロード数が圧倒的に多いようです。

#[macro_use]

extern crate log;
extern crate env_logger as logger;

use log::Level;
use std::env;

fn main() {
env::set_var("RUST_LOG", "info");
// env::set_var("RUST_LOG", "trace");
logger::init();

debug!("this is a debug {}", "message");
error!("this is printed by default");

if log_enabled!(Level::Info) {
let x = 3 * 4; // expensive computation
info!("the answer was: {}", x);
}
}

実行ファイルの名前がmainとすると、次のような実行結果が得られます。env_loggerのデフォルトログレベルはErrorで、標準エラー出力に書き出されます。ソースコードの中で環境変数のRUST_LOGInfoに設定しているため、ここではerrorinfoは出力されていますが、debugは何も出ませんね。

$ ./main

[2019-03-24T14:16:11Z ERROR log_sample] this is printed by default
[2019-03-24T14:16:11Z INFO log_sample] the answer was: 12


simple_logger

crateの名前の通り、シンプルに標準出力に書き出します

#[macro_use]

extern crate log;
extern crate simple_logger as logger;

use log::Level;

fn main() {
// logger::init().unwrap();
logger::init_with_level(Level::Info).unwrap();

debug!("this is a debug {}", "message");
error!("this is printed by default");

if log_enabled!(Level::Info) {
let x = 3 * 4; // expensive computation
info!("the answer was: {}", x);
}
}

実行ファイルの名前がmainとすると、次のような実行結果が得られます。simple_loggerのデフォルトログレベルはtraceですが、そのレベルは簡単に変更できるみたいです。多くのloggerの実装ではこのようなinit関数が用意されているとのことです。

$ ./main

2019-03-24 23:32:48 ERROR [log_sample] this is printed by default
2019-03-24 23:32:48 INFO [log_sample] the answer was: 12


stderrlog

もう一つくらい、stderrlog試してみます。

#[macro_use]

extern crate log;
extern crate stderrlog as logger;

use log::Level;

fn main() {
logger::new()
.module(module_path!())
.verbosity(2)
.init()
.unwrap();

debug!("this is a debug {}", "message");
error!("this is printed by default");

if log_enabled!(Level::Info) {
let x = 3 * 4; // expensive computation
info!("the answer was: {}", x);
}
}

実行結果は次のようになります。タイムスタンプを入れたりもっと細かい設定もできますが、ここではサボっています。実行結果は次のようになります。

$ ./main

ERROR - this is printed by default
INFO - the answer was: 12

注意点としては、stderrlogのverbosityがログレベルに相当するのですが、logcrateのLovelとは微妙にずれているのでverbosity(Level::Info as usize)等とすると期待する結果とずれてしまいました。ソースコードで確認しといたほうが良さそうですね。


補足(?)

use ... as loggerとすればダックタイピングになるかなと期待したのですが、実装ごとに初期化に必要な手順が異なってるのでほとんど意味がありませんでしたorz


参考にした記事など


コード

log_sample