唯一事件ID生成
我正在使用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方法的调用堆栈。这个策略的问题在于,它只能在调试符号构建时才能工作。我也需要它在生产代码中工作。
有没有人有任何想法?
IL偏移号码不带调试符号。结合堆栈信息和哈希值,我认为这可以解决问题。
这里有一篇文章说,部分覆盖检索IL偏移量(用于记录它的离线匹配PDB文件的目的 - 不同的问题,但我认为它会告诉你你需要什么):
我不知道我是如何错过了这一点,但欢呼声。这正是我所期待的。 – 2009-06-09 20:23:41
现在我想用EventId尝试 和组相关的错误。
您在事件查看器中的过滤器,为什么(去寻找?你有65536个独特的事件ID了。
或者说使用log4net的什么?
只是我的想法....
这有两个问题。首先,即使我使用的log4net不能解决我的分组问题。其次,我想要使用EventId *因为我想使用过滤器。这是一个非常糟糕的答案,这就是为什么我投了票。 – 2009-06-04 16:56:17
以及你可以写自己的代码.... – abmv 2009-06-05 10:21:24
感谢散列调用堆栈的想法,我要问的是如何挑选的EVENTID是非常相同的问题。
我建议把在LogSomething是incremen静态变量每次调用它时。
使用最后一个堆栈帧的ILOffset而不是行号(即上述TestLog方法的堆栈帧)创建一个散列。
下面是一些代码,你可以用它来生成与我在我的问题描述性的事件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。
* 重要提示:本文着重于解决问题的根源,而不是提供您特别要求的解决方案。我意识到这篇文章已经过时了,但是觉得它很重要。 *
我的团队也有类似的问题,我们改变了我们管理日志的方式,这显着降低了生产支持和bug修补时间。实际上,这适用于我团队工作的大多数企业应用程序:
- 使用“类名”。“函数名”的前缀日志消息。
- 对于真正的错误,将捕获的异常输出到事件记录器。
- 重点将清晰的消息作为同行代码审查的一部分,而不是事件ID。
- 为每个功能使用一个唯一的事件ID,只需从上到下键入它们。
- 当为每个函数编写不同的事件ID变得不切实际时,每个类应该只有一个唯一的(碰撞被定罪)。
- 利用事件类别过滤日志
当然它很重要你的应用程序有多大,以及如何敏感数据时减少事件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; }
}
只是要清楚,你想在你的例子中的两个电话有不同的eventIDs? – 2009-06-09 13:45:10
@Michael是的,他们应该有不同的EventIds,因为日志调用发生在不同的线路上。我的问题是能否做到这一点? – 2009-06-09 14:14:56