3

Javaでデバッグメッセージをログに記録するさまざまな方法について少し読んだことがあります.Cの背景から来て、私の懸念は次のとおりです。

これらのライブラリは、ロギングが無効になっている場合 (実稼働環境など) に最小限のオーバーヘッドを要求しますが、それらのlog()関数への引数は引き続き評価されるため、現実のシナリオでのオーバーヘッドは実際にはまったく無視できないという懸念があります。

たとえば、ログ関数自体が何もしない場合でも、 alog(myobject.toString(), "info message")には を評価するオーバーヘッドがまだありますmyobject.toString()。これはかなり大きくなる可能性があります。

誰もこの問題の解決策を持っていますか?

PS: C のバックグラウンドについて言及した理由を知りたい人のために: C では、プリプロセッサ マクロとコンパイル時の命令を使用できます。これにより、コンパイル時のデバッグに関連するすべてのコードが完全に削除されます (マクロのパラメーターはまったく表示されません)。

編集: 回答の最初のバッチを読んだ後、Java には明らかにそのトリックを実行するものがないようです (CPU のすべてのビットが重要なモバイル環境で大きなループで数値の余弦をログに記録することを考えてください)。そのため、IDE ベースのソリューションを使用することもあると付け加えておきます。私の最後の手段は、「すべてを検索/置換」マクロのようなものを構築することです。私は最初、アスペクト指向のフレームワークから得た何かが役立つのではないかと考えました...誰か?

4

5 に答える 5

9

log4j FAQはこれにうまく対処していると思います:

いくつかのロガー l について、書き込み、

l.debug("Entry number: " + i + " is " + String.valueOf(entry[i]));

整数 i と entry[i] の両方を文字列に変換し、中間文字列を連結するメッセージ パラメータを作成するコストが発生します。これは、メッセージがログに記録されるかどうかに関係なく。

速度が心配な場合は、書いてください

 if(l.isDebugEnabled()) {
     l.debug("Entry number: " + i + " is " + String.valueOf(entry[i]));
 }

このようにして、ロガー l のデバッグが無効になっている場合、パラメーター構築のコストが発生しません。一方、ロガーのデバッグが有効になっている場合は、ロガーが有効かどうかを 2 回 (debugEnabled で 1 回、デバッグで 1 回) 評価するコストが発生します。ロガーの評価にかかる時間は、実際にステートメントをログに記録するのにかかる時間の 1% 未満であるため、これは取るに足らないオーバーヘッドです。

ガード句を使用することは、ここで文字列の構築を回避するための一般的なアプローチです。

slf4jなどの他の一般的なフレームワークは、フォーマットされた文字列/パラメーター化されたメッセージを使用するアプローチを採用しているため、必要でない限りメッセージは評価されません。

于 2011-04-26T16:46:22.717 に答える
4

最新のロギング フレームワークには変数置換があります。ロギングは次のようになります。

log.debug("The value of my first object is %s and of my second object is %s", firstObject, secondObject).

指定されたオブジェクトの toString() は、ロギングがデバッグに設定されている場合にのみ実行されます。それ以外の場合は、パラメーターを無視して戻ります。

于 2011-04-26T16:44:47.870 に答える
3

答えは非常に簡単です。ログ呼び出し自体で高価なメソッドを呼び出さないでください。さらに、回避できない場合は、ロギング呼び出しの周りにガードを使用してください。

 if(logger.isDebugEnabled()) {
    logger.debug("this is an "+expensive()+" log call.");
 }

また、他の人が指摘しているように、ロギング フレームワークで利用可能なフォーマットがある場合 (つまり、それをサポートするのに十分な最新のものを使用している場合、それはすべてのフレームワークである必要がありますが、そうではありません)、それに依存する必要があります。伐採の時点で費用を負担するのに役立ちます。選択したフレームワークがまだフォーマットをサポートしていない場合は、切り替えるか、独自のラッパーを記述します。

于 2011-04-26T16:45:16.833 に答える
2

log()おっしゃるとおり、呼び出しの引数を評価すると、不要なオーバーヘッド追加され、コストがかかる可能性があります。

そのため、ほとんどの正常なロギング フレームワークは、次のようなものを記述できるように、いくつかの文字列フォーマット関数も提供しています。

log.debug("Frobnicating {0}", objectWithExpensiveToString);

この方法では、唯一のオーバーヘッドは への呼び出しdebug()です。そのレベルが非アクティブ化されている場合は、それ以上何も行われず、アクティブ化されている場合は、フォーマット文字列が解釈され、toString()onobjectWithExpensiveToString()が呼び出され、結果がログに記録される前にフォーマット文字列に挿入されます。

MessageFormatスタイル プレースホルダー ( {0})を使用するログ ステートメントもあれば、format()スタイルプレースホルダー ( ) を使用するログ ステートメントもあります%s

于 2011-04-26T16:44:52.880 に答える
-1

少し冗長ですが、アサーションで面白い方法を使用できます。アサーションをオンにすると出力とオーバーヘッドが発生し、アサーションをオフにすると出力もオーバーヘッドもまったくありません。

public static void main(String[] args) {
    assert returnsTrue(new Runnable() {
        @Override
        public void run() {
            // your logging code
        }
    });
}

public static boolean returnsTrue(Runnable r) {
    r.run();
    return true;
}

ここで returnsTrue() 関数が必要なのは、式が true を返すようにするためのより良い方法がわからないためであり、assert にはブール値が必要です。

于 2011-04-26T17:03:13.183 に答える