Kengo's blog

Technical articles about original projects, JVM, Static Analysis and TypeScript.

3行で解説するSLF4Jの使い方

すみません、この前のエントリでSLF4JというかJavaのロギングがとてもややこしいものだという印象を残してしまったようです。そんなことないので、ログ出力の使い方についてさくっと説明することで誤解を解きたいと思います。

SLF4Jでログを出すのは、たったの3ステップで終わります。

  1. LoggerFactpry.getLogger(Class)メソッドを使ってLoggerインスタンスを取得する。
  2. 適切なログレベルを検討する。
  3. 選択したログレベルに対応するメソッドを呼び出してログを出力する。

たったこれだけ!ログを出す人はファイルの形式とか保存先とかログローテーションとかを一切考えなくて構いません。バインディングを意識する必要もありません。

void sayHello(String target) {
  Logger logger = LoggerFactory.getLogger(this.getClass());
  logger.info("Hello, {}", target);
}

例外オブジェクトをログに残したいときは、最後の引数に例外を渡してあげます。

} catch (SecurityException e) {
  logger.error("Something happen, but we can ignore because this is sample code.", e);
}

ログ文字列中にある{}というのは、そこにパラメータを埋め込むためのプレースホルダです。System.out.printf()String.format(), MessageFormat.format()プレースホルダとだいたい同じと考えて大丈夫です。

これを使うと文字列生成を遅延させられるので、余計な条件判定やオブジェクト生成を省略でき、可読性とパフォーマンスが良くなります

/**
 * 古いロギングライブラリでは、デバッグ出力が有効かどうかを事前に判別することが
 * 推奨されていた。
 *
 * もしifが無いと、デバッグ出力が無効な場合でも{@code "debug data: a = " + a + ", b = " + b}と
 * いう文字列生成が実行されてしまい、余計なリソースを使ってしまう。
 */
void traditionalWay() {
  if (logger.isDebugEnabled()) { // 文字列生成を行わないために、自分でifを書く必要がある。
    logger.debug("debug data: a = " + a + ", b = " + b);
  }
}

/**
 * SLF4Jではログレベルの判別と文字列生成をライブラリの内側で処理してくれるので、
 * プレースホルダを使うように心がけさえすればifブロックを書く必要がない。
 */
void simplifiedWay() {
  logger.debug("debug data: a = {}, b = {}", a, b); // debugログを出す必要がない場合は、文字列生成が行われない。
}

以上です。こんな簡単なインタフェースで例外オブジェクト(スタックトレース)の保存やパフォーマンス向上まで面倒を見てくれる、かなり良いライブラリだということが伝わりましたら幸いです。

see also