📌

javaのログライブラリまとめ(slf4j, logback, log4j2)

2023/02/16に公開

背景

javaのログ出力ライブラリ、log4jとかslf4jとかよく見るけどなんとなくでしか使っていなかったので調べてみた。
とりあえず、めちゃくちゃややこしい。

先にまとめ

  • ログライブラリは、interfaceの役割を持つもの(ファサード)と実際のログ出力を実行するもの(実装)に大別される
    • slf4j, log4j2(のlog4j-api), commons logging は ファサード
    • logback, log4j2(のlog4j-core), log4j, java util logging は 実装
  • ファサードはログ出力APIだけを提供し、実際のログ出力は実装ライブラリに移譲する
  • slf4j, log4j2 は他のログライブラリ経由で送られるログを乗っ取る仕組みを持つ
  • 現在は slf4j + logback が広く使われており、対抗馬としてlog4j2(log4j-api + log4j-core)がある

※ ファサードと実装の区分はあくまでざっくりで、slf4jも簡易ログ出力実装を持っていたりするので厳密ではない

ログ出力ライブラリの歴史

これがめちゃくちゃわかりやすい。
https://qiita.com/nisshiee/items/c5388f1d472ec86295e0

上記記事に記載のある下記のスライドも良かった。
https://www.slideshare.net/miyakawataku/concepts-and-tools-of-logging-in-java

まとめると

  • まず、log4jが誕生しデファクトスタンダードになった
  • java 標準の java.util.logging(jul) が生まれたが、そこまで流行らなかった
  • OSSのライブラリは log4j を使うものと jul を使うものに分かれたため、複数のOSSライブラリを入れると、log4jとjulが混在することになった
  • そこで、commons logging が登場し、 log4jとjulを統一したインターフェースで扱えるようになった
  • しかし、commons logging も使いにくかったので、他のログライブラリ経由で送られるログを乗っ取る仕組みを持つ slf4j が誕生し、デファクトスタンダードとなった
    という感じの経緯になっている。

slf4j について

デファクトスタンダードとなったslf4jについてもう少し見ていく。
slf4j は logback とセットで開発され、 slf4j (ファサード) + logback (実装) の組み合わせで利用されることが多い。

前述の通りslf4jは

  • ファサードであり
  • 他のログライブラリ経由で送られるログを乗っ取る仕組みを持ち
  • 他のログ実装ライブラリを利用する

という特徴がある。

この3つの観点で整理している記事がこちら↓
https://www.bunkei-programmer.net/entry/2012/10/20/javaのロガーが多すぎて訳が解らないので整理して

①ファサードとして他のlogライブラリにログ出力処理を移譲する仕組み
②他のログライブラリ経由で送られるログを乗っ取る仕組み
がキモとなる。

①ファサードとしてのslf4j

まずファサードとして、他のlogライブラリにロク出力処理を移譲するという仕組みについて。
例えば、slf4j を利用して log4j に処理を移譲する場合は slf4j-log412.jar というアダプタが log4j に接続してくれる。
また、 java.util.logging(jul)に処理を移譲する場合は slf4j-jdk14.jar というアダプタが jul に接続してくれる。
logback は、 slf4j とセットで使う前提で作られたものであり、 slf4j-api から直接使うことができる。

ややこしいのが、 slf4j から他のファサードに対しても処理を移譲することもでき、
commons logging や log4j-api に対してもアダプタが 用意されている点である。
(log4j-apiに対してはlog4j側がアダプタを用意している)

slf4jというファサードから別のファサードを介して、ログ実装ライブラリを通して出力されることになる。

②他のログライブラリを乗っ取る仕組み

log4j や java.util.logging を利用しているライブラリをアプリケーションに組み込んでいても、slf4j を通してログ出力をさせることができる。

例えば、slf4j+logback の構成でアプリケーションを構築する際に、
log4j を利用してログを出力するライブラリを追加した場合に、slf4j に log4j 経由でのログを乗っ取らせ、logbackでログを出力させることができる。

ここでも、乗っ取りを行うためにアダプタが用意されていて、
アダプタが元々のログ出力ライブラリの処理を上書きし、slf4jにログを送り込むという仕組みになっている。

また、こちらも別のファサードを乗っ取る仕組みも用意されており、
commons logging を利用したログを slf4j で乗っ取ることができる。

log4j2について

slf4j/logback が普及したのち、log4j の version2 (log4j2) が登場した。
log4j2 は slf4j (ファサード) + logback (実装) と似たような構成となっており、 log4j-api がファサード、 log4j-core が実装 となっている。
log4j-core のログ実装は他のログ実装ライブラリよりも格段にパフォーマンスが良いとされている。
また、世間を騒がせた log4shell の脆弱性を作り込んだのがこの log4j2 である。

log4j2 は slf4j 同様に他のログライブラリの乗っ取りの機能も備えているため、
slf4j 経由で log4j2 を使うことができたり、 log4j2 経由で slf4j を使うことができたりと、ややこしさに拍車をかけている。

様々なファサード、ログ実装ライブラリの組み合わせを図示したものがこちら。

(https://www.alibabacloud.com/blog/java-logging-frameworks-summary-and-best-practices_598223 より引用)

ややこしすぎる、、。

何を使うべきか

結局どのライブラリを使えばいいのか。

https://blog.kengo-toda.jp/entry/2021/05/31/200807
上記の記事では、slf4j/logback の開発は停滞しているから、新規開発では log4j2 を使うべきと書かれているが、
slf4j/logback の開発は2021年ごろから再び進むようになっており、2023年現在では積極採用すべきではないとまでは言えないように見える。

結論、安定を求めるなら広く使われている slf4j + logback を、
パフォーマンスを求めるなら log4j2 を使ってみるとよいと考える。

Discussion