4

我正在使用 Windows 事件日志来记录一些事件。可以为 Windows 事件日志中的事件分配一些属性。其中之一是 EventID。

现在我想使用 EventId 来尝试和分组相关的错误。我可以为每次调用我所做的日志记录方法选择一个数字,但这似乎有点乏味。

我希望系统自动执行此操作。它将选择一个 eventId,该 eventId 对于发生日志事件的代码中的位置是“唯一的”。现在,只有 65536 个唯一事件 ID,因此可能会发生冲突,但它们应该足够少,以使 EventId 成为对错误进行分组的有用方法。

一种策略是获取堆栈跟踪的哈希码,但这意味着以下代码中的第一次和第二次调用将生成相同的事件 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() 方法调用给出了执行时该特定帧内的位置。

我将这些偏移量与整个堆栈跟踪连接起来,为程序中的当前位置提供一个唯一的字符串。

最后,由于只有 65536 个唯一事件 ID,因此我将哈希码与 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

使用最后一个但一个堆栈帧的 ILOffset 而不是行号(即上面的 TestLog 方法的堆栈帧)创建一个哈希。

于 2009-06-09T16:55:28.363 回答
1

*重要提示:这篇文章的重点是解决问题的根本原因,而不是提供您特别要求的解决方案。我意识到这篇文章已经过时了,但我觉得做出贡献很重要。*

我的团队遇到了类似的问题,我们改变了管理日志的方式,这显着减少了生产支持和错误修补时间。实际上,这适用于我的团队从事的大多数企业应用程序:

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

}
于 2014-02-17T06:06:47.703 回答
0

感谢您对调用堆栈进行散列处理的想法,我正要问同样的问题,即如何选择 eventId。

我建议在 LogSomething 中放置一个静态变量,该变量在每次调用时都会递增。

于 2009-06-09T13:41:48.897 回答
-2

现在我想使用 EventId 来尝试和分组相关的错误。

您在事件查看器中有过滤器,为什么(去查找?您也有 65536 个唯一事件 ID。

或者更确切地说使用log4net或其他东西?

只是我的想法....

于 2009-06-04T16:51:37.377 回答