Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationEventAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
17
Help us understand the problem. What are the problem?

More than 1 year has passed since last update.

posted at

Organization

Rust:logでログ出力を行う

この記事はWanoアドベントカレンダーの14日目の記事です。

TL;DR

  • log crateとenv_logger crateで基本的には何でも出来る
  • env_loggerでは不十分な場合はcrate.ioで探すか、自分でLog traitを実装する

Rustでログ出力をするにはlogとlogに対応したcrateを使おう

Rustにはログ出力の為の枠組みを定めたlog crateというものがあります。
log crateはLog traitとdebug/info/warn/errorというprintlnと同じ引数を取れるログ出力の為のマクロを提供していて、debugwarnマクロでログ出力を行っていれば、Log traitの実装として何を利用するかは自由に選べるようになっています。

このLog traitを実装したライブラリには次のような物があります。

例えばenv_loggerを使う場合は次の様なコードになります。

use env_logger;
use log::{error, warn, info, debug};
use std::env;

fn main() {
    env::set_var("RUST_LOG", "info");
    env_logger::init();

    debug!("debugです");
    info!("infoです");
    warn!("warnです");
    error!("errorです");
}

env_loggerはその名の通りRUST_LOG環境変数によって出力するログレベル等を設定する事ができます。
上のコードではinfoを値に入れていますので、infoレベル以上のログレベルのログだけ出力されます。つまりdebugログは出力されません。

またenv_loggerのようなcrateは多くがinit関数を提供しています(恐らくlog crateのドキュメントにこういう関数を提供して初期化処理を隠蔽しましょうと書いてある為)。
これによってロガーの初期化が行われますので、main関数の最初に呼ぶようにしましょう。

上のコードを実行した結果は次の様になります。

[2018-12-15T05:53:53Z INFO  playground] infoです
[2018-12-15T05:53:53Z WARN  playground] warnです
[2018-12-15T05:53:53Z ERROR playground] errorです

env_loggerの出力をカスタマイズする

env_loggerの標準のフォーマットでは不足がある場合はカスタマイズする事ができます。
ここではログ出力を行ったファイル名と行番号を足してみましょう。

env_loggerには出力フォーマットの設定をする為にBuilder型が提供されています。
この型のformatメソッドを使って出力内容をカスタムします。

use env_logger;
use log::{error, warn, info, debug};
use std::env;
use std::io::Write;

fn main() {
    env::set_var("RUST_LOG", "info");
    env_logger::Builder::from_default_env()
        .format(|buf, record| {
            let ts = buf.timestamp();
            writeln!(
                buf,
                "[{} {} {}] {} {}:{}",
                ts,
                record.level(),
                record.target(),
                record.args(),
                record.file().unwrap_or("unknown"),
                record.line().unwrap_or(0),
            )
        })
        .init();

    debug!("debugです");
    info!("infoです");
    warn!("warnです");
    error!("errorです");
}

Builder::from_default_env()でBuilderオブジェクトを生成する事でinitで初期化した場合と使い勝手を変わらなくすることが出来ます(この他にnewfrom_envというメソッドでもBuilderオブジェクトを生成できますが、こちらは挙動が少し変わります)。

次にBuilderのformatメソッドを使ってログのフォーマットを定義します。
formatメソッドはFn(&mut Formatter, &Record) -> Result<()> + Sync + Sendという型のクロージャを引数に取ります。
あとはFormatterRecordのドキュメントを参照しつつ、writelnマクロでFormatterに書き込むコードを書きます。

このコードを実行すると次のような出力になります。

[2018-12-15T06:45:39Z INFO playground] infoです src/main.rs:25
[2018-12-15T06:45:39Z WARN playground] warnです src/main.rs:26
[2018-12-15T06:45:39Z ERROR playground] errorです src/main.rs:27

各行の末尾にファイル名と行番号を追加することが出来ました。

env_loggerでは不十分な場合

crate.ioで必要な機能を持ったcrateを探すか、自分でLog traitを実装するかのどちらかになります。

Log traitを実装する時は次の3つのメソッドを実装します。

また初期化関数(例えばinit関数)を提供し、その中でset_logger(又はset_boxed_logger)とset_max_level関数を呼んで自前のロガーとログレベルをセットします。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
17
Help us understand the problem. What are the problem?