4

Windows イベント ログを使用していくつかのイベントを記録しています。Windows イベント ログ内のイベントには、いくつかのプロパティを割り当てることができます。そのうちの 1 つは EventID です。

ここで、EventId を使用して、関連するエラーを試してグループ化したいと思います。ロギング メソッドの呼び出しごとに番号を選択することもできますが、それは少し面倒です。

システムがこれを自動的に行うようにしたい。ロギング イベントが発生したコード内の位置に対して「一意」の eventId を選択します。現在、一意のイベント ID は 65536 しかないため、競合が発生する可能性がありますが、EventId をエラーのグループ化に役立つ方法にするほど、衝突はまれです。

1 つの戦略は、スタックトレースのハッシュコードを取得することですが、これは、次のコードの最初と 2 番目の呼び出しが同じイベント ID を生成することを意味します。

public void TestLog()
{
   LogSomething("Moo");
   // Do some stuff and then a 100 lines later..
   LogSomething("Moo");
}

GetFileLineNumber メソッドを持つ StackFrame クラスを使用してコール スタックを調べることを考えました。この戦略の問題点は、デバッグ シンボルをオンにしてビルドした場合にのみ機能することです。プロダクションコードでも動作する必要があります。

誰にもアイデアはありますか?

4

6 に答える 6

6

私の質問で説明したプロパティを使用して EventID を生成するために使用できるコードを次に示します。

 public static int GenerateEventId()
 {
     StackTrace trace = new StackTrace();

     StringBuilder builder = new StringBuilder();
     builder.Append(Environment.StackTrace);

     foreach (StackFrame frame in trace.GetFrames())
     {
           builder.Append(frame.GetILOffset());
           builder.Append(",");
     }

     return builder.ToString().GetHashCode() & 0xFFFF;
 }

frame.GetILOffset() メソッド呼び出しは、実行時の特定のフレーム内の位置を示します。

これらのオフセットをスタック トレース全体と連結して、プログラム内の現在の位置を表す一意の文字列を作成します。

最後に、一意のイベント ID は 65536 個しかないため、0xFFFF に対してハッシュコードの論理積をとって、最下位の 16 ビットを抽出します。この値は EventId になります。

于 2009-06-09T20:31:11.120 に答える
3

IL オフセット番号は、デバッグ シンボルなしで使用できます。スタック情報と組み合わせてハッシュすると、うまくいくと思います。

これは、部分的に、ILオフセットの取得について説明している記事です(PDBファイルとのオフライン一致のためにログに記録するためです-別の問題ですが、必要なものが表示されると思います):

http://timstall.dotnetdevelopersjournal.com/getting_file_and_line_numbers_without_deploying_the_pdb_file.htm

于 2009-06-09T16:37:31.040 に答える
1

行番号の代わりに、最後から 2 つ前のスタック フレームの ILOffset を使用してハッシュを作成します (つまり、上記の TestLog メソッドのスタック フレーム)。

于 2009-06-09T16:55:28.363 に答える
1

*重要: この投稿では、具体的に求められた解決策を提供するのではなく、問題の根本原因を解決することに焦点を当てています。この投稿が古いことは承知していますが、貢献することが重要だと感じました。*

私のチームにも同様の問題があり、ロギングの管理方法を変更したことで、本番サポートとバグ パッチの時間が大幅に短縮されました。実際には、これは私のチームが取り組んでいるほとんどのエンタープライズ アプリで機能します。

  1. ログ メッセージの前に「クラス名」.「関数名」を付けます。
  2. 真のエラーの場合、キャプチャされた例外をイベント ロガーに出力します。
  3. イベント ID ではなく、ピア コード レビューの一部として明確なメッセージを持つことに重点を置いてください。
  4. 関数ごとに一意のイベント ID を使用し、上から下に移動してキーを設定します。
  5. 各関数に異なるイベント ID をコーディングすることが現実的でなくなった場合は、各クラスに一意のイベント ID を指定する必要があります (衝突は最悪です)。
  6. ログをフィルタリングする際に、イベント カテゴリを利用してイベント ID への依存を減らします。

もちろん、アプリの大きさとデータの機密性は重要です。私たちのほとんどは、最小限の機密情報を含む約 10,000 ~ 500,000 行のコードです。単純化しすぎているように感じるかもしれませんが、KISS の観点からは実用的に機能します。

そうは言っても、抽象的な Event Log クラスを使用してプロセスを簡素化すると、使いやすくなりますが、クリーンアップは不快な場合があります。例えば:

MyClass.cs (ラッパーを使用)

class MyClass
{
    // hardcoded, but should be from configuration vars
    private string AppName = "MyApp";
    private string AppVersion = "1.0.0.0";
    private string ClassName = "MyClass";
    private string LogName = "MyApp Log";

    EventLogAdapter oEventLogAdapter;
    EventLogEntryType oEventLogEntryType;

    public MyClass(){
        this.oEventLogAdapter = new EventLogAdapter(
              this.AppName
            , this.LogName
            , this.AppName
            , this.AppVersion
            , this.ClassName
        );
    }

    private bool MyFunction() {
        bool result = false;
        this.oEventLogAdapter.SetMethodInformation("MyFunction", 100);
        try {
            // do stuff
            this.oEventLogAdapter.WriteEntry("Something important found out...", EventLogEntryType.Information);

        } catch (Exception oException) {
            this.oEventLogAdapter.WriteEntry("Error: " + oException.ToString(), EventLogEntryType.Error);
        }
        return result;
    }
}

EventLogAdapter.cs

class EventLogAdapter
{
    //vars
    private string _EventProgram = "";
    private string _EventSource = "";
    private string _ProgramName = "";
    private string _ProgramVersion = "";
    private string _EventClass = "";
    private string _EventMethod = "";
    private int _EventCode = 1;
    private bool _Initialized = false;
    private System.Diagnostics.EventLog oEventLog = new EventLog();
    // methods
    public EventLogAdapter() {  }
    public EventLogAdapter(
          string EventProgram
        , string EventSource
        , string ProgramName
        , string ProgramVersion
        , string EventClass
    ) {
        this.SetEventProgram(EventProgram);
        this.SetEventSource(EventSource);
        this.SetProgramName(ProgramName);
        this.SetProgramVersion(ProgramVersion);
        this.SetEventClass(EventClass);
        this.InitializeEventLog();
    }
    public void InitializeEventLog() {
        try {
            if(
                !String.IsNullOrEmpty(this._EventSource)
                && !String.IsNullOrEmpty(this._EventProgram)
            ){
                if (!System.Diagnostics.EventLog.SourceExists(this._EventSource)) {
                    System.Diagnostics.EventLog.CreateEventSource(
                        this._EventSource
                        , this._EventProgram
                    );
                }
                this.oEventLog.Source = this._EventSource;
                this.oEventLog.Log = this._EventProgram;
                this._Initialized = true;
            }
        } catch { }
    }
    public void WriteEntry(string Message, System.Diagnostics.EventLogEntryType EventEntryType) {
        try {
            string _message = 
                "[" + this._ProgramName + " " + this._ProgramVersion + "]"
                + "." + this._EventClass + "." + this._EventMethod + "():\n"
                + Message;
            this.oEventLog.WriteEntry(
                  Message
                , EventEntryType
                , this._EventCode
            );
        } catch { }
    }
    public void SetMethodInformation(
        string EventMethod
        ,int EventCode
    ) {
        this.SetEventMethod(EventMethod);
        this.SetEventCode(EventCode);
    }
    public string GetEventProgram() { return this._EventProgram; }
    public string GetEventSource() { return this._EventSource; }
    public string GetProgramName() { return this._ProgramName; }
    public string GetProgramVersion() { return this._ProgramVersion; }
    public string GetEventClass() { return this._EventClass; }
    public string GetEventMethod() { return this._EventMethod; }
    public int GetEventCode() { return this._EventCode; }
    public void SetEventProgram(string EventProgram) { this._EventProgram = EventProgram; }
    public void SetEventSource(string EventSource) { this._EventSource = EventSource; }
    public void SetProgramName(string ProgramName) { this._ProgramName = ProgramName; }
    public void SetProgramVersion(string ProgramVersion) { this._ProgramVersion = ProgramVersion; }
    public void SetEventClass(string EventClass) { this._EventClass = EventClass; }
    public void SetEventMethod(string EventMethod) { this._EventMethod = EventMethod; }
    public void SetEventCode(int EventCode) { this._EventCode = EventCode; }

}
于 2014-02-17T06:06:47.703 に答える
-2

ここで、EventId を使用して、関連するエラーを試してグループ化したいと思います。

イベントビューアーにフィルターがあるのはなぜですか (検索に移動しますか? 65536 の一意のイベント ID もあります。

それとも、log4netなどを使用しますか??

ちょうど私のアイデア....

于 2009-06-04T16:51:37.377 に答える