使用.net检查事件日志中是否记录了事件的最简单方法是什么?

在一段时间内检查事件日志中是否记录了事件的最简单方法是什么?

我想执行一系列自动化测试步骤,然后检查是否有任何错误记录到应用程序事件日志中,忽略了一些我不感兴趣的源。我可以使用System.Diagnostics.EventLog然后查看条目集合,但它似乎不适用于这种情况。 例如,如果事件日志正在删除旧条目,则Entries.Count会随着时间的推移变小。 我更喜欢某种方式来查询日志或监视它在一段时间内的变化。 例如

DateTime start = DateTime.Now; // do some stuff... foreach(EventLogEntry entry in CleverSolution.EventLogEntriesSince(start, "Application")) { // Now I can do stuff with entry, or ignore if its Source is one // that I don't care about. // ... } 

只是为了成为一名优秀的维基公民并努力完成,还有其他方法。 我之前没有提出过建议,因为它只是作为测试套件的一部分在内部运行的东西完全矫枉过正,而你在标题中说你想要的东西很容易。

但是,如果您需要查看运输代码中发生的事件,请继续阅读。 信不信由你,此时有三种不同的Windows API。

NotifyChangeEventLog()

这类事物的原始API称为NotifyChangeEventLog() ,它在Windows 2000中得到支持。基本上,您使用WIN32事件日志API打开事件日志,然后使用另一个给出的句柄调用此API。 API和事件句柄。 当有新的事件日志条目要查看时,Windows将发出事件信号。

我自己从未使用过这个API,因为我最感兴趣的是远程事件日志访问,而且这个API显然不支持远程日志。 但是,如果您具有正确的权限,则此属于的其余API集允许您按顺序读取远程日志。

Windows Management Instrumentation

第二种方法是使用Windows Management Instrumentation API ,这确实支持本地和远程日志。 这是一个基于COM / DCOM的API,已在Windows中存在多年,.NET Framework在System.Management命名空间中有很好的实现。 基本上你要做的是创建一个EventQuery ,它查找Win32_NTLogEvent类型(在WMI类型系统中)的新WMI对象的外观。 这些内容将显示新的事件日志条目,并且它们将实时呈现。 这些对象上的属性包含日志条目的所有详细信息。 有一篇来自MSDN杂志的文章谈到在Visual Studio中玩这些东西。

同样,对于测试应用程序来说,这将是完全过度的,它将需要比现有解决方案更多的代码。 但是几年前我为网络管理应用程序编写了一个子系统,该子系统使用此API的DCOM风格从网络上的所有服务器收集事件日志,以便我们可以对特定的服务器发出警报。 它非常光滑,近乎实时。 如果您使用DCOM在C ++中实现它,请准备好处理multithreading公寓和许多毛茸茸的逻辑,以检测您与远程服务器的连接是否/何时上升或下降。

Windows Vista事件日志

Windows Vista(和Server 2008)有一个与事件记录和跟踪相关的全新API套件。 此处记录了新的事件日志 。 看起来有一个名为EvtSubscribe的API允许您订阅事件 。 我没有使用过这个API,所以我不能评论它的优缺点。

话虽如此,这里的答案实际上应该非常简单,即使对于您的测试应用程序而言也是特定于.NET Framework的。

您需要在开始测试之前打开EventLog,并为EventLog.EntryWritten事件订阅事件处理程序。 这是.NET公开NotifyChangeEventLog()Win32 API的方式。

将当前逻辑从GetEventLogEntriesSince()到事件处理程序中,但不是将事件添加到列表中以进行返回,而是将它们存储在可以从运行结束时的某个位置检索的列表中。 您可以通过Entry属性从EntryWrittenEventArgs参数中检索日志条目的内容。

System.Diagnostics.EventLog类确实是执行此操作的正确方法。

您的主要异议似乎是日志可以在某些情况下删除旧条目。 但是你说这是在软件测试场景中。 您是否可以安排配置测试系统,使日志足够大以包含所有条目,并且在测试期间不会删除旧条目?

我提出的解决方案确实使用System.Diagnostics.EventLog并简单地遍历所有事件以过滤我想要的那些事件。 我想这很简单,我只是觉得会有更高效的界面。 任何建议或改进都非常欢迎!

我创建了一个从某个时间开始返回事件日志条目的方法:

 ///  /// Steps through each of the entries in the specified event log and returns any that were written /// after the given point in time. ///  /// The event log to inspect, eg "Application" /// The point in time to return entries from /// The type of entry to return, or null for all entry types /// A list of all entries of interest, which may be empty if there were none in the event log. public List GetEventLogEntriesSince(string logName, DateTime writtenSince, EventLogEntryType type) { List results = new List(); EventLog eventLog = new System.Diagnostics.EventLog(logName); foreach (EventLogEntry entry in eventLog.Entries) { if (entry.TimeWritten > writtenSince && (type==null || entry.EntryType == type)) results.Add(entry); } return results; } 

在我的测试类中,我存储了一个时间戳:

 private DateTime whenLastEventLogEntryWritten; 

在测试设置期间,我将时间戳设置为写入最后一个事件日志条目的时间:

 EventLog eventLog = new EventLog("Application"); whenLastEventLogEntryWritten = eventLog.Entries.Count > 0 ? eventLog.Entries[eventLog.Entries.Count - 1] : DateTime.Now; 

在测试结束时,我检查没有事件日志错误:

 Assert.IsEmpty(GetEventLogEntriesSince("Application", whenLastEventLogEntryWritten, EventLogEntryType.Error), "Application Event Log errors occurred during test execution."); 

我使用此Powershell在过去7天内扫描事件日志中的相关条目:

 $d=Get-Date $recent=[System.Management.ManagementDateTimeConverter]::ToDMTFDateTime($d.AddDays(-7)) get-wmiobject -computer HOSTNAME -class Win32_NTLogEvent ` -filter "logfile = 'Application' and (sourcename = 'SOURCENAME' or sourcename like 'OTHERSOURCENAME%') and (type = 'error' or type = 'warning') AND (TimeGenerated >='$recent')" | sort-object @{ expression = {$_.TimeWritten} } -descending | select SourceName, Message | format-table @{Expression = { $_.SourceName};Width = 20;Label="SourceName"}, Message 

如果您使用C#(已标记,但在问题中未提及),则神奇之处在于get-wmiobject查询。