現在のJavaプロジェクトがどんどん大きくなっているので、デバッグ出力をコードのいくつかのポイントに挿入する必要性も同様に高まっています。
この機能を適切に有効または無効にするには、テストセッションの開始または終了に応じて、通常private static final boolean DEBUG = false
私のテストが検査しているクラスの最初で、(たとえば)このように簡単に使用します。
public MyClass {
private static final boolean DEBUG = false;
... some code ...
public void myMethod(String s) {
if (DEBUG) {
System.out.println(s);
}
}
}
など。
しかし、もちろんそれはうまくいくので、私を喜ばせるわけではありませんが、2つだけを見つめていなければ、DEBUGをtrueに設定するクラスが多すぎる可能性があります。
逆に、出力されるテキストの量が膨大になる可能性があるので、(私は-私が思うに-他の多くの人のように)アプリケーション全体をデバッグモードにしたくありません。
それで、そのような状況をアーキテクチャ的に処理する正しい方法はありますか、または最も正しい方法はDEBUGクラスメンバーを使用することですか?
ロギングフレームワーク、おそらくロギングファサードフレームワークを見たいと思います。
複数のロギングフレームワークが存在し、多くの場合、機能が重複しているため、時間の経過とともに、多くのものが共通のAPIに依存するように進化したり、ファサードフレームワークを介して使用を抽象化したり、それらを所定の場所に入れ替えたりできるようになりました必要に応じて。
これらのフレームワークのほとんどは、次のような形式で記述できます(ここでは_slf4j-api
_および_logback-core
_を使用しています)。
_package chapters.introduction;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
// copied from: http://www.slf4j.org/manual.html
public class HelloWorld {
public static void main(String[] args) {
final Logger logger = LoggerFactory.getLogger(HelloWorld.class);
logger.debug("Hello world, I'm a DEBUG level message");
logger.info("Hello world, I'm an INFO level message");
logger.warn("Hello world, I'm a WARNING level message");
logger.error("Hello world, I'm an ERROR level message");
}
}
_
現在のクラスを使用して専用ロガーを作成することに注意してください。これにより、SLF4J/LogBackが出力をフォーマットし、ロギングメッセージの送信元を示すことができます。
SLF4Jマニュアル に記載されているように、クラスの一般的な使用パターンは通常次のとおりです。
_import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class MyClass {
final Logger logger = LoggerFactory.getLogger(MyCLASS.class);
public void doSomething() {
// some code here
logger.debug("this is useful");
if (isSomeConditionTrue()) {
logger.info("I entered by conditional block!");
}
}
}
_
しかし実際には、ロガーを次の形式で宣言するのがより一般的です。
_private static final Logger LOGGER = LoggerFactory.getLogger(MyClass.class);
_
これにより、ロガーを静的メソッド内からも使用でき、クラスのすべてのインスタンス間で共有されます。これはあなたの好みの形である可能性が高いです。ただし、コメントでBrendan Longが述べたように、必ず 意味を理解する を決定し、それに応じて決定する必要があります(これは、これらのイディオムに従うすべてのロギングフレームワークに適用されます)。
ロガーをインスタンス化する方法は他にもあります。たとえば、文字列パラメーターを使用して名前付きロガーを作成します。
_Logger logger = LoggerFactory.getLogger("MyModuleName");
_
デバッグレベルはフレームワークごとに異なりますが、一般的なものは次のとおりです(重要度の順に、良性からバットバットまで、そしておそらく非常に一般的なものから非常にまれなものまで)。
TRACE
非常に詳細な情報。ログにのみ書き込む必要があります。チェックポイントでのプログラムのフローを追跡するためにのみ使用されます。
DEBUG
詳細情報。ログのみに書き込む必要があります。
INFO
注目すべきランタイムイベント。コンソールにすぐに表示されるはずなので、控えめに使用してください。
WARNING
実行時の異常と回復可能なエラー
ERROR
その他の実行時エラーまたは予期しない状態。
FATAL
重大なエラーにより、途中で終了します。
ここで、いくつかのデバッグステートメントを記述しようとしているコードセクションがあるとします。ロギング自体の影響と、ロギングメソッドに渡すパラメータの生成の両方が原因で、これはパフォーマンスにすぐに影響する可能性があります。
この種の問題を回避するために、次のような形式で書きたいことがよくあります。
_if (LOGGER.isDebugEnabled()) {
// lots of debug logging here, or even code that
// is only used in a debugging context.
LOGGER.debug(" result: " + heavyComputation());
}
_
メッセージが出力されない場合でも、デバッグステートメントのブロックの前にこのガードを使用していなかった場合(たとえば、ロガーが現在INFO
レベルを超えるもののみを出力するように構成されている場合)、 heavyComputation()
メソッドは引き続き実行されます。
構成はロギングフレームワークに大きく依存しますが、これらはほとんど同じテクニックを提供します。
また、ほとんど同じ機能を提供します。
以下は、_logback.xml
_ファイルを使用した宣言型構成の一般的な例です。
_<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<!-- encoders are assigned the type
ch.qos.logback.classic.encoder.PatternLayoutEncoder by default -->
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<root level="debug">
<appender-ref ref="STDOUT" />
</root>
</configuration>
_
前述のように、これはフレームワークに依存し、他の代替手段がある可能性があります(たとえば、LogBackではGroovyスクリプトを使用することもできます)。 XML構成形式も、実装によって異なる場合があります。
その他の設定例については、(特に)以下を参照してください。
Log4J は現在、メジャーな更新が行われており、バージョン 1.x から 2.x に移行しています。もっと歴史的な面白さや混乱のために両方を見たいと思うかもしれません、そしてあなたが Log4J を選択した場合、おそらく2.xバージョンで行くことを好むでしょう。
Mike Partridgeがコメントで述べたように、LogBackが元のLog4Jチームメンバーによって作成されたことは注目に値します。これは、Javaロギングフレームワークの欠点に対処するために作成されました。また、次期メジャーLog4J 2.xバージョン自体が、LogBackから取得したいくつかの機能を統合するようになりました。
結論として、できる限り分離して、少数で遊んで、何が最適かを確認します。最後にそれは単なるロギングフレームワークです。非常に具体的な理由がある場合を除いて、使いやすさや個人的な好みは別として、これらはどれでも大丈夫ですので、それを忘れる必要はありません。それらのほとんどは、ニーズに合わせて拡張することもできます。
それでも、今日組み合わせを選択する必要がある場合は、LogBack + SLF4Jを使用します。しかし、数年後に私に尋ねた場合、Apache Commons Loggingを備えたLog4Jをお勧めします。したがって、依存関係に注意を払い、それらとともに進化してください。
ロギングフレームワークを使用する
ほとんどの場合、静的なファクトリメソッドがあります。
private static final Logger logger = Logger.create("classname");
次に、さまざまなレベルでロギングコードを出力できます。
logger.warning("error message");
logger.info("informational message");
logger.trace("detailed message");
次に、各クラスのどのメッセージをログ出力(ファイルまたはstderr)に書き込むかを定義できる単一のファイルがあります。
これは、log4jや新しいslf4jなどのロギングフレームワークがまさに対象とするものです。ロギングを非常に詳細に制御し、アプリケーションの実行中でもログを構成できます。
ロギングフレームワークは間違いなく進むべき道です。ただし、優れたテストスイートも必要です。多くの場合、適切なテストカバレッジにより、デバッグ出力をまとめて行う必要がなくなります。