14

我正在开发一个从远程机器读取事件日志(应用程序)的应用程序。我在 .net 中使用 EventLog 类,然后迭代日志条目,但这非常慢。在某些情况下,某些机器有 40000 多个日志条目,并且需要数小时来遍历这些条目。完成这项任务的最佳方法是什么?.net 中是否还有其他更快的类或任何其他技术?

4

9 回答 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 之前)的事件日志格式的数据来源,包括链接文本和我记得在 codeproject.com 上包含一些 c# 代码的文章。

Vista 和 Windows Server 2008 机器使用新的 .evtx 格式,这是一种新格式,因此您不能在所有版本中使用相同的二进制解析方法。但是新的 EventLogQuery 和 EventLogReader 类非常快,您不必这样做。现在只使用内置类非常快速。

于 2009-05-29T01:34:50.097 回答
2

可以在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]");

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 秒内完成。

于 2017-08-23T08:27:57.883 回答
2

事件日志阅读器非常慢……太慢了。微软?

使用 LogParser 2.2 - 在 Internet 上搜索 C# 和 LogParser(或者您可以从命令行使用日志解析器命令)。我不想重复其他人已经贡献的工作。

我通过将日志导出为 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;
    }
于 2015-10-27T21:45:58.560 回答
0

也许 WMI 可以帮助您:

使用 C# 的 WMI

于 2009-05-27T10:26:16.497 回答
0

您是否尝试过使用 powershell 2.0 中的远程处理功能?它们允许您在远程机器上执行 cmdlet(如读取事件日志的命令)并将结果(当然作为对象)返回给调用会话。

于 2009-05-28T02:28:38.147 回答
0

您可以在那些将日志保存到文件并将其发送到您的 web 应用程序的机器上放置一个程序,我认为这会更快,因为您可以在本地执行循环,但我不知道该怎么做,所以我不能给您任何代码: (

于 2009-05-28T07:24:44.837 回答
0

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

我的技巧是使用与 PowerShells 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++;
        }
    }
}
于 2020-01-15T13:03:04.777 回答
0

我最近通过 WCF 回调接口做了这样的事情,但是我的客户通过 WCF 与服务器进行交互,并且在我的项目中添加 WCF 回调很容易,这里提供了完整的示例代码

于 2019-08-16T11:34:41.763 回答
-1

也许远程计算机可以做一点计算。所以这样你的服务器只会处理相关信息。这将是一种使用远程计算机进行光过滤的集群,服务器将进行分析部分。

于 2009-05-28T02:13:17.100 回答