实时事件日志读取器






4.37/5 (11投票s)
RealTimeEventLogReader 将向您展示如何在 C# 中读取事件日志,只要它们被写入 Windows 事件日志中。
引言
RealTime Event Log Reader 可用于实时读取 Windows 事件日志,即,只要日志被写入 Windows 事件日志中,就立即读取。
考虑这样一种情况:某些其他应用程序正快速写入事件日志。在这种情况下,如果我们使用 EventLog.EntryWritten Event
来读取最新的日志,那么只要条目被添加到 Windows 事件日志中,此事件就会被触发。这会减慢应用程序的速度或导致其挂起。
此问题的解决方案就在这里。 我使用 EventLogQuery
和 EventLogReader
类来读取最近的事件。
LogReader
类计算自上次读取事件以来经过的时间。 然后,使用创建时间上的过滤器,它会读取在经过的时间内写入的日志。
然后,这些记录将发布到主窗口以在网格上显示。
运行 RealTimeEventLogReader
时,在将某些内容写入 Windows 事件日志之前,它不会显示任何日志。
RealTimeEventLogReader
将不会读取在运行 RealTimeEventLogReader
之前 Windows 事件日志中已存在的现有日志。
- 在下面的窗口中输入日志名称,然后单击“确定”。
- 单击“确定”按钮后,如果它是一个有效的日志名称,将显示以下窗口。
- 通过启动/停止某些服务来生成一些日志。
- 双击网格中的任何条目。
Using the Code
在此处下载源代码 -
https://codeproject.org.cn/KB/tips/1242641/RealTimeEventLogReader.zip
EventLogRecord.cs
public EventLogRecord(EventRecord eventdetail)
{
eventID = eventdetail.Id;
detailsXML = eventdetail.ToXml();
taskCategory = eventdetail.Task.Value;
timestamp = eventdetail.TimeCreated.Value;
source = eventdetail.ProviderName;
//level = (LogLevel)eventdetail.Level.Value;
levelString = eventdetail.LevelDisplayName;
logName = eventdetail.LogName;
eventData = GetEventData(eventdetail);
}
Ctor
将 EventRecord
对象作为参数,并创建 EventLogRecord
对象。
EventLogRecord
用于在 Grid
中显示日志。
LogReader.cs
public delegate void AddRecordDelegate(EventLogRecord record);
public AddRecordDelegate AddRecord;
AddRecordDelegate
用于将 EventRecord
对象发布到主窗口。
private Thread readerThread = null;
private DateTime _lastReadTime = DateTime.UtcNow;
private const string TimeFormatString = "yyyy-MM-ddTHH:mm:ss.fffffff00K";
private const string EventReaderQuery = "*[System/TimeCreated/@SystemTime >='{0}']";
readerThread
是一个线程,用于及时读取事件日志。_lastReadTime
用于计算经过的时间。TimeFormatString
用于将本地时间格式化为事件记录格式。EventReaderQuery
是基于创建时间读取事件的查询。
线程主循环
private void ReadLogs()
{
while (!Stop)
{
// 1. Calculate elapsed time since previous read.
double elapsedTimeSincePreviousRead = (DateTime.UtcNow - _lastReadTime).TotalSeconds;
DateTime timeSpanToReadEvents =
DateTime.UtcNow.AddSeconds(-elapsedTimeSincePreviousRead);
string strTimeSpanToReadEvents =
timeSpanToReadEvents.ToString(TimeFormatString, CultureInfo.InvariantCulture);
string query = string.Format(EventReaderQuery, strTimeSpanToReadEvents);
int readEventCount = 0;
// 2. Create event log query using elapsed time.
// 3. Read the record using EventLogReader.
EventLogQuery eventsQuery = new EventLogQuery(LogName, PathType.LogName, query)
{ ReverseDirection = true };
EventLogReader logReader = new EventLogReader(eventsQuery);
// 4. Set lastReadTime to Date.Now
_lastReadTime = DateTime.UtcNow;
for (EventRecord eventdetail = logReader.ReadEvent();
eventdetail != null; eventdetail = logReader.ReadEvent())
{
byte[] bytes = null;
if (eventdetail.Properties.Count >= 2)
{
bytes = (byte[])eventdetail.Properties[eventdetail.Properties.Count-1].Value;
}
EventLogRecord record = new EventLogRecord(eventdetail);
// 5. Post record read using event log query.
// if (parser.IsValid(temporaryRecord))
{
PostDetail(record);
}
// 6. Post only latest InternalLogLimit records,
// if result of event log query is more than InternalLogLimit.
if (++readEventCount >= LogLimit)
{
break;
}
}
Thread.Sleep(ReadInterval);
}
}
ReadLogs
是线程启动方法。 它用于使用 EventLogQuery
和 EventLogReader
读取事件日志。
- 上面的方法首先计算自上次读取以来经过的时间,并创建查询字符串以读取事件。
- 使用查询字符串创建
EventLogQuery
对象。 - 使用
EventLogQuery
对象,使用EventLogReader
读取事件。 - 使用
for
循环,使用PostDetail
方法发布记录。
PostDetail() 方法
private void PostDetail(params EventLogRecord[] records)
{
if (AddRecord != null && records != null)
{
//Return each record in the list to the viewer using AddRecord
foreach (EventLogRecord record in records)
{
if (record != null)
{
AddRecord.BeginInvoke((EventLogRecord)record.Clone(), null, null);
}
}
}
}
上面的方法调用 AddRecord
委托。 此方法在 *MainWindow.cs* 中处理。
MainWindow.cs
AddRecord() 方法
private void AddRecord(EventLogRecord record)
{
eventLogRecordList.Add(record);
toolStripStatusLabelNumCount.Text = eventLogRecordList.Count.ToString();
toolStripStatusLabelStatusString.Text = "Started";
if (eventLogRecordList.Count >= reader.LogLimit)
{
eventLogRecordList.RemoveAt(0);
}
gvLogs.FirstDisplayedScrollingRowIndex = gvLogs.RowCount - 1;
}
eventLogRecordList
用于维护 EventLogRecord
的列表。 还可以绑定到网格以在网格中显示记录。
实时事件日志读取器在网格中显示最近的 5000 条记录。 一旦达到限制,它就会开始从列表底部删除项目。 这可以防止实时事件日志读取器发生内存泄漏。
关注点
如果事件生成速度太快,则使用 EventLog.EntryWritten Event
实时读取事件可能会导致应用程序挂起。
我们需要适当地使用列表,如果我们忘记从列表中清理旧记录,那么经过很长时间后,会导致内存泄漏。
历史
2018年5月8日 - 添加了下载源代码的链接。