【问题标题】:What is the easiest way using .net to check if events have been logged in the eventlog?使用 .net 检查事件日志中是否记录了事件的最简单方法是什么?
【发布时间】:2008-10-08 12:01:07
【问题描述】:

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

我想执行一系列自动化测试步骤,然后检查是否有任何错误记录到应用程序事件日志中,忽略一些我不感兴趣的来源。我可以使用 System.Diagnostics.EventLog 然后查看在 Entries 集合中,但在这种情况下似乎不太有用。例如,如果事件日志正在删除旧条目,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.
  // ...
}

【问题讨论】:

    标签: c# .net testing event-log


    【解决方案1】:

    只是为了成为一名优秀的 Wiki 公民并努力完成,还有其他方法。我之前没有建议它,因为它对于仅作为测试套件的一部分在内部运行的东西来说完全是矫枉过正,而且你在标题中说你想要一些简单的东西。

    但是,如果您需要查看运输代码中发生的事件,请继续阅读。信不信由你,目前有 三个 不同的 Windows API 用于这个东西。

    NotifyChangeEventLog()

    这类事情的原始 API 称为 NotifyChangeEventLog(),从 Windows 2000 开始就支持它。本质上,您使用 WIN32 event log APIs 打开事件日志,然后使用您提供的句柄调用此 API另一个 API 和一个事件句柄。当有新的事件日志条目可供查看时,Windows 将发出您的事件信号。

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

    Windows 管理规范

    第二种方法是使用Windows Management Instrumentation API,它确实支持本地和远程日志。这是一个基于 COM/DCOM 的 API,在 Windows 中已经存在好几年了,.NET 框架在 System.Management 命名空间中有一个很好的实现。本质上,您所做的是创建一个EventQuery,它查找Win32_NTLogEvent 类型(即在WMI 类型系统内)的新WMI 对象的外观。这些的出现将指示新的事件日志条目,并且它们将几乎实时呈现。这些对象的属性包含日志条目的所有详细信息。有一个 article from MSDN magazine 谈到在 Visual Studio 中玩这些东西。

    同样,这对于测试应用程序来说完全是多余的,它需要的代码比您现有的解决方案要多得多。但是几年前,我为一个网络管理应用程序编写了一个子系统,它使用这个 API 的 DCOM 风格来收集网络上所有服务器的事件日志,以便我们可以对特定的服务器发出警报。它几乎是实时的。如果您使用 DCOM 在 C++ 中实现此功能,请准备好处理多线程单元和大量复杂的逻辑来检测您与远程服务器的连接是否/何时启动或关闭。

    Windows Vista 事件日志

    Windows Vista(和 Server 2008)具有与事件记录和跟踪相关的全新 API 套件。 new event log is documented here。看起来有一个名为 EvtSubscribe 的 API 允许您 subscribe to events。我没有使用过这个 API,所以我无法评论它的优缺点。

    【讨论】:

      【解决方案2】:

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

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

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

      【讨论】:

        【解决方案3】:

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

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

        【讨论】:

        • 公平点,只有多个开发人员我想灵活地使用运行测试的环境。
        【解决方案4】:

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

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

        /// <summary>
        /// Steps through each of the entries in the specified event log and returns any that were written 
        /// after the given point in time. 
        /// </summary>
        /// <param name="logName">The event log to inspect, eg "Application"</param>
        /// <param name="writtenSince">The point in time to return entries from</param>
        /// <param name="type">The type of entry to return, or null for all entry types</param>
        /// <returns>A list of all entries of interest, which may be empty if there were none in the event log.</returns>
        public List<EventLogEntry> GetEventLogEntriesSince(string logName, DateTime writtenSince, EventLogEntryType type)
        {
            List<EventLogEntry> results = new List<EventLogEntry>();
            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.");
        

        【讨论】:

        • 如果您可以根据给定的参数生成 XML 查询,性能会更好。
        【解决方案5】:

        我使用此 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 查询。

        【讨论】:

          猜你喜欢
          • 2018-05-03
          • 1970-01-01
          • 2011-07-21
          • 1970-01-01
          • 1970-01-01
          • 2010-11-03
          • 2010-09-23
          • 1970-01-01
          • 2015-07-08
          相关资源
          最近更新 更多