2.1 最初のロガー - log4j
すでにご存知のとおり、ログの歴史はSystem.err.println()
コンソールへのレコードの出力から始まりました。これは今でもデバッグに積極的に使用されており、たとえば、Intellij IDEA はコンソールにエラー メッセージを表示するために使用しています。ただし、このオプションには設定がないため、次に進みます。
最初で最も人気のあるロガーは と呼ばれるものでしたLog4j
。これは優れた、高度にカスタマイズ可能なソリューションでした。さまざまな状況により、この決定は JDK に反映されず、コミュニティ全体が大きく動揺しました。
このロガーは単にログを記録できるだけでなく、プログラマーによってプログラマーのために作成され、ログに関連して常に発生する問題を解決できるようにしました。
すでにご存知のとおり、ログは最終的に書き込まれ、誰かがそれを読んで、プログラムの動作中に何が起こったのか、つまり、いつ、何が予想どおりに失敗したのかを理解しようとします。
そのためには次の 3 つのことが必要log4j
でした。
- サブパッケージのロギング。
- アペンダーのセット (結果);
- ホットリロード設定。
log4j
まず、あるパッケージではログインを有効にし、別のパッケージでは無効にするように設定を記述することができます。たとえば、 ではロギングを有効にしてもcom.codegym.server
、 では無効にすることができますcom.codegym.server.payment
。これにより、ログから不要な情報を素早く削除することが可能になりました。
次に、log4j
ログ結果を複数のログ ファイルに一度に書き込むことができました。そして、それぞれへの出力は個別に設定できます。たとえば、あるファイルには重大なエラーに関する情報のみを書き込み、別のファイルには特定のモジュールからのログを、そして 3 番目のファイルには一定期間のログを書き込むことができます。
したがって、各ログ ファイルは、予想される特定の種類の問題に合わせて調整されています。これにより、ギガバイトのログ ファイルを手動で調べるのが苦手なプログラマの作業が大幅に簡素化されます。
そして最後に、第三に、log4j
プログラムを再起動せずに、プログラムの実行中にログ設定を直接変更できるようになりました。これは、特定のエラーに関する追加情報を見つけるためにログの内容を修正する必要がある場合に非常に便利でした。
重要!ログには 1.2.x と 2.xx の 2 つのバージョンがありlog4j
、相互に互換性がありません。
次のコードを使用して、ロガーをプロジェクトに接続できます。
<dependencies>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.17.2</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.17.2</version>
</dependency>
</dependencies>
2.2 最初の公式ロガー - 7 月: java.util.logging
Java コミュニティにロガーの動物園が登場した後、開発者はJDK
誰もが使用できる標準ロガーを 1 つ作成することにしました。ロガーは次のように表示されますJUL
: package java.util.logging
。
log4j
ただし、ロガーの開発中に、ロガーの作成者は ではなく、IBM のロガーの亜種を基礎として採用し、それが開発に影響を与えました。良いニュースは、ロガーがJUL
含まれていることですがJDK
、悪いニュースは、それを使用している人がほとんどいないことです。
開発者は「別の普遍的な標準」JUL
を作成しただけでなく、その標準に対応する独自のログ レベルも作成しました。これは、当時一般的なロガーによって受け入れられていたレベルとは異なります。
そしてそれは大きな問題でした。結局のところ、製品はJava
多数のライブラリから収集されることが多く、そのような各ライブラリには独自のロガーがありました。したがって、アプリケーション内のすべてのロガーを構成する必要がありました。
ロガー自体はかなり優れていますが。ロガーの作成もほぼ同じです。これを行うには、以下をインポートする必要があります。
java.util.logging.Logger log = java.util.logging.Logger.getLogger(LoggingJul.class.getName());
ログの送信元を知るために、クラス名が特別に渡されます。
このリリースでのみ、開発者は重要な問題を解決しました。その後、JUL
非常に使いやすくなりました。それまでは、ある種の二流ロガーでした。
このロガーは、ラムダ式と遅延評価もサポートしています。から始めてJava 8
、 を通過できますSupplier<String>
。これにより、以前のように毎回ではなく、本当に必要なときにのみ文字列を読み取って作成することができます。
引数を持つメソッドはSupplier<String> msgSupplier
次のようになります。
public void info(Supplier msgSupplier) {
log(Level.INFO, msgSupplier);
}
2.3 最初のロガーラッパー - JCL: jakarta commons ロギング
長い間、ロガー間に単一の標準は存在しませんでした。JUL
単一の標準になるはずでしたが、さらに悪いことlog4j
に、単一の標準が現れることはありませんでした。しかし、木こりの動物園全体が現れ、それぞれが同じになりたいと考えていました。
しかし、一般の Java 開発者は、ほとんどすべてのライブラリに独自のロガーがあり、何らかの特別な方法で設定する必要があることを好みませんでした。したがって、コミュニティは他のロガーに対する特別なラッパーを作成することを決定しました。これがその方法です。JCL: jakarta commons logging
そしてまたしても、リーダーになるために作られたプロジェクトは一つにはならなかった。勝者を生み出すことはできず、勝者になることしかできません。機能はJCL
非常に貧弱で、誰も使いたがりませんでした。すべてのロガーを置き換えるように設計されたロガーは、使用されなかったため、同じ運命をたどりましたJUL
。
Apache コミュニティによってリリースされた多くのライブラリに追加されていますが、ロガーの動物園は成長するばかりです。
2.4 最初と最後のロガー - Logback
しかし、それだけではありません。開発者はlog4j
自分が最も賢いと判断し (結局のところ、ほとんどの人が彼のロガーを使用していました)、log4j
他のロガーの利点を組み合わせた新しい改良されたロガーを作成することにしました。
新しいロガーは と呼ばれましたLogback
。このロガーは、将来誰もが使用する単一のロガーになるはずでした。と同じ考え方に基づいていますlog4j
。
次のコードを使用して、このロガーをプロジェクトに接続できます。
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.6</version>
</dependency>
違いは次のとおりですLogback
。
- パフォーマンスを向上させた;
- ネイティブサポートを追加しました
slf4j
。 - フィルタリングオプションが拡張されました。
このロガーのもう 1 つの利点は、非常に優れたデフォルト設定があることです。また、ロガーの何かを変更したい場合にのみ、ロガーを設定する必要がありました。また、設定ファイルは企業ソフトウェアにさらに適合し、すべての構成が として設定されましたxml/
。
デフォルトでは、Logback
設定は必要なく、そのレベルDEBUG
以上のすべてのログが記録されます。xml
別の動作が必要な場合は、構成を通じて構成できます。
<configuration>
<appender name="FILE" class="ch.qos.logback.core.FileAppender">
<file>app.log</file>
<encoder>
<pattern>%d{HH:mm:ss,SSS} %-5p [%c] - %m%n</pattern>
</encoder>
</appender>
<logger name="org.hibernate.SQL" level="DEBUG" />
<logger name="org.hibernate.type.descriptor.sql" level="TRACE" />
<root level="info">
<appender-ref ref="FILE" />
</root>
</configuration>
2.5 最新のユニバーサル ロガー - SLF4J: Java 用のシンプルなロギング ファサード
黄金の中庸を見つけるのにどれくらい時間がかかりますか...
2006 年に、作成者の 1 人がlog4j
プロジェクトを離れ、ユニバーサル ロガーの作成に再挑戦することにしました。しかし、今回は新しいロガーではなく、異なるロガーが相互に対話できるようにする新しいユニバーサル標準 (ラッパー) でした。
このロガーは と呼ばれ、、slf4j — Simple Logging Facade for Java
のラッパーでした。このロガーは、ロガーの動物園を管理するという実際の問題を解決したため、全員がすぐにそれを使い始めました。log4j
JUL
common-loggins and logback
私たちは自分たちで作り出した問題を勇敢に解決します。ご覧のとおり、ラッパーの上にラッパーを作成するところまで進歩しました。
ラップ自体は 2 つの部分で構成されます。
API
、アプリケーションで使用されます。- ロガーごとに個別の依存関係として追加される実装。
次のコードを使用して、ロガーをプロジェクトに接続できます。
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.17.2</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.17.2</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
<version>2.17.2</version>
</dependency>
正しい実装を接続するだけで十分です。プロジェクト全体がそれを使用して動作します。
2.6 slf4j での最適化
Slf4j
は、ロギング用の文字列フォーマットなどのすべての新機能をサポートします。この前にもこんな問題がありました。メッセージをログに出力したいとします。
log.debug("User " + user + " connected from " + request.getRemoteAddr());
このコードには問題があります。アプリケーションが動作しproduction
、ログに何も書き込まないとしますDEBUG-messages
。ただし、メソッドはlog.debug()
引き続き呼び出され、呼び出されるときに次のメソッドも呼び出されます。
user.toString();
request.getRemoteAddr();
これらのメソッドを呼び出すと、アプリケーションの速度が低下します。これらの呼び出しはデバッグ中にのみ必要ですが、とにかく呼び出されます。
ロジックの観点から見ると、この問題はログ ライブラリ自体で解決する必要がありました。そして、log4j の最初のバージョンでは、次のような解決策が考えられました。
if (log.isDebugEnabled()) {
log.debug("User " + user + " connected from " + request.getRemoteAddr());
}
ログを 1 行ではなく、3 行書き込む必要がありました。これにより、コードの可読性が大幅に悪化し、 の人気が低下しましたlog4j
。
ロガーはslf4j
スマート ロギングを提供することで、状況をわずかに改善することができました。次のようになりました。
log.debug("User {} connected from {}", user, request.getRemoteAddr());
ここで、{}
はメソッドに渡される引数の挿入を示します。つまり、最初のは{}
user に対応し、2 番目{}
は に対応しますrequest.getRemoteAddr()
。
これらのパラメータは、ログ レベルでログが許可されている場合にのみ、単一のメッセージに連結されます。完璧ではありませんが、他のすべてのオプションよりも優れています。
その後、SLF4J
急速に人気が高まり始めましたが、現時点ではこれが最善の解決策です。
したがって、バンドルの例を使用してロギングを検討しますslf4j-log4j12
。
GO TO FULL VERSION