Javaでのログ/クイックスタート

DataArtでの仕事の過程で、とりわけメンタリングに携わっています。 特に、これには、研修生が行った研修の割り当ての確認が含まれます。 最近、ロガーの「奇妙な」使用のタスクに傾向があります。 同僚と私は、割り当てのテキストに、Javaロギングのベストプラクティスを説明する記事へのリンクを含めることにしましたが、Javaログへの書き込み方法については、このように簡単かつ追加の詳細なしで説明することがわかりました。あります。



この記事には啓示は含まれていません。多くのJavaロギングフレームワークの複雑さについては説明していません。 ここでは、同僚に驚きを与えないようにログに書き込む方法を説明します。書き込みの主な目的は、それを研修生の必須の読み取りリストに含めることです。 それでも興味があれば、読み進めてください。





いくつかの説明。





例1




よし




public class SomeClass { private static Logger log = Logger.getLogger(SomeClass.class.getName()); public void someMethod() { log.info("Some message"); } ...
      
      







  1. ロガーは、クラスがロードされたときに初期化される静的クラスフィールドです。シンプルで短い名前を持ち、すべてのクラスでロガー変数が同じ名前で呼び出されることが重要です(これは、一般的な規則によって決定され、プログラム内の同じことは同じ方法で行われる必要があります)。
  2. クラスの名前をロガーの名前として使用しますが、実際にはこれが唯一の方法ではありません。何らかの種類のログ階層(たとえば、データ交換を処理するサブシステムのトランスポート層/アプリ層)を整理することができますが、実際には、このような階層に厳密に従うことは非常に難しく、クラス名と一致するロガー名のオプションは非常に優れており、プロジェクトの99%で使用されています
  3. ここでは、より一般的な.logメソッドではなく、短い.infoメソッドを使用してログに書き込みます。
  4. ロガー名は「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()); }
      
      







  1. 例外を予約する必要がある場合は、このために.log(レベル、メッセージ、例外)メソッドを使用します
  2. ログシステムを特に設定していない場合、情報などのレベルが低い(たとえば、罰金)メッセージは表示されません。 しかし、少なくともシステムの重要な部分のためにそれらを書くことは価値があります。 問題が発生した場合、より詳細なレベルのログを構成し、多くの興味深いことがわかります。
  3. ログメッセージが多すぎると、レベルが低すぎるためにログファイルに物理的に書き込まれていなくても、プログラムの速度が大幅に低下する可能性があります。 特に、メッセージ自体を準備するために多くのリソースを費やす必要がある場合。 これには.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









ここで何をしましたか





メッセージログを別の場所に表示する




コンソールの悪い結論は何ですか? コンソールは基本的に古き良きstderrです。 これはどういう意味ですか:





これらの問題を解決するために、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つの方法があります。

  1. コマンドラインからアプリケーションを実行する
  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()); } .....
      
      













舞台裏に残っているもの


実際には、すべてのJavaアプリケーションの少なくとも半分がWebアプリケーションです。 それらにログインする方法自体は、上記とまったく違いはありません。 おそらく、異なるアプリケーションサーバーが次のような異なるロギングライブラリを使用できるという例外はあります。





したがって、構成名とメソッド名はわずかに異なります。 しかし、原理自体はほとんど変わりません。 特定の機能は、通常、アプリケーションサーバー自体のドキュメントで詳しく説明されています。




All Articles