独特的EventId生成

时间:2009-06-04 16:40:23

标签: c# logging event-log

我正在使用Windows事件日志记录一些事件。可以为Windows事件日志中的事件分配一些属性。其中一个是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类来调用调用堆栈。此策略的问题在于它仅在使用调试符号构建时才有效。我也需要它在生产代码中工作。

有没有人有任何想法?

6 个答案:

答案 0 :(得分:5)

以下是一些可用于生成具有我在问题中描述的属性的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。

答案 1 :(得分:3)

IL偏移号可用,不带调试符号。结合堆栈信息和哈希,我认为这样就可以了。

这篇文章部分涵盖了检索IL偏移量(为了将其记录为与PDB文件脱机匹配的目的 - 不同的问题,但我认为它会向您展示您需要的内容):

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

答案 2 :(得分:1)

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

答案 3 :(得分:1)

* 重要提示:本文重点介绍解决问题所在的根本原因,而不是提供您特别要求的解决方案。我意识到这篇文章很老,但觉得贡献很重要。 *

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

  1. 使用“类名”前缀日志消息。“函数名称”。
  2. 对于真正的错误,将捕获的异常输出到事件记录器。
  3. 专注于将明确的消息作为对等代码审查的一部分而不是事件ID。
  4. 为每个功能使用唯一的事件ID,只需从上到下按键即可。
  5. 当为每个函数编写不同的事件ID变得不切实际时,每个类应该只有一个唯一的(冲突被诅咒)。
  6. 利用事件类别来减少过滤日志时的事件ID依赖性
  7. 当然,重要的是应用程序的大小以及数据的敏感程度。我们的大多数代码都是大约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; }
    
    }
    

答案 4 :(得分:0)

感谢哈希调用堆栈的想法,我打算问一个关于如何选择eventId的相同问题。

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

答案 5 :(得分:-1)

  

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

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

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

只是我的想法......