2009-06-04 165 views
4

我正在使用Windows事件日誌來記錄一些事件。 Windows事件日誌中的事件可以分配一些屬性。其中之一是EventID。唯一事件ID生成

現在我想使用EventId嘗試將相關的錯誤進行分組。我可以爲每次調用我所用的日誌記錄方法選擇一個數字,但這似乎有點乏味。

我希望系統自動執行此操作。它會選擇一個eventId,它對發生日誌記錄事件的代碼中的位置是「唯一」的。現在,只有65536個唯一的事件ID,因此可能會發生衝突,但它們應該足夠罕見,可以使EventId成爲分組錯誤的有用方法。

一種策略是採用堆棧跟蹤的散列碼,但這意味着下面代碼中的第一個和第二個調用將生成相同的事件ID。

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

我想到了使用StackFrame類有一個GetFileLineNumber方法的調用堆棧。這個策略的問題在於,它只能在調試符號構建時才能工作。我也需要它在生產代碼中工作。

有沒有人有任何想法?

+0

只是要清楚,你想在你的例子中的兩個電話有不同的eventIDs? – 2009-06-09 13:45:10

+0

@Michael是的,他們應該有不同的EventIds,因爲日誌調用發生在不同的線路上。我的問題是能否做到這一點? – 2009-06-09 14:14:56

回答

3

IL偏移號碼不帶調試符號。結合堆棧信息和哈希值,我認爲這可以解決問題。

這裏有一篇文章說,部分覆蓋檢索IL偏移量(用於記錄它的離線匹配PDB文件的目的 - 不同的問題,但我認爲它會告訴你你需要什麼):

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

+0

我不知道我是如何錯過了這一點,但歡呼聲。這正是我所期待的。 – 2009-06-09 20:23:41

-1

現在我想用EventId嘗試 和組相關的錯誤。

您在事件查看器中的過濾器,爲什麼(去尋找?你有65536個獨特的事件ID了。

或者說使用log4net的什麼?

只是我的想法....

+0

這有兩個問題。首先,即使我使用的log4net不能解決我的分組問題。其次,我想要使用EventId *因爲我想使用過濾器。這是一個非常糟糕的答案,這就是爲什麼我投了票。 – 2009-06-04 16:56:17

+0

以及你可以寫自己的代碼.... – abmv 2009-06-05 10:21:24

0

感謝散列調用堆棧的想法,我要問的是如何挑選的EVENTID是非常相同的問題。

我建議把在LogSomething是incremen靜態變量每次調用它時。

1

使用最後一個堆棧幀的ILOffset而不是行號(即上述TestLog方法的堆棧幀)創建一個散列。

5

下面是一些代碼,你可以用它來生成與我在我的問題描述性的事件ID:

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()方法調用給出了具體的框架內的位置時執行。

我將這些偏移與整個堆棧跟蹤連接起來,爲程序中的當前位置提供唯一的字符串。

最後,由於只有65536個唯一事件ID,我邏輯與哈希碼相對於0xFFFF來提取最不重要的16位。這個值然後成爲EventId。

1

* 重要提示:本文着重於解決問題的根源,而不是提供您特別要求的解決方案。我意識到這篇文章已經過時了,但是覺得它很重要。 *

我的團隊也有類似的問題,我們改變了我們管理日誌的方式,這顯着降低了生產支持和bug修補時間。實際上,這適用於我團隊工作的大多數企業應用程序:

  1. 使用「類名」。「函數名」的前綴日誌消息。
  2. 對於真正的錯誤,將捕獲的異常輸出到事件記錄器。
  3. 重點將清晰的消息作爲同行代碼審查的一部分,而不是事件ID。
  4. 爲每個功能使用一個唯一的事件ID,只需從上到下鍵入它們。
  5. 當爲每個函數編寫不同的事件ID變得不切實際時,每個類應該只有一個唯一的(碰撞被定罪)。
  6. 利用事件類別過濾日誌

當然它很重要你的應用程序有多大,以及如何敏感數據時減少事件ID依賴。我們大部分的代碼都是大約10k到500k行代碼,並且信息極其敏感。它可能會讓人覺得過於簡單,但從KISS的角度來看,它務實地工作。這就是說,使用抽象的事件日誌類來簡化過程使其易於使用,儘管清理我的不愉快。例如:

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; } 

}