我正在开发一个从远程机器读取事件日志(应用程序)的应用程序。我在 .net 中使用 EventLog 类,然后迭代日志条目,但这非常慢。在某些情况下,某些机器有 40000 多个日志条目,并且需要数小时来遍历这些条目。完成这项任务的最佳方法是什么?.net 中是否还有其他更快的类或任何其他技术?
9 回答
伙计,我感觉到你的痛苦。我们在我们的应用程序中遇到了完全相同的问题。
您的解决方案有一个分支,具体取决于您正在运行的服务器版本以及您的“目标”机器正在运行的服务器版本。
如果您同时使用 Vista 或 Windows Server 2008,那么您很幸运。你应该看看System.Diagnostics.Eventing.Reader.EventLogQuery
和System.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 类非常快,您不必这样做。现在只使用内置类非常快速。
可以在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 秒内完成。
事件日志阅读器非常慢……太慢了。微软?
使用 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;
}
也许 WMI 可以帮助您:
您是否尝试过使用 powershell 2.0 中的远程处理功能?它们允许您在远程机器上执行 cmdlet(如读取事件日志的命令)并将结果(当然作为对象)返回给调用会话。
您可以在那些将日志保存到文件并将其发送到您的 web 应用程序的机器上放置一个程序,我认为这会更快,因为您可以在本地执行循环,但我不知道该怎么做,所以我不能给您任何代码: (
刚遇到同样的问题,想分享我的解决方案。它从 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++;
}
}
}
我最近通过 WCF 回调接口做了这样的事情,但是我的客户通过 WCF 与服务器进行交互,并且在我的项目中添加 WCF 回调很容易,这里提供了完整的示例代码
也许远程计算机可以做一点计算。所以这样你的服务器只会处理相关信息。这将是一种使用远程计算机进行光过滤的集群,服务器将进行分析部分。