SLF4Jのドキュメント読むよ
SLF4Jマニュアルを読んで気になるところについてメモなどを書く
user manual
vesion
2系
fluent APIが使える
Java8対応
logging backendの検索にServiceLoaderが使われる様になったっぽい
HelloWorld
最初にslf4j-apiだけ依存を入れてログを出すと以下のようなワーニングがでて、logging backendにバインドできないと言われる
code: log
SLF4J: No SLF4J providers were found.
SLF4J: Defaulting to no-operation (NOP) logger implementation
ひとまず、slf4j-simpleを入れると標準出力に繋いでくれるので、コンソールにログが出るようになると
Fluent Logging API
LoggingEventBuilderが一つ一つイベントを記録していく
atTrace, atDebug, atInfoなどのメソッドはすべて、LoggingEventBuilderのインスタンスを返すようになってる
無効なログレベルの場合、LoggingEventBuilderは何もしないので従来のようにnanosecondレベルのパフォーマンスが維持される
ここよくわからんが普通にFluent Logging API使うと多少は遅いってはなし?
Linking with a logging framework at deployment time
SLF4Jは様々なロギングフレームワークのファサードして意図されている
SLF4Jが提供してるproviderと呼ばれる依存が、各ロギングフレームワークと接続してくれるくんのこと
SLF4J1.7以前はproviderに対して、bindingという用語が使われていたので留意が必要
下記のAdaptorレイヤがプロバイダ
https://gyazo.com/22f3353ea655ad9ea7e29381ed760e7e
slf4j-nop.jar面白いな
何もproviderがない場合と行き着く先は一緒だけど、このproviderは/dev/nullに送るproviderなのね
SLF4Jのinterfaceやadaptersはとてもシンプルとのこと
クラスローダーとかも使ってないので、Jakarta Commons Loggingのようにメモリリークとかも起きないとのこと
Libraries
SLF4J1.6.0以降bindingが見つからない場合(つまりproviderがない場合)、すべてのログが破棄される
警告メッセージが出るだけで、それ以降無言でログの要求を破棄する
基本ライブラリやFWなどの組み込みコンポーネントは、slf4j-apiだけに依存するべきである
Declaring project dependencies for logging
slf4j-api
ほとんどのロギング実装は自動でこの依存を含むけど、mavenの場合一番近い依存を使う動きになるので、明示で気にpom.xml内で宣言するのがおすすめ
Note that if two dependency versions are at the same depth in the dependency tree, the first declaration wins.
logback-classic
logging frameworkとしてlogbackを使う場合
slf4j-log4j12
log4jの1系とのbinding用
log4j-slf4j-implとどっちがいいんだろとか一瞬おもったけどlog4j1は基本もう使わないので考えない
(書いてないけど) log4j-slf4j2-impl
log4j2とのbinding用
slf4j-simple
コンソールに出して動きみたいくらいの感じならコレをいれればよい
slf4j-apiも含まれるけど前述のとおりpom.xmlで明示的にslf4j-apiを宣言したほうがいいとのこと
Binary compatibility
基本provider系の依存と、slf4j-apiのバージョンは揃えましょう
バージョン不一致の問題がありそうな場合は警告ログが出るよとのこと
SLF4Jによるログの統合
SLF4JはJCL、java.util.logging、および log4jへのブリッジングモジュールを提供するので、コレを入れておけば例えばCommons logging APIとかでログ出している箇所とかもSLF4Jに統合してログ出力できたりする
https://gyazo.com/172bdbcd5d094e5f7b22bff82f0812c6
古い依存とか入っていてログ出力が揃ってない場合とかに便利だと思う
Support for JDK Platform Logging (JEP 264) SLF4J
2.0.0-ALPHA5以降 JEP264のサポートも入ってるとのこと
これからやるならそもそもSLF4JからSystem.Loggerに置き換えたらいいんじゃないか感がある
Mapped Diagnostic Context (MDC) support
MDCはロギングフレームワークによって管理されるmap
アプリケーションがkey-valueペアの値を設定すると、ログに値を出力できる
MDCのデータはフィルタリングや特定のアクションのトリガーとしても役に立つ
ベースのログ出力ライブラリがMDC的な機能を提供している場合、SLF4Jはログ出力ライブラリにMDC機能を以上する
現状だとlog4j, logbackのみがMDCを提供している
FAQ
どのようなときにSLF4Jを使うべき?
ライブラリや組み込みコンポーネントは、それを使うユーザにロギングフレームワークの選択を押し付けることができないのでSLF4Jでログを出しておくのが良い
あーユーザ側がプロバイダ入れてくれれば確かに出力できるからってことかな
スタンドアロンのアプリの場合は必ずしも使わなくても良い
ただ、スタンドアロンの場合でも、内部依存ごとに使ってるロギングフレームワークがバラバラだったりするケースだと、JCLつかってSLF4Jにまとめてやるのは便利だと思う
What has changed in SLF4J version 2.0.0?
fluentAPI野ついイア
プロジェクトJigsawの仕様に沿ってモジュール化されてる
binding(StaticLoggerBInder)のかわりにorg.slf4j.LoggerFactoryは、providerをServiceLoaderで検索するようになった
なので、slf4j-apiとslf4j-simpleとかadaptionレイヤ感のバージョンが2.0と1.7でまたがってるとうまく動かなくなる (providerが探せなかったり、バインドできなかったりする)
Should my library attempt to configure logging?
ライブラリなどの組み込みコンポーネントは必要がないというか、実際ログフレームワークを構成するべきではない
ライブラリはSLF4Jでログは出しても良いが、最終的な出力先はエンドユーザがコントロールできるようになっているべきである
実際ログを読んで対処する必要があるのはエンドユーザです
In order to reduce the number of dependencies of our software we would like to make SLF4J an optional dependency. Is that a good idea?
この辺見てるとこれからはこういう用途ではSystem.Loggerがよさげだなぁ。ライブラリ側はJava標準ライブラリの依存で済むし。
How do I exclude commons-logging as a Maven dependency?
provided scopeでcommons-loggingを指定して、jcl-over-slf4jから完全に互換性のあるcommon-loggingが使われるので、互換が崩れて意図しない動きが起こったりがなくなると
What is the fastest way of (not) logging?
ロガーのparameterizd昨日の積極的に使いましょう (文字列結合を自前でするのではなく)
After evaluating whether to log or not, and only if the decision is affirmative, will the logger implementation format the message and replace the '{}' pair with the string value of entry.
このaffirmative(肯定的に評価された)場合のみというのが何を指すのかがあんまピンと来てない
nullの場合はnullって出るので
あーなんかわかった。例えばdebugレベルのロガー
Why doesn't the org.slf4j.Logger interface have methods for the FATAL level?
冗長だからFATALはslf4jはサポートしてなくてかわりにMarker使えと
Makerはlog4jサポートしてないとあるけど、Log4j2はサポートしてる気がする
What are markers and what are they goood for?
Triggerring
Markerで引っ掛けて例えばメールを送るとかできる
Filtering
重要な情報にMarkerをつけておけばフィルタリングできる
In the presence of an exception/throwable, is it possible to parameterize a logging statement?
SLF1.6.0からはexception/throwableもparameterizeできる
例外オブジェクトがloggerの最後のパラメータとして渡されてあらそれは例外情報だと解釈してStack traceを出力する
例外オブジェクトがloggerの最後のパラメータでない場合はPOJOとして扱われるので、スタックトレースは出力されない
でもそんなシチュエーションは基本ないよね
Should Logger members of a class be declared as static?
昔は静的な宣言よりインスタンス変数として定義することを進めてたけど今は、一方を推奨することはないよ。
長所短所を理解して好きな方を選んでねという感じみたい
ここで書かれてるIOCはInversion of Cotnrol (制御の反転)。ハリウッド原則とも。
Loggerはstaticで宣言するほうが一般的な慣用句とのこと
Appache commonsにもこの話題について参考になる記事があるよとのこと
Loggerをインスタンス変数にするとシリアル化される場合がある
SLF4J1.5.3以降Serializableなので特にtransientつけないとエラーになるとかはないよ
でもややこしいので、この辺も考慮するとやっぱstaticにしたほうが気持ちになってくるなぁ
Is there a recommended idiom for declaring a logger in a class?
静的にするかどうかは前述の通りoptionalだよ
code: java
package some.package;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class MyClass {
final (static) Logger logger = LoggerFactory.getLogger(MyClass.class);
... etc
}