Java のロガーってたくさんありますね。Guava は java.util.logging.Logger を使ってますし、Spring Framework や Apache 関連のライブラリは Apache Commons Logging を使っています。パッと用例が出て来ませんが、Log4J や、SLF4J もあります。
まとめると有名所だけでも、これだけあります:
うんざりですね。
これらを依存ライブラリがバラバラに使っていると、ログレベルごとの出力制御が一元化できなかったり、ログフォーマットのバラツキが発生しやすくなり、つらいです。
上に上がっている SLF4J には、これらの出力をブリッジして1つにまとめることのができるモジュールがあります。
この記事ではこれらのモジュールについて簡単にメモします。
ここに書いてあることは、基本的には Log4j Bridge を見れば全て書いてありますので詳しく知りたい方は参照してください。
これを書くにあたり、以下のようなサンプルを作りました:
それぞれをブリッジしてくれるライブラリ
以下のようになっています:
- java.util.logging.Logger → jul-to-slf4j
- Apache Commons Logging →jcl-over-slf4j
- Log4J → log4j-over-slf4j
XXX-over-sjf4j
に関しては、maven の依存関係や、クラスパスに追加すれば自動的にブリッジしてくれるようになります。ただし、他の依存関係によって読み込んでいる commons-logging
や log4j
を exclude しないと 予期しない挙動を起こす可能性があります。
jul-to-slf4j
は他の2つと違い、ブリッジの実装が違うため、使い方も少し手間が必要になります。
jul-to-slf4j
によるブリッジ実現方法
SLF4JBridgeHandler の javadoc にも書いてありますが、java.util.logging.Logger
の出力をブリッジするには以下のようなメソッドの呼び出しが必要になります:
SLF4JBridgeHandler.removeHandlersForRootLogger();
SLF4JBridgeHandler.install();
これ以降は、java.util.logging.Logger
自身の出力は抑制され(一行目)、代わりに SLF4J がログをとってくれるようになります(二行目)。
ただし、上記した Log4j Bridge も書いてあるとおり注意が必要になります。
jul-to-slf4j
の注意点
端的に言うと、ブリッジのオーバーヘッドがあまりにも大きいようです。
これに関しては、Log4j Bridge の jul-to-slf4j の "Note on performance" に書いてあります:
Consequently, j.u.l. to SLF4J translation can seriously increase the cost of disabled logging statements (60 fold or 6000%) and measurably impact the performance of enabled log statements (20% overall increase).
対策としては、logback.xml
に以下のようなリスナーを追加すると、オーバーヘッドを軽減できるようです:
<configuration>
<contextListener class="ch.qos.logback.classic.jul.LevelChangePropagator">
<resetJUL>true</resetJUL>
</contextListener>
...
</configuration>
以上です。おわり。