JavaRush コミュニティの皆さん、こんにちは! 今日は Java ログについて説明します。
- これは何ですか、なぜですか。どのような場合に使用した方がよく、どのような場合に使用しない方がよいでしょうか?
- Java におけるロギングのさまざまな実装は何ですか?また、この多様性をどうすればよいでしょうか?
ロギングレベル。アペンダーとは何なのか、そしてそれを正しく設定する方法について説明しましょう。
- ノードのログ記録と、すべてが希望どおりに動作するようにノードを正しく構成する方法。
この資料は幅広い読者を対象としています。
logger.info(“log something”);
Java に慣れ始めたばかりの人にも、すでに取り組んでいるがLet's Go!でしか理解できなかった人にも、それは明らかです。
なぜログ記録が必要なのでしょうか?
ログ記録によって問題が解決される実際のケースを見てみましょう。これは私の仕事の一例です。他のサービスと統合するアプリケーション ポイントがあります。私はこれらのポイントのログを
「アリバイ」として使用します。統合が機能しない場合でも、問題の原因がどちら側にあるのかを簡単に特定できるようになります。データベースに保存される重要な情報を記録することもお勧めします。たとえば、管理者ユーザーを作成します。これはまさにログに記録しておくと良いことです。
Java ロギング ツール
Java でログインするためのよく知られたソリューションには次のものがあります。
- ログ4j
- 7 月 - java.util.logging
- JCL - ジャカルタ・コモンズのロギング
- ログバック
- SLF4J - Java 用の単純なロギング ファサード
それぞれを簡単に見てみましょう。資料の実践的な部分では、Slf4j - log4j の接続を基礎とします。今は奇妙に思えるかもしれませんが、心配しないでください。この記事が終わるまでにすべてが明らかになるでしょう。 |
System.err.println
もちろん、最初は
System.err.println (コンソールへのレコード出力) がありました。デバッグ中にログをすばやく取得するために今でも使用されています。もちろん、ここで設定について説明する必要はありませんので、覚えておいて先に進みましょう。
Log4j
これは、開発者のニーズから作成された、すでに本格的なソリューションでした。とても興味深いツールであることがわかりました。さまざまな状況により、このソリューションは JDK に組み込まれることはなく、コミュニティ全体を大きく動揺させました。
com.example.type
log4j には、パッケージ内でロギングをオンにし、サブパッケージ内でロギングをオフにするための構成オプションがありました
com.example.type.generic
。これにより、ログに記録する必要があるものと、記録する必要のないものを迅速に区別することが可能になりました。
ここで、log4j には 1.2.x と 2.x.x という 2 つのバージョンがあり、互いに互換性がないことに注意することが重要です。
log4j は、 appender、つまりログを記録し、レイアウト - ログのフォーマットを行うツールのような概念を追加しました。これにより、必要なものだけを必要な方法で記録できます。アペンダーについては後ほど詳しく説明します。
7 月 - java.util.logging
主な利点の 1 つは、JUL が JDK (Java 開発キット) に含まれているというソリューションです。残念ながら、開発中に基礎として採用されたのは人気のある log4j ではなく、開発に影響を与えた IBM のソリューションでした。実際、現時点では JUL はありますが、誰も使っていません。「まあまあ」から: JUL では、ログ レベルが Logback、Log4j、Slf4j のものとは異なるため、これらの間の理解が悪化します。ロガーの作成も多かれ少なかれ似ています。これを行うには、以下をインポートする必要があります。
java.util.logging.Logger log = java.util.logging.Logger.getLogger(LoggingJul.class.getName());
ログの送信元を知るために、クラス名が特別に渡されます。Java 8以降では、 を渡すことが可能になりました
Supplier<String>
。これにより、以前のように毎回ではなく、本当に必要なときにのみ文字列をカウントして作成することができます。Java 8 のリリースによってのみ開発者は重要な問題を解決し、その後 JUL が実際に使用できるようになりました。
Supplier<String> msgSupplier
つまり、次のような 引数を持つメソッドです。
public void info(Supplier<String> msgSupplier) {
log(Level.INFO, msgSupplier);
}
JCL - ジャカルタ・コモンズのロギング
長い間、ロギングにおける業界標準が存在せず、多くの人が独自のカスタム ロガーを作成していた時期があったため、他のものよりも使用される共通のラッパーである JCL をリリースすることにしました。なぜ?いくつかの依存関係がプロジェクトに追加されると、プロジェクトのロガーとは異なるロガーが使用される可能性があります。このため、それらは推移的にプロジェクトに追加され、すべてをまとめようとしたときに大きな問題が発生しました。残念ながら、ラッパーの機能は非常に貧弱で、追加機能はありませんでした。誰もが JCL を使用して作業を行うことができれば便利でしょう。しかし、実際にはそのようにはうまくいきませんでした。そのため、現時点では JCL を使用することは得策ではありません。
ログバック
オープンソースへの道はなんと険しいことでしょう... Logback は、log4j と同じ開発者によって、その後継を作成するために作成されました。考え方はlog4jと同じでした。違いはログバックにあります。
- パフォーマンスを向上させた;
- slf4j のネイティブ サポートを追加しました。
- フィルタリング オプションが拡張されました。
デフォルトでは、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>
SLF4J - Java 用の単純なロギング ファサード
2006 年頃、log4j の創設者の 1 人がプロジェクトを離れ、log4j、JUL、common-loggins、logback のラッパーである slf4j (Simple Logging Facade for Java) を作成しました。ご覧のとおり、ラッパーの上にラッパーを作成するところまで進捗が進んでいます。さらに、アプリケーションで使用される API と、追加される実装の 2 つの部分に分かれています。ロギングの種類ごとに個別の依存関係が必要になります。例えば、
slf4j-log4j12.jar
、
slf4j-jdk14.jar
。正しい実装を接続するだけで十分です。プロジェクト全体がそれを使用して動作します。Slf4j は、ログの文字列フォーマットなどのすべての新機能をサポートします。以前にもそんな問題がありました。次のようなログ エントリがあるとします。
log.debug("User " + user + " connected from " + request.getRemoteAddr());
文字列の連結によりオブジェクト内で
user
暗黙的な変換が行われる
user.toString()
ため、時間がかかり、システムの速度が低下します。アプリケーションをデバッグすれば、すべて問題ありません。このクラスのログ レベルが INFO 以上の場合、問題が発生します。つまり、このログは書き留めるべきではなく、文字列の連結も実行すべきではありません。理論的には、これはログ ライブラリ自体によって決定されるはずです。さらに、これが log4j の最初のバージョンの最大の問題であることが判明しました。彼らは通常の解決策を提供しませんでしたが、次のようにすることを提案しました。
if (log.isDebugEnabled()) {
log.debug("User " + user + " connected from " + request.getRemoteAddr());
}
つまり、ログ記録行を 1 行ではなく 3(!) と書くことを提案しました。ロギングではコードへの変更を最小限に抑える必要がありますが、3 行は明らかに一般的なアプローチと矛盾しています。slf4j には JDK および API との互換性の問題がなかったため、すぐに素晴らしいソリューションが現れました。
log.debug("User {} connected from {}", user, request.getRemoteAddr());
ここで、
{}
はメソッドに渡される引数の挿入を示します。つまり、最初のは
{}
に対応し
user
、2 番目は
{}
-に対応します
request.getRemoteAddr()
。このため、ログ レベルでログが許可されている場合にのみ、このメッセージを 1 つのメッセージに連結できます。その後、SJF4J の人気が急速に高まり、現在では最適なソリューションとなっています。したがって、バンドルの例を使用してロギングを検討します
slf4j-log4j12
。
ログに記録する必要があるもの
もちろん、すべてを記録すべきではありません。場合によっては、これは不必要であり、危険ですらあります。たとえば、誰かの個人データを誓約し、それが何らかの形で明るみに出た場合、特に西側向けのプロジェクトでは、大きな問題が発生するでしょう。
ただし、ログに記録することが必須のものもあります。
- アプリケーションの開始/終了。アプリケーションが実際に期待どおりに起動し、期待どおりに終了したことを知る必要があります。
- 秘密の質問。ここでは、パスワード推測の試行や重要なユーザーのログインなどを記録するとよいでしょう。
- 一部のアプリケーションの状態。たとえば、ビジネス プロセス内のある状態から別の状態への遷移です。
- 適切なレベルのログを含むデバッグ用の情報。
- いくつかの SQL スクリプト。これが必要になる実際のケースがあります。繰り返しますが、レベルを上手に調整することで、優れた結果を達成できます。
- 正常な動作を確認した場合、実行したスレッド(Thread)をログに記録できます。
よくあるロギングの間違い
多くのニュアンスがありますが、よくある間違いをいくつか紹介します。
- 過剰なログ記録。理論的には重要である可能性があるすべてのステップを記録すべきではありません。ルールがあります。ログによるパフォーマンスの負荷は 10% までです。そうしないと、パフォーマンス上の問題が発生します。
- すべてのデータを 1 つのファイルに記録します。これにより、特定のシステムにはファイル サイズの制限があることは言うまでもなく、ある時点で読み取り/書き込みが非常に困難になります。
- 間違ったログレベルを使用している。各ログレベルには明確な境界があり、尊重する必要があります。境界があいまいな場合は、どのレベルを使用するかについて合意できます。
ロギングレベル
|
|
|
×: 見える |
|
|
|
|
致命的 |
エラー |
警告 |
情報 |
デバッグ |
痕跡 |
全て |
オフ |
|
|
|
|
|
|
|
致命的 |
バツ |
|
|
|
|
|
|
エラー |
バツ |
バツ |
|
|
|
|
|
警告 |
バツ |
バツ |
バツ |
|
|
|
|
情報 |
バツ |
バツ |
バツ |
バツ |
|
|
|
デバッグ |
バツ |
バツ |
バツ |
バツ |
バツ |
|
|
痕跡 |
バツ |
バツ |
バツ |
バツ |
バツ |
バツ |
|
全て |
バツ |
バツ |
バツ |
バツ |
バツ |
バツ |
バツ |
ログレベルとは何ですか? 何らかの方法で丸太をランク付けするには、特定の指定と区別を与える必要がありました。この目的のために、ログレベルが導入されました。レベルはアプリケーションで設定します。エントリが指定されたレベルより下のレベルに属している場合、そのエントリはログに記録されません。たとえば、アプリケーションのデバッグに使用されるログがあります。通常の運用作業 (アプリケーションが本来の目的で使用されている場合) では、このようなログは必要ありません。したがって、ログのレベルはデバッグの場合よりも高くなります。log4j を例として使用してレベルを見てみましょう。JUL を除く他のソリューションは同じレベルを使用します。以下に降順に示します。
- OFF:ログは書き込まれず、すべて無視されます。
- FATAL: JVM メモリ不足エラーなど、その後アプリケーションが動作できなくなり停止するエラー。
- ERROR:解決する必要がある問題がある場合のエラー率。このエラーによってアプリケーション全体が停止するわけではありません。他のクエリは正しく動作する可能性があります。
- WARN:警告を含むログを示します。予期しないアクションが発生しましたが、システムは抵抗して要求を完了しました。
- INFO:アプリケーション内の重要なアクションを記録するログ。これらはエラーではなく、警告でもありません。これらはシステムの予期された動作です。
- DEBUG:アプリケーションのデバッグに必要なログ。システムが期待どおりに動作することを確認するため、またはシステムの動作を説明するには、「method1 が動作し始めました」。
- TRACE:デバッグ用の優先度が低く、ログレベルが最も低いログ。
- ALL:システムからのすべてのログが記録されるレベル。
アプリケーション内のどこかで INFO ログ レベルが有効になっている場合、INFO から FATAL までのすべてのレベルがログに記録されることがわかります。ログ レベルが FATAL の場合、このレベルのログのみが記録されます。
ログの記録と送信: Appender
例として log4j を使用してこのプロセスを検討します。log4j はログを記録/送信するための十分な機会を提供します。
- ファイルへの書き込み用 - ソリューションDailyRollingFileAppender ;
- アプリケーション コンソールにデータを受信する - ConsoleAppender ;
- データベースにログを書き込む - JDBCAppender ;
- TCP/IP 経由の送信を制御する - TelnetAppender ;
- ロギングがパフォーマンスに影響を与えないようにするには、AsyncAppender を使用します。
他にもいくつかの実装があります。完全なリストはここにあります。ちなみに、必要なアペンダが利用できない場合でも問題ありません。
log4j のみを受け入れるAppenderインターフェースを実装することで、独自のアペンダーを作成できます。
ロギングノード
デモンストレーションでは、slf4j インターフェイスと log4j からの実装を使用します。ロガーの作成は非常に簡単です。
MainDemo
ロギングが行われる という名前のクラスに次のコードを記述する必要があります。
org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(MainDemo.class);
これにより、ロガーが作成されます。ログ エントリを作成するには、エントリがどのレベルで作成されるかを示すさまざまな方法を使用できます。例えば:
logger.trace("Method 1 started with argument={}", argument);
logger.debug("Database updated with script = {}", script);
logger.info("Application has started on port = {}", port);
logger.warn("Log4j didn't find log4j.properties. Please, provide them");
logger.error("Connection refused to host = {}", host);
クラスを渡しているにもかかわらず、最終的に書き留められるのはパッケージを含むクラスの完全名です。これは、ロギングをノードに分割し、各ノードのロギング レベルとアペンダーを構成できるようにするために行われます。たとえば、クラスの名前は次のとおりです。
com.github.romankh3.logginglecture.MainDemo
- ロガーがその中に作成されました。このようにしてロギング ノードに分割できます。メイン ノードは null
RootLoggerです。これは、アプリケーション全体のすべてのログを受信するノードです。残りは以下のように表すことができます。
アペンダーは、特にログ ノードでの作業を構成します。ここで、例として
log4j.properties を使用して、それらを構成する方法を見ていきます。
Log4j.properties の段階的な構成
次に、すべてを段階的にセットアップして、何ができるかを確認します。
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
この行は、org.apache.log4j.ConsoleAppender 実装を使用する CONSOLE アペンダーを登録していることを示しています。このアペンダーはコンソールにデータを書き込みます。次に、ファイルに書き込む別のアペンダーを登録しましょう。
log4j.appender.FILE=org.apache.log4j.RollingFileAppender
アペンダーを引き続き構成する必要があることに注意することが重要です。アペンダーを登録したら、ノードでのロギングのレベルと、どのアペンダーが使用されるかを決定できます。
log4j.rootLogger=デバッグ、コンソール、ファイル
- log4j.rootLogger は、すべてのログを含むメイン ノードを構成することを意味します。
- 等号の後の最初の単語は、ログがどのレベル以上で記録されるかを示します (この場合、これは DEBUG です)。
- カンマの後に、使用されるすべてのアペンダーが示されます。
特定のログ ノードを構成するには、次のエントリを使用する必要があります。
log4j.logger.com.github.romankh3.logginglecture=TRACE, OWN, CONSOLE
ここで
log4j.logger.
、特定のノードを構成するために使用されます。この場合は、次
com.github.romankh3.logginglecture.
のようになります。 次に、CONSOLE アペンダーの設定について話しましょう。
# CONSOLE appender customisation
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.threshold=DEBUG
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=[%-5p] : %c:%L : %m%n
ここでは、アペンダーが処理するレベルを設定できることがわかります。実際の状況: info レベルのメッセージがロギング ノードによって受信され、それに割り当てられているアペンダーに渡されましたが、warn 以上のレベルのアペンダーはこのログを受け入れましたが、それに対して何も行いませんでした。次に、メッセージにどのテンプレートを含めるかを決定する必要があります。この例では PatternLayout を使用していますが、世の中には多くの解決策があります。この記事ではそれらは公開されません。FILE アペンダの設定例:
# File appender customisation
log4j.appender.FILE=org.apache.log4j.RollingFileAppender
log4j.appender.FILE.File=./target/logging/logging.log
log4j.appender.FILE.MaxFileSize=1MB
log4j.appender.FILE.threshold=DEBUG
log4j.appender.FILE.MaxBackupIndex=2
log4j.appender.FILE.layout=org.apache.log4j.PatternLayout
log4j.appender.FILE.layout.ConversionPattern=[ %-5p] - %c:%L - %m%n
ここで、ログを書き込むファイルを設定できます。次のようになります。
log4j.appender.FILE.File=./target/logging/logging.log
録音はファイルに保存されます
logging.log
。ファイル サイズの問題を回避するために、最大値 (この場合は 1MB) を設定できます。MaxBackupIndex - そのようなファイルがいくつ存在するかを示します。この数を超えて作成された場合は、最初のファイルが削除されます。ロギングが構成されている実際の例を確認するには、 GitHub の
オープン リポジトリにアクセスしてください。
結果を統合しましょう
説明されているすべてのことを自分で実行してみてください。
- 上記の例と同様の独自のプロジェクトを作成します。
- Maven の使用に関する知識がある場合はそれを使用しますが、そうでない場合は、ライブラリの接続方法を説明した記事へのリンクを次に示します。
要約しましょう
- Java にはどのようなソリューションがあるかについて話し合いました。
- 既知のロギング ライブラリのほぼすべては、1 人の人の管理下で作成されました :D
- 何をログに記録する必要があるのか、何がそうでないのかを学びました。
- ログレベルを把握しました。
- ロギングノードについて説明しました。
- アペンダーとは何か、またその目的について説明しました。
- log4j.proterties ファイルを段階的に構成しました。
追加資料
- JavaRush: ロギング。stectrace のボールをほどく
- JavaRush:ロガーの講義
- Habr: Java ログ記録。こんにちは世界
- Habr: Java ロギング: 悪夢の物語
- Youtube: ゴロヴァッハのコース。ロギング。第 1 部、第 2 部、第 3 部、第 4 部
- Log4j:アペンダー
- Log4j:レイアウト
私の他の記事も参照してください。
GO TO FULL VERSION