時々、ログコードを見ると、正しくやっているのだろうかと思います。それに対する決定的な答えはないかもしれませんが、私には以下の懸念があります:
ライブラリクラス
いくつかのINFO
メッセージを記録するライブラリクラスがいくつかあります。致命的なエラーは例外として報告されます。現在、クラス名をロギング名として使用する静的ロガーインスタンスがクラスにあります。 (Log4jの場合:Logger.getLogger(MyClass.class)
)
これは正しい方法ですか?このライブラリクラスのユーザーは、私の実装からのメッセージを望んでいないか、アプリケーション固有のログにリダイレクトしたいかもしれません。ユーザーが「外の世界」からロガーを設定できるようにする必要がありますか?そのような場合はどのように処理しますか?
一般ログ
一部のアプリケーションでは、クラスが、クラスの名前で識別されない特定のログにログメッセージを書き込みたい場合があります。 (つまり:HTTP Request log
)そのようなことをする最良の方法は何ですか?検索サービスが思い浮かびます...
あなたの慣習はかなり標準的で、非常に素晴らしいです(私見)。
注目すべき1つのことは、過度のアンデッドデバッグコールによるメモリの断片化です。したがって、Log4J(および他のほとんどのJavaロギングフレームワーク)では、次のような結果になります。
if (log.isDebugEnabled()) {
log.debug("...");
}
そのログメッセージ(おそらくは使用していない)の構築は、特に数千または数百万回行われた場合、高価になる可能性があるためです。
INFOレベルのロギングは、「チャット」ではないはずです(そして、あなたの言うことから、そうではないように聞こえます)。 INFOメッセージは、アプリケーションの起動や停止のように、一般的に意味があり重要です。問題が発生した場合に知りたいことがあります。デバッグ/ファインレベルのロギングは、診断しようとしている問題が実際にある場合により多く使用されます。デバッグ/ファインロギングは通常、必要な場合にのみオンになります。通常、情報は常にオンになっています。
誰かがあなたのクラスから特定のINFOメッセージを望んでいないなら、彼らはもちろんそれらを取得しないようにlog4j設定を自由に変更できます。 Log4jは、この部門では非常に単純です(Java 1.4ロギング)とは対照的です)。
HTTPに関しては、通常、Javaロギングの問題となることはありません。なぜなら、通常、単一のクラスがあなたが興味を持っていることを担当しているので、それを置くだけです。 (私の経験では珍しい)一見無関係なクラスに共通のログメッセージが必要な場合は、簡単にgrepできるトークンを入れてください。
以下は、すべてのプロジェクトで良好なパフォーマンスを確保するために従うガイドラインのセットです。インターネットのさまざまなソースからの入力に基づいて、この一連のガイドラインを作成しました。
今日のように、Log4j 2がJavaでのログ記録のための最高のオプションであると信じています。
ベンチマークが利用可能です ここ 。最高のパフォーマンスを得るために私が従うプラクティスは次のとおりです。
_12:01:00,127 INFO FILE_NAME=file1.txt - Processing starts 12:01:00,127 DEBUG FILE_NAME=file1.txt, CUSTOMER_ID=756 12:01:00,129 INFO FILE_NAME=file1.txt - Processing ends
_
_private static final Marker sqlMarker = MarkerManager.getMarker("SQL"); private void method1() { logger.debug(sqlMarker, "SELECT * FROM EMPLOYEE"); }
_
_int i=5, j=10; logger.info("Sample output {}, {}", ()->i, ()->j);
_
文字列連結を使用しないでください。上記のようにパラメーター化されたメッセージを使用します
ロギング構成の動的再ロードを使用して、アプリケーションがアプリケーションを再起動することなくロギング構成の変更を自動的に再ロードするようにします
printStackTrace()
またはSystem.out.println()
を使用しないでください
アプリケーションは、終了する前にロガーをシャットダウンする必要があります。
_LogManager.shutdown();
_
_<?xml version="1.0" encoding="UTF-8"?> <Configuration monitorinterval="300" status="info" strict="true"> <Properties> <Property name="filePath">${env:LOG_ROOT}/SAMPLE</Property> <Property name="filename">${env:LOG_ROOT}/SAMPLE/sample </Property> <property name="logSize">10 MB</property> </Properties> <Appenders> <RollingFile name="RollingFileRegular" fileName="${filename}.log" filePattern="${filePath}/sample-%d{yyyy-dd-MM}-%i.log"> <Filters> <MarkerFilter marker="SQL" onMatch="DENY" onMismatch="NEUTRAL" /> </Filters> <PatternLayout> <Pattern>%d{HH:mm:ss,SSS} %m%n </Pattern> </PatternLayout> <Policies> <TimeBasedTriggeringPolicy interval="1" modulate="true" /> <SizeBasedTriggeringPolicy size="${logSize}" /> </Policies> </RollingFile> <RollingFile name="RollingFileError" fileName="${filename}_error.log" filePattern="${filePath}/sample_error-%d{yyyy-dd-MM}-%i.log" immediateFlush="true"> <PatternLayout> <Pattern>%d{HH:mm:ss,SSS} %p %c{1.}[%L] [%t] %m%n </Pattern> </PatternLayout> <Policies> <TimeBasedTriggeringPolicy interval="1" modulate="true" /> <SizeBasedTriggeringPolicy size="${logSize}" /> </Policies> </RollingFile> </Appenders> <Loggers> <AsyncLogger name="com" level="trace"> <AppenderRef ref="RollingFileRegular"/> </AsyncLogger> <Root includeLocation="true" level="trace"> <AppenderRef ref="RollingFileError" level="error" /> </Root> </Loggers> </Configuration>
_
_<dependency> <groupId>org.Apache.logging.log4j</groupId> <artifactId>log4j-api</artifactId> <version>2.8.1</version> </dependency> <dependency> <groupId>org.Apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> <version>2.8.1</version> </dependency> <dependency> <groupId>com.lmax</groupId> <artifactId>disruptor</artifactId> <version>3.3.6</version> </dependency> <!-- (Optional)To be used when working with the applications using Log4j 1.x --> <dependency> <groupId>org.Apache.logging.log4j</groupId> <artifactId>log4j-1.2-api</artifactId> <version>2.8.1</version> </dependency>
_
@ cletus 'answer で、彼は
if (log.isDebugEnabled()) {
log.debug("val is " + value);
}
SL4J を使用することで克服できます。フォーマットのヘルプを提供します
log.debug("val is {}", value);
メッセージは、レベルがデバッグの場合にのみ作成されます。
そのため、今日では、パフォーマンスと安定性の理由から、SL4JとそのコンパニオンロガーであるLogbackを使用するのは 推奨 です。
ロガーのインスタンス化に関しては、Eclipse Javaロガーをセットアップするためのテンプレートを使用していくつかの成功を収めました。
private static Logger log = Logger.getLogger(${enclosing_type}.class);
これにより、JVMがスタックトレースをいじる問題を回避し、最初にスタックトレースを作成することによるオーバーヘッドを(おそらく、おそらく)削減します。
このようなテンプレートを使用することの素晴らしい点は、ロガーのために一貫した標準を設定したい場合、チームと共有できることです。
IntelliJは、囲んでいる型の名前を表すテンプレート変数の同じ概念をサポートしているようです。 NetBeansで簡単に行う方法がわかりません。
記述している種類のlog4j構成の推奨オプションは、log4j構成ファイルを使用することです。これにより、実装のユーザーは、自分の実装により適したもので構成を後でオーバーライドできるため、要求したとおりに実行できます。非常に徹底的な入門書については、 here を参照してください。
私はおそらくどこかからこれを盗んだが、それはいいです。
コピーするときにロガーを混同するリスクを軽減し、リファクタリングを貼り付けます。また、入力する必要が少なくなります。
コード内:
private final static Logger logger = LoggerFactory.make();
...およびLoggerFactory:
public static Logger make() {
Throwable t = new Throwable();
StackTraceElement directCaller = t.getStackTrace()[1];
return Logger.getLogger(directCaller.getClassName());
}
(スタックダンプは初期化中に行われます。スタックトレースはおそらく JVMによって最適化されませんが、実際には保証はありません)
アプリケーションのログレベルを確認していますが、現在パターンを検出しています:
private static final Logger logger = Logger.getLogger(Things.class)
public void bla() {
logger.debug("Starting " + ...)
// Do stuff
...
logger.debug("Situational")
// Algorithms
for(Thing t : things) {
logger.trace(...)
}
// Breaking happy things
if(things.isEmpty){
logger.warn("Things shouldn't be empty!")
}
// Catching things
try {
...
} catch(Exception e) {
logger.error("Something bad happened")
}
logger.info("Completed "+...)
}
Log4j2-fileは、ソケットアペンダーとフェイルオーバーファイルアペンダーを定義します。コンソールアペンダー。状況によって必要な場合は、log4j2マーカーを使用することがあります。
余分な視点が役立つかもしれないと思った。
さらに、Java(SLF4J)( http://www.slf4j.org/ )のSimple Logging Facadeを意味することが重要だと思います。大きなプロジェクトの多様化した部分で異なるロギングフレームワークを使用する問題、SLF4Jは、これらの部分を正常に管理するための問題を解決するための事実上の標準ではありませんか?
2番目の概念:一部の旧式のタスクは Aspect-Oriented-Programming で置き換えることができるようです、Spring frmwrkには独自の 実装here StackOverflowで here Springブログで。