Introduction
RealTime Event Log Reader is useful to read Windows event logs in realtime, i.e., Read log as soon as they are written in Windows Event Logs.
Consider a case where some other application(s) are writing event logs very fast. In this case, if we use EventLog.EntryWritten Event
to read the latest logs, then this event will be raised as soon as the entry is added to Windows event logs. Which then slows down or hang the application.
The solution to this problem is here. I am using EventLogQuery
and EventLogReader
class to read most recent events.
LogReader
class calculates the elapsed time since previous event read. Then using the filter on creation time, it reads the log written in between the elapsed time.
These records are then posted to main window to display it on grid.
On running RealTimeEventLogReader
, it will not show any logs until something is written to Windows event logs.
RealTimeEventLogReader
will not read existing logs which were there in windows event logs before running the RealTimeEventLogReader
.
- Enter the Log Name on below window and click Ok.
- After clicking on OK button, If it is a valid Log Name, the below window will be shown.
- Generate some logs by starting/ stopping some services.
- Double click on any entry in the grid.
Using the Code
Download source code here -
https://www.codeproject.com/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;
levelString = eventdetail.LevelDisplayName;
logName = eventdetail.LogName;
eventData = GetEventData(eventdetail);
}
Ctor
takes the EventRecord
object as a parameter and creates the EventLogRecord
object.
EventLogRecord
is used to display logs in Grid
.
LogReader.cs
public delegate void AddRecordDelegate(EventLogRecord record);
public AddRecordDelegate AddRecord;
AddRecordDelegate
is used to post the EventRecord
object to the main window.
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
is a thread which is used to read the event logs on a timely basis. _lastReadTime
is used to calculate the elapsed time. TimeFormatString
to format local time into the event record format. EventReaderQuery
is the query to read events based on creation time.
Thread Main Loop
private void ReadLogs()
{
while (!Stop)
{
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;
EventLogQuery eventsQuery = new EventLogQuery(LogName, PathType.LogName, query)
{ ReverseDirection = true };
EventLogReader logReader = new EventLogReader(eventsQuery);
_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);
{
PostDetail(record);
}
if (++readEventCount >= LogLimit)
{
break;
}
}
Thread.Sleep(ReadInterval);
}
}
ReadLogs
is the thread startup method. Which is used to read event logs using the EventLogQuery
and EventLogReader
.
- The above method first calculates the elapsed time since previous read and creates the query string to read events.
- Using the query string
EventLogQuery
object is created. - Using
EventLogQuery
object, events are read using EventLogReader
. - Using the
for
loop post the records using PostDetail
method.
PostDetail() Method
private void PostDetail(params EventLogRecord[] records)
{
if (AddRecord != null && records != null)
{
foreach (EventLogRecord record in records)
{
if (record != null)
{
AddRecord.BeginInvoke((EventLogRecord)record.Clone(), null, null);
}
}
}
}
The above method invokes the AddRecord
delegate. This method is handled in MainWindow.cs.
MainWindow.cs
AddRecord() Method
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
is used to maintain list of EventLogRecord
. Also used to bound to grid to display the records in grid.
Real time Event Log Reader displays recent 5000 records in grid. Once the limit is reached, it starts deleting the items from the bottom of the list. This prevents Real time Event Log Reader from memory leak.
Points of Interest
Using the EventLog.EntryWritten Event
to read the events in real time can hang the application if the event generation is too fast.
We need to use list appropriately, if we forget to clean-up older records from list then after some long time, it leads to memory leak.
History
08 May 2018 - Added a link to download source code.