什么是远程读取事件日志的最快方法?

14

我正在开发一个应用程序,从远程计算机读取事件日志(应用程序)。我使用 .net 中的 EventLog 类,并迭代日志条目,但这非常缓慢。在某些情况下,一些计算机有 40000+ 条日志条目,需要花费数小时才能迭代完所有条目。
如何以最佳方式完成此任务?是否有其他 .net 类或其他技术可以更快地实现?


我不知道读取事件日志项的最佳方法是什么,但我建议您重新考虑架构!您应该使用其他日志技术!我会使用Enterprise Library Logging Application block。然后,您可以轻松地记录到数据库中(您也可以记录到事件日志中)。然后,您可以轻松地针对数据库运行查询。 - Pavel Nikolov
我不记录事件日志。有多个应用程序记录事件日志,我的应用程序根据来源和事件代码搜索事件日志以从中获取信息。 - Kapil
9个回答

17

兄弟,我感同身受。我们的应用程序也遇到了完全相同的问题。

你的解决方案分支取决于你正在运行的服务器版本和你的“目标”机器所运行的服务器版本。

如果您们两个都在Vista或Windows Server 2008上,那就很幸运了。你应该看一下System.Diagnostics.Eventing.Reader.EventLogQuerySystem.Diagnostics.Eventing.Reader.EventLogReader。这些是.NET 3.5中新的功能。

基本上,你可以在XML中构建一个查询,并将其发送到远程计算机上运行。也许你只是在搜索特定类型的事件,或者仅仅是从特定时间点开始搜索新的事件。搜索在远程计算机上运行,然后你就可以得到匹配的事件。新的类比旧的.NET 2.0方式快得多,但它们仅在Vista或Windows Server 2008上受支持。

对于我们的应用程序,当目标不在Vista/Win2008上时,我们会从远程系统下载原始的.evt文件,然后使用其二进制格式解析文件。有几个关于.evt文件(Vista之前的文件)事件日志格式的数据来源,包括link text和我在codeproject.com上记得看到的一篇文章,其中有一些C#代码。

Vista和Windows Server 2008机器使用了一个新的.evtx格式,这是一种新格式,因此你不能在所有版本上使用相同的二进制解析方法。但新的EventLogQuery和EventLogReader类非常快,所以你不必这样做。现在只需要使用内置的类就可以轻松处理了。


4

一个好的解释/示例可以在MSDN上找到。

EventLogSession session = new EventLogSession(Environment.MachineName);

// [System/Level=2] filters out the errors
// Where "Log" is the log you want to get data from.
EventLogQuery query = new EventLogQuery("Log", PathType.LogName, "*[System/Level=2]");
query.Session = session;

EventLogReader reader = new EventLogReader(query);

for (EventRecord eventInstance = reader.ReadEvent();
    null != eventInstance;
    eventInstance = reader.ReadEvent())
{
    // Output or save your event data here.
}

使用旧代码等待 5-20 分钟,而这个代码不到 10 秒就能完成。


2
这里缺少了一行重要的代码:query.Session = session - OfirD
@OfirD,你能更新一下代码吗?应该放在哪里? - Mike Q
1
@OfirD 谢谢,我正在尝试将它移植到PowerShell中,所以这很有帮助。谢谢。它现在能够工作,但数据不完全正确。 - Mike Q

2
事件日志读取器太慢了...太慢了。微软这是怎么回事?
使用LogParser 2.2 - 在互联网上搜索C#和LogParser(或者您可以使用命令行中的log parser命令)。我不想重复其他人已经做过的工作。
通过将日志导出为EVTX文件,我从远程系统中获取日志。然后我将文件从远程系统复制到本地。这个过程非常快-即使网络跨越整个星球(我曾经尝试将日志导出到网络资源时遇到问题)。一旦你将它保存在本地,就可以进行搜索和处理。
有多种原因需要EVTX- 我不会详细说明我们为什么需要这样做。
以下是将日志另存为EVTX文件的代码示例: (注:‘device’是网络主机名或IP,“LogName” 是所需日志的名称:“System”,“Security”或“Application”。outputPathOnRemoteSystem是远程计算机上的路径,例如“c:\temp\%hostname%.%LogName%.%YYYYMMDD_HH.MM%.evtx”。)
    static public bool DumpLog(string device, string LogName, string outputPathOnRemoteSystem, out string errMessage)
    {
        bool wasExported = false;
        string errorMessage = "";
        try
        {
            System.Diagnostics.Eventing.Reader.EventLogSession els = new System.Diagnostics.Eventing.Reader.EventLogSession(device);
            els.ExportLogAndMessages(LogName, PathType.LogName, "*", outputPathOnRemoteSystem);
            wasExported = true;

        }
        catch (UnauthorizedAccessException e)
        {
            errorMessage = "Unauthorized - Access Denied: " + e.Message;
        }
        catch (EventLogNotFoundException e)
        {
            errorMessage = "Event Log Not Found: " + e.Message;
        }
        catch (EventLogException e)
        {
            errorMessage = "Export Failed: " + e.Message + ", Log: " + LogName + ", Device: " + device;
        }
        errMessage = errorMessage;
        return wasExported;
    }

1

刚遇到同样的问题,想分享我的解决方案。使用EventLogQuery可以使应用程序、系统和安全事件日志的搜索速度快100倍,时间只需260秒(使用EventLog)。 而且这种方式可以检查事件消息是否包含模式或任何其他检查,而无需FormatDescription()。

我的技巧是使用与PowerShell Get-WinEvent相同的机制,然后通过结果检查。

以下是我的代码,用于查找最近4天内所有事件消息中包含筛选器模式的事件。

string[] eventLogSources = {"Application", "System", "Security"};
var messagePattern = "*Your Message Search Pattern*";
var timeStamp = DateTime.Now.AddDays(-4);

var matchingEvents = new List<EventRecord>();

foreach (var eventLogSource in eventLogSources)
{ 
    var i = 0;
    var query = string.Format("*[System[TimeCreated[@SystemTime >= '{0}']]]",
        timeStamp.ToUniversalTime().ToString("o"));

    var elq = new EventLogQuery(eventLogSource, PathType.LogName, query);
    var elr = new EventLogReader(elq);
    EventRecord entryEventRecord;
    while ((entryEventRecord = elr.ReadEvent()) != null)
    {
        if ((entryEventRecord.Properties)
            .FirstOrDefault(x => (x.Value.ToString()).Contains(messagePattern)) != null)
        {
            matchingEvents.Add(entryEventRecord);
            i++;
        }
    }
}

0

最近我通过WCF回调接口完成了这样的事情,但我的客户是通过WCF与服务器进行交互的,在我的项目中添加WCF回调非常容易,完整的代码和示例可在此处找到。


0

0

你尝试过在PowerShell 2.0中使用远程功能吗?它们允许你在远程计算机上执行cmdlet(比如读取事件日志的cmdlet),并将结果(当然是作为对象)返回给调用会话。


0
你可以在那些机器上放置一个程序,将日志保存到文件并发送到你的Web应用程序中,我认为这样会快得多,因为你可以在本地循环,但我不确定如何做,所以我不能给你任何代码 :(

-1
也许远程计算机可以进行一些计算。这样,您的服务器只需处理相关信息。它将是一种使用远程计算机进行轻量级过滤的集群,并且服务器将是分析部分。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接