この記事には啓示は含まれていません。多くのJavaロギングフレームワークの複雑さについては説明していません。 ここでは、同僚に驚きを与えないようにログに書き込む方法を説明します。書き込みの主な目的は、それを研修生の必須の読み取りリストに含めることです。 それでも興味があれば、読み進めてください。
いくつかの説明。
- すべてのサンプルコードはjava.util.loggingフレームワークを使用します。 「どのロギングフレームワークが最もコーシャですか」という質問は、舞台裏に残しておきます。 java.util.loggingに到達する最も簡単な方法は、すでにJREに付属しているということです。実際、この記事で説明した最小限の外観変更は、ほとんどのロギングシステムに当てはまります。
- 一般に、この記事に記載されているレシピだけが真のものではなく、議論できる瞬間がありますが、一般的に、これらのレシピは多くの開発者によって多くのプロジェクトで長年使用されており、深刻な異議。
- この記事では、次のような「高度な」トピックについては説明していません。
- 個々のロガーのレベル構成
- ログのフォーマット
- 非同期ロギング
- Log4Jでのカスタムログレベルの作成
- コンテキストロギング
- その他
- 私はロシア語で「log」という単語を、基本的には「g」という1文字のログとして記録します。このタイプの翻訳はより一般的です
- ヒントは、どのレベルのロギングを使用して、おそらく舞台裏にも残します。 それはすべて、アプリケーション、動作条件、顧客との関係などに依存します。 微妙なもの。
例1
よし
public class SomeClass { private static Logger log = Logger.getLogger(SomeClass.class.getName()); public void someMethod() { log.info("Some message"); } ...
- ロガーは、クラスがロードされたときに初期化される静的クラスフィールドです。シンプルで短い名前を持ち、すべてのクラスでロガー変数が同じ名前で呼び出されることが重要です(これは、一般的な規則によって決定され、プログラム内の同じことは同じ方法で行われる必要があります)。
- クラスの名前をロガーの名前として使用しますが、実際にはこれが唯一の方法ではありません。何らかの種類のログ階層(たとえば、データ交換を処理するサブシステムのトランスポート層/アプリ層)を整理することができますが、実際には、このような階層に厳密に従うことは非常に難しく、クラス名と一致するロガー名のオプションは非常に優れており、プロジェクトの99%で使用されています
- ここでは、より一般的な.logメソッドではなく、短い.infoメソッドを使用してログに書き込みます。
- ロガー名は「com.dataart.demo.java.logging.SomeClass」としてではなく、SomeClass.class.getName()として取得されます。両方のメソッドは基本的に同じですが、最初はクラス名/パッケージをリファクタリングするときの驚きから保護します
悪い
public class SomeClass { public void someMethod() { Logger.getLogger("com.dataart.demo.java.logging.SomeClass").log(Level.INFO,"Some message"); } ...
本質的には同じことですが、より多くの文字があり、読むのはそれほど簡単ではありません。
例間の注意
おそらく、例のすべてのメッセージが英語であることに気づいたでしょう。 これは偶然ではありません。 実際、あなたのコードを使って仕事をするすべての人がロシア語を話すとしても、たとえばsshを介してリモートコンピューターのメッセージログを確認する必要があり、多くの場合、このようなメッセージが表示されます。 ???、???? ????? !!!! " (私は確かにsshを介してロシア文字をドラッグできることを知っていますが、何らかの理由で、すべてが常に適切にセットアップされるわけではありません)。
または、cmdのローカルマシンでも、これが何であるかを確認できます。
INFO: ╨╨░╨║╨╛╨╡-╤╨╛ ╤╨╛╨╛╨▒╤╨╡╨╜╨╕╨╡ ╨▓ ╨╗╨╛╨│
もちろん、これと戦うこともできます。 しかし、携帯電話の反対側の顧客に、クラックの代わりにロシア文字を表示する方法を説明するのは必ずしも簡単ではありません。
ヒント:メッセージログは英語で、極端な場合はラテン文字で書きます。
例2
よし
try { throw new Exception("Some exception"); } catch (Exception ex) { log.log(Level.SEVERE, "Exception: ", ex); } // log.fine("some minor, debug message"); /* ( - ..). */ if (log.isLoggable(Level.FINE)) { log.fine("Some CPU consuming message: " + prepareCPUConsumingLogMessage()); }
- 例外を予約する必要がある場合は、このために.log(レベル、メッセージ、例外)メソッドを使用します
- ログシステムを特に設定していない場合、情報などのレベルが低い(たとえば、罰金)メッセージは表示されません。 しかし、少なくともシステムの重要な部分のためにそれらを書くことは価値があります。 問題が発生した場合、より詳細なレベルのログを構成し、多くの興味深いことがわかります。
- ログメッセージが多すぎると、レベルが低すぎるためにログファイルに物理的に書き込まれていなくても、プログラムの速度が大幅に低下する可能性があります。 特に、メッセージ自体を準備するために多くのリソースを費やす必要がある場合。 これには.isLoggable(レベル)メソッドがあります-ロガーの現在の構成がこのメッセージをスキップするかどうかを確認できます
悪い
try { throw new Exception("Some exception"); } catch (Exception ex) { log.severe("Exception: " + ex.toString() ); } log.fine("Some CPU consuming message: " + itTakes500MillisecondsToPrepageThisMessage());
ex.toString()のみをログに記録した場合、後で例外が最初に機能していた行を特定できなくなります。
例3
ロガーを構成する必要があります。 デフォルトの設定があり、INFOレベル以上のすべてのメッセージがコンソールに表示されます。 IDEからの開発には十分ですが、実際のアプリケーションでは通常、修正するのが良いでしょう。
どんなオプションがありますか
デフォルト:INFOレベルのLogging.propertiesファイル、コンソール出力
#Console handler
handlers= java.util.logging.ConsoleHandler
.level=INFO
ロギングをより詳細にし、FINEレベルのメッセージも表示します
#Console handler
handlers= java.util.logging.ConsoleHandler
.level=FINE
java.util.logging.ConsoleHandler.level = FINE
ここで何をしましたか
- メッセージがシステムログにクロールされるように、ルートロガーのFINEレベルを設定します。
- また、ログシステムをクロールするすべてのものは、FINEレベル以上からコンソールに表示する必要があると述べました。
メッセージログを別の場所に表示する
コンソールの悪い結論は何ですか? コンソールは基本的に古き良きstderrです。 これはどういう意味ですか:
- javawを使用してアプリケーションを起動した場合、何も表示されません。
- 出力がコンソールに送られ、必要なメッセージが4時間前にフラッシュされた場合、コンソールバッファーはすでにそれを食べていたため、情報は失われました。
- コンソール出力がJavaファイルcom.yourcompanyname.EntryClass 2 >> application_log.txtに送られ 、アプリケーションが数週間停止せずに動作する場合、ファイルは非常に大きくなり、ディスク全体を占有する危険があります。
これらの問題を解決するために、java.util.logging.FileHandlerが発明されました。これは、メッセージログをファイルに出力するハンドラです。 同時に、彼はファイルをローテーションできます。 最大サイズに達した後、現在のログメッセージをファイルに追加し、プレフィックスが増分された新しいファイルを開きます。 そして円で。 例えば
handlers= java.util.logging.FileHandler java.util.logging.FileHandler.pattern = application_log.txt java.util.logging.FileHandler.limit = 50 java.util.logging.FileHandler.count = 7 java.util.logging.FileHandler.formatter = java.util.logging.SimpleFormatter
そのようなファイルを作成します(最後の列-バイト単位のサイズ)
application_log.txt.0│0 application_log.txt.1│79 application_log.txt.2│79 application_log.txt.3│676 application_log.txt.4│87 application_log.txt.5│114
最大サイズを50バイトに指定しましたが、実際には少なくとも1メガバイトを示す必要があります(たとえば、1,000,000は1メガバイトより少し小さいことを知っていますが、問題の本質が変わらない場合は、メモリから1048576を書き込みたいと思います)
java.util.logging.FileHandler.limit = 1000000
この例では、サイズは基本的に最後のメッセージログ全体に切り上げられているため、ご覧のとおり、ファイルは50バイトを超えています。 つまり 1バイトのサイズを指定し、サイズが1000バイトのログメッセージを書き込むと、ファイルサイズは1000バイトになり、その後メッセージログファイルが閉じて次のファイルが開きます。
実際の設定をコピーして貼り付けるだけで、ほとんどのサービス、コンソール、デスクトップアプリケーションに十分です。
ハンドラー= java.util.logging.FileHandler java.util.logging.FileHandler.pattern = application_log.txt java.util.logging.FileHandler.limit = 1000000 java.util.logging.FileHandler.count = 5 java.util.logging.FileHandler.formatter = java.util.logging.SimpleFormatter
最後の魔法
さて、最後に伝えることは、プロパティファイルからロガーを実際に構成する方法です。 2つの方法があります。
- コマンドラインからアプリケーションを実行する
- アプリケーションコードの最初の行
最初のものは宣言的であり、アプリケーションのコードが動作を開始する直前に機能するため、少し正確です。
このように
java Djava.util.logging.config.file=logging.properties com.dataart.application.ClassName
しかし、残念ながら、発射ラインを変更することは常に可能であるとは限らないか、常に便利とは限りません。 2番目の方法もうまく機能します。
public static void main(String[] args) { try { LogManager.getLogManager().readConfiguration( MainApplicationEntryClass.class.getResourceAsStream("/logging.properties")); } catch (IOException e) { System.err.println("Could not setup logger configuration: " + e.toString()); } .....
- ここで、MainApplicationEntryClassはクラスです-アプリケーションへのエントリポイントは、明らかにクラス名が異なります
- logging.propertiesファイル自体は、原則として、このような場合にクラス階層のルートに配置され、次のようになります

舞台裏に残っているもの
実際には、すべてのJavaアプリケーションの少なくとも半分がWebアプリケーションです。 それらにログインする方法自体は、上記とまったく違いはありません。 おそらく、異なるアプリケーションサーバーが次のような異なるロギングライブラリを使用できるという例外はあります。
- Log4j
- JULIロガー(厳密には、これは完全に独立したフレームワークではなく、java.util.loggingの一種のアドオンです)
- SLF4J
- コモンズロギング
したがって、構成名とメソッド名はわずかに異なります。 しかし、原理自体はほとんど変わりません。 特定の機能は、通常、アプリケーションサーバー自体のドキュメントで詳しく説明されています。