22

When should we log? Before function calls (example A) or at beginning of a target method (example B)?

Note, that this question is about exact logger function call placement, not general best logging practices.

Solution A: Log at function call:

function someProcess() {
    log.info("Reading data");
    readDataFromIO();
    log.info("Outputing data");
    outputDataToScreen();
}

// ... other module:

function readDataFromIO() {
    ...
}

function outputDataToScreen() {
    ... 
}

Solution B: Log at the beggining of a method:

function someProcess() {
    readDataFromIO();
    outputDataToScreen();
}

// ... other module:

function readDataFromIO() {
    log.info("Reading data");
    ...
}

function outputDataToScreen() {
    log.info("Outputing data");
    ... 
}

解決策 A では、メッセージをカスタマイズしたり、効率の問題が発生したときにログを取り消すことができますが、ログ メッセージが同じように見える場合、ログを記録するのを忘れて、多くの重複コードが発生する可能性があります。解決策 B では、ログ記録とコードの重複を忘れるリスクはありませんが、ログ記録ロジックを 100% オフにすることはできず、null ポインター例外などのメソッド呼び出しでエラーが発生した場合に問題が発生します。ベストプラクティスはどれですか?

4

7 に答える 7

10

私がここで提供しているプラ​​クティスは、ソースからのものではありませんが、私が使用し、長年の使用で最も効果的であることがわかったものです.

ログイン方法

メソッドは、特定の目的を持つコードのブロックです。メソッド自体に各メソッドのログを保持します。そうすれば、他の場所からメソッドを再利用するときに、それぞれの場所にロガーを追加する必要がなくなります。メソッドがたまたま多くの場所から呼び出されるユーティリティである場合は、そのプレフィックスのロガー レベルまたはロガーの優先度を下げます。

MDC/リクエストID/スレッド名を使用

リクエストのフローまたは呼び出しのソースを追跡するには、ロガーにパラメーターを設定するか、スレッド名を使用して、後続のすべてのログにタグが付けられ、そのタグのログが追跡されるようにします。通常、リクエストを受信したらすぐにロガーにタグを設定することをお勧めします。

重複ログを回避するには

例外をキャッチし、コードの特定の論理ステージでログに記録します。例 - 次のスタック Action/JSP/Web サービスなどを持つ Web アプリケーションで -> モジュール呼び出し -> ヘルパー モジュール -> Util -> ライブラリ。

ここでは、モジュール呼び出しレベル (コードのsomeProcess()に対応) でログを記録します。内部呼び出しはすべて、メソッド内に配置された DEBUG レベルの呼び出しになります。または、より高いログ フィルターを使用してヘルパー モジュールなどをログに記録することもできます。

ロギングは非常に主観的な問題であり、1 つの方法を決定し、どこでもそれに固執することに関係しています。万能のソリューションはありません。時間の経過とともにパラメータを少しずつ微調整することで、使用しているロガーの詳細レベル、パフォーマンス、信号対雑音比を把握する必要があります。

于 2013-04-28T20:28:19.727 に答える
1

以下は、私自身の経験に基づいて提供できるヒントです (このトピックは言語に依存しないというフラグが付けられているため、一般的なものにしておきます)。

  • メッセージをログに記録するには、デリゲート関数を使用します (または、ログ関数を使用して中央ログ クラスを作成します)。パラメータには、ログ メッセージ、ログの重大度、およびログ レベルが含まれている必要があります。このデリゲート関数 (またはログ クラスの関数) は、ログを記録する必要があるすべての場所で呼び出す必要があります。ファイルベースのログから Windows イベント ログへの変更など、ログ メカニズムを簡単に置き換えることができます。この関数では、ログ レベルを処理することもできます。つまり、警告を抑制するように構成可能にすることができます。
  • ランタイム エラーをキャッチできるようにsomeProcess()try-catch を追加します。
  • 何かを開始したとき、何かを終了したときにログを記録し、発生する可能性のあるエラーを常にログに記録します。これらのログ呼び出しは、例 B に示すように、関数内でローカルにすることができます。
  • 使用している言語がそれをサポートしている場合は、例外をログに記録するための関数/メソッドを記述します。たとえば、C#では、例外の拡張メソッド を記述することがpublic static void Log(this Exception ex) { // ... logging code ... }できます。これにより、次のように各 catch ブロックで単純に呼び出すことがtry { ... } catch (Exception ex) { ex.Log(); }
    できます。のようにオプションのパラメータを追加するのにも役立つpublic static void Log(this Exception ex, string message="") { ... logging code ... }ので、 のように追加情報を渡すことができますex.Log("readDataFromIO() - read error occurred");

このようにして、質問で言及した欠点を回避できます (エラーがキャッチされず、コードが重複します)。

可能であれば、使用しているフレームワークまたは言語に既にそのようなクラスがあるかどうかを確認し (通常はそうです)、それを使用するか、それを使用する独自のフレームワーク (つまり、独自の集中ロギング クラス) を開発し直してください。ホイールを完全に。

于 2013-04-22T11:45:30.067 に答える
1

前に述べたことに加えて、私はロギングのやや一般化された概念を使用しています。これは、特定の条件が予想よりも頻繁に発生する、または発生する頻度が低い状況を発見するのに役立ちます。

クラスを使用していLogEventます (コードは ですがJava、アイデアはほとんどの言語に移植できます):

public class LogEvent {
    private int count;
    private String name;

    public LogEvent(String name) {
        this.name = name;
        count = 1;
    }

    public int count() {
        return this.count;
    }

    public void inc() {
        count++;
    }

    public String name() {
        return this.name;
    }

    public void report() {
        if (count >= 1) {
            Util.info(name + " (x " + count + ")");
        }
        else {
            Util.info(name);
        }
    }
}

イベントを発生させ、その発生を収集する方法は?

LogEventsを使用して「登録」できますLogEventCollection

import java.util.Map;
import java.util.TreeMap;

public class LogEventCollection {
    private Map<String, LogEvent> events;

    public EventCollection() {
        events = new TreeMap<String, Event>();
    }

    public void register(String name) {
        LogEvent ev;

        if (events.containsKey(name)) {
            ev = events.get(name);

            ev.inc();
        }
        else {
            ev = new LogEvent(name);

            events.put(name, ev);
        }
    }

    public void report(String title, int minCount) {
        Util.info("");

        if (!title.isEmpty()) {
            Util.info(title);
        }

        for (LogEvent ev : events.values()) {       
            if ((minCount < 0) || (ev.count() >= minCount)) {
                ev.report();
            }
        }
        Util.info("");
    }
}

私のプログラムの内部イベントの概要を取得するために、このLogEventCollectionメソッドreport()は、すべてのリストとLogEventsそれぞれのカウントを示します。このリストは、名前またはイベントの頻度でソートできます。

マルチスレッド アプリケーションで LogEventCollection への同時アクセス中の競合を防ぐには、追加のロック コードまたはスレッド セーフ コレクションが必要です。

明らかに、このアプローチは条件付きイベントを追加することで拡張できます (= への呼び出しregister()は何らかの条件によって保護されます)。または、本番実行中にイベント ログを無効にすることもできます。

于 2013-04-27T20:30:47.370 に答える
1

ベスト プラクティス:

  • さまざまなレベル (DEBUG、INFO など) でログを記録できる、ある種の Logger クラス/モジュール (言語によって異なります) を使用します。
  • 非常に基本的な機能を LogLevel DEBUG に記録します
  • より複雑な関数を LogLevel INFO に記録します (例: 他の基本関数を呼び出す関数)
  • LogLevel WARN で潜在的な問題をログに記録する
  • LogLevel ERROR でエラーと例外をログに記録する

個別のログ機能により、効率に応じてログのオン/オフを切り替えることができます。しかし、すべてをログに記録する機能もあります。

例: Java には、優れたカスタマイズ オプションを提供する log4j があります。logLevel を定義し、どのクラスのロギングを有効にするかを定義できます。そうすれば、基本レベル (WARN) でシステムを監視でき、エラーが発生した場合は、チェックする必要がある特定のクラスに DEBUG レベルを設定できます。

この手順は (もちろん) 使用する言語に大きく依存しますが、この「log4j」アプローチは非常に優れたものだと思います。

于 2013-04-22T11:02:42.553 に答える
0

ベスト プラクティスは、関数内に log() の呼び出しを配置することです。「someProcess」から呼び出されたときだけでなく、関数が呼び出されるたびにトレースが表示されます。

于 2013-04-28T12:46:24.090 に答える
-1

最も簡単な解決策は、メソッドのオーバーロードを作成することです。これにより、いつ「ログに記録」し、いつ「ログに記録」しないかを指定できます。

function someProcess() {
    readDataFromIO(true);  //This will make a "log"
    outputDataToScreen();  //This will make no "log"
}

// ... other module:

function readDataFromIO() {
    readDataFromIO(false); 
}

function readDataFromIO(bool makeLog) {
    if(makeLog)
        log.info("Reading data");
    ...
}

function outputDataToScreen() {
    outputDataToScreen(false);
}

function outputDataToScreen(bool makeLog) {
    if(makeLog)
        log.info("Outputing data");
    ... 
}
于 2013-04-29T10:44:28.020 に答える