以下自動翻訳です。
—-
これは記憶によるものなので、間違いがあっても私の責任でることはご了承ください。
—-
Javaアプリケーションは、複数の依存関係で構成されています。これらの依存関係は、ログを取りたがる傾向にあります。アプリケーションの作者は、1つのAPIを介してすべてのログ情報を収集し、一貫したフォーマット(例:先頭のタイムスタンプ、スレッド名、ログレベルなど)で記録したいと考えます。
1990年代後半:標準出力への書き込み
これらの組み合わせにより、単に標準出力を使用するのではなく、ロギングAPIを使用したいという欲求が生まれました。ライブラリの作者は一貫したAPIに合わせてコーディングすることができ、アプリケーションの作者はAPIを一度設定するだけで、ログを収集したり放出したりするきちんとした柔軟な方法を得ることができました。
Log4j 1.xは、90年代後半にCeci Gulcuという名前の人物によって、このユースケースに対処するために作成されました。
- 1990年代後半: 標準出力への書き込み OR log4jへの書き込み(標準出力への書き込みが可能)。
2000年代初頭、Sunはログ記録がより重要になり、JRE自体が提供するサービスであるべきだと考えました。理想的な世界では、これはすべての人に喜んで受け入れられ、Java開発者はいつでも使用できる1つの真のAPIを持つことになるでしょう。しかし、残念ながらそうはなりませんでした。いくつかのライブラリはlog4jを使い続け、他のライブラリはjulを使い始めました。
- 2000年代前半:標準出力への書き込み、またはlog4j(標準出力への書き込みが可能)への書き込み、またはjul(標準出力への書き込みが可能、または標準出力への書き込みが可能なlog4jにブリッジされている)への書き込み。
コンピュータ・プログラミングの最初のルール(抽象化のレイヤーを追加する)を適用して、commons-loggingはこの事実のすぐ後に生まれました。ロギングバックエンドを抽象化したAPIで、ライブラリ作者がコーディングすべきAPIとなります。アプリケーションの作者は、設定によってバックエンドを選ぶことになり、誰もが幸せになります。ハラショー!
- 2000年代初期/中期: 標準出力への書き込み OR log4jへの書き込み(標準出力に書き込むことができる) OR julへの書き込み(標準出力に書き込むことができる、または、標準出力に書き込むことができるlog4jにブリッジされる)。or commons-loggingへの書き込み(標準出力への書き込み、log4jへのブリッジング、julへのブリッジングが可能)。この時点で再帰的に展開するのはやめておきます)
悲しいことに、commons-loggingは私たちの救世主ではありませんでした。commons-loggingは、クラスローダがアンロードされたときに、いくつかの不幸なメモリリークがあり、それは当時のデプロイメント・メカニズムであるWebサーバやアプリケーション・サーバ(例:Tomcat、Orion)と本当に摩擦がありました。アプリケーションを含むWARまたはEARファイルをフォルダに置くと、以前のバージョンをアンロードし、新しいバージョンをロードし、標準的なJava APIですべてを設定してくれるのです。アプリがデプロイされるたびにログライブラリがメモリをリークし、最終的にアプリサーバ自体(他のテナントをホストしているかもしれない)の再起動を余儀なくされない限り、完璧です。
2005年頃、Ceci Gulcuは、ログ問題にもう一度取り組むことを決め、slf4jを導入しました。このプロジェクトはcommons-loggingに似たアプローチをとっていましたが、API(ライブラリやアプリケーションの作者がコーディングするもの)と実装(アプリケーションの作者だけが選んで設定するもの)をより明確に分けていました。2006年には、sl4jの実装としてlogbackをリリースし、log4j 1xやjulよりもパフォーマンスが向上しました。
- 2000年代半ば/後半: 標準出力への書き込み、log4jへの書き込み、julへの書き込み、commons-loggingへの書き込み、slf4jへの書き込み、そしてslf4jの実装(log4j、logback、julなど)を選ぶ。
この時点で、ライブラリ間のブリッジとシムの完全に接続されたグラフを構築することを可能にする標準出力の船のプラグインを除いて、多かれ少なかれすべてを想定しています。(例えば、jcl-over-slf4jは、commons-logging APIを提供するslf4jライブラリで、 彼らがcommons-loggingに書いていると思うライブラリでさえslf4jを使うことができるようにします)。
2012年頃、slf4jがロギングのための支配的なAPIになることが明らかになり、Ceci Gulcuのslf4jのlogback実装がlog4j 1xよりも速かったとき、人々のチームは一緒に集まり、log4j 1xの埃を払いました。彼らは本質的に完全な書き直しを実行して、まともなレベルの性能と非同期のベルとホイッスルを一緒に得て、そして、それをlog4j2と呼びました。時間が経つにつれて、それは(ライブラリがそうであるように)、JNDIで検索された変数の補間のような、より多くの機能を追加しました - それは構成を抽象化する適切なメカニズムであり、アプリケーションがアプリ・サーバーにデプロイされた2000年代半ばに人気がありました。
2010年代後半:標準出力への書き込み、log4jへの書き込み、julへの書き込み、commons-loggingへの書き込み、slf4jへの書き込み、slf4jの実装(log4j 1x、log4j2、logback、julなど)を選ぶ。
これが私たちの現状です。
あなたがあなたの依存の良い制御を持つ勤勉なアプリケーション・オーサーであるならば、 あなたはおそらく依存のその木を小さく保つことを試みて、 slf4j-apiと単一のロギング実装(あなたが選ぶ)だけがクラスパス上にあることを積極的に保証します。
あなたがよりずさんであるか、または(よりありそうな)あなたが何をインポートするかについてより少ない制御を持っているならば(例えば
サード・パーティ・ベンダーは、彼らのUSBに接続されたウィジェットがインターフェイスすることができる唯一の方法である悪い設計のライブラリをあなたに与えました)、あなたはクラスパス上にあなた自身の選択(slf4j-apiとlogback)とベンダーがまだ依存しているlog4j 1xの両方を持っているのを見つけるかもしれません。この場合、過渡的なlog4j 1x依存を除外して、 slf4jブリッジを挿入して、ライブラリがlog4j 1xであると信じるものに書けるようにしますが、 slf4jにルーティングされます。
あなたが本当にずさんであるか、または(よりありそうな)経験がないならば、 stackoverflowであなたに推薦されたすべてのライブラリをインポートします、 あなたの依存木は巨大になります、そして、あなたはすべてのロギングAPIを持っています、 そして、あなたのアプリケーションの範囲で過去30年にわたって定義された実装。皮肉なことに、私はこれが「開発者」の80%が住んでいるところだと推定します-Javaだけでなく、すべてのエコシステムにわたって。新しい依存関係を導入するコストは、あなたのアプリケーションが何をしているのかを正確に理解するための永遠の警戒心に比べて低いです。
私たちは、悪意や無謀な無能さ、愚かさによってここまで来たのではありません。個々のアクターが合理的に行動し、それぞれの意思決定が25年間にわたって統合され、過去の意思決定に対する経路依存性を持つことでここまで来たのです。
log4j2のJNDIの大失敗は、30年間のソフトウェアのアプローチの中で後方互換性を維持することの難しさ、開発者の間での一般的な攻撃面の理解の欠如、あなたのアプリケーションを理解する上でライブラリがもたらす不透明さ、そしてこの期間に構築されたコードのどれでも再コンパイルせずに喜んで実行できるVMとランタイム環境の荒削りな部分をファイルするためのOracleのJavaチームによる(率直に言って)過小評価されているけれども堅実な努力の上に、独自の記事に値するでしょう。