Your application might have produced many entries in the event log. To perform an analysis of how the application operated, how many errors were encountered, and so on, you need to be able to perform a search through all of the entries in an event log. Unfortunately, there are no good built-in search mechanisms for event logs.
You will eventually have to sift through all the entries your
application writes to an event log in order to find the entries that
allow you to perhaps fix a bug or improve your
application’s security system. Unfortunately, there
are no good search mechanisms for event logs. This recipe contains an
EventLogSearch
class, which contains many static
methods allowing you to search for entries in an event log based on a
criterion. In addition, this search mechanism allows complex searches
involving multiple criteria to be performed on an event log at one
time. The code for the EventSearchLog
class
is:
using System; using System.Collections; using System.Diagnostics; public sealed class EventLogSearch { private EventLogSearch( ) {} // Prevent this class from being instantiated. public static EventLogEntry[] FindTimeGeneratedAtOrBefore( IEnumerable logEntries, DateTime timeGeneratedQuery) { ArrayList entries = new ArrayList( ); foreach (EventLogEntry logEntry in logEntries) { if (logEntry.TimeGenerated <= timeGeneratedQuery) { entries.Add(logEntry); } } EventLogEntry[] entriesArray = new EventLogEntry[entries.Count]; entries.CopyTo(entriesArray); return (entriesArray); } public static EventLogEntry[] FindTimeGeneratedAtOrAfter( IEnumerable logEntries, DateTime timeGeneratedQuery) { ArrayList entries = new ArrayList( ); foreach (EventLogEntry logEntry in logEntries) { if (logEntry.TimeGenerated >= timeGeneratedQuery) { entries.Add(logEntry); } } EventLogEntry[] entriesArray = new EventLogEntry[entries.Count]; entries.CopyTo(entriesArray); return (entriesArray); } }
Other searchable criteria can be added to this class by following the same coding pattern for each search method. For instance, the following example shows how to add a search method to find all entries that contain a particular username:
public static EventLogEntry[] FindUserName(IEnumerable logEntries, string userNameQuery) { ArrayList entries = new ArrayList( ); foreach (EventLogEntry logEntry in logEntries) { if (logEntry.UserName == userNameQuery) { entries.Add(logEntry); } } EventLogEntry[] entriesArray = new EventLogEntry[entries.Count]; entries.CopyTo(entriesArray); return (entriesArray); }
The methods shown in Table 6-2 list other search methods that could be included in this class and describe which property of the event log entries they search on. (All of these methods are implemented on the code for this book, which can be found at http://www.oreilly.com/catalog/csharpckbk.)
Table 6-2. Other possible search methods
The FindCategory
method can be overloaded to
search on either the category name or category number.
The following method makes use of the
EventLogSearch
methods to find and display entries
that are marked as Error
log
entries:
public void FindAnEntryInEventLog( ) { EventLog Log = new EventLog("System"); EventLogEntry[] entries = EventLogSearch.FindEntryType(Log.entries, EventLogEntryType.Error); foreach (EventLogEntry Entry in entries) { Console.WriteLine("Message: " + Entry.Message); Console.WriteLine("EventID: " + Entry.EventID); Console.WriteLine("Category: " + Entry.Category); Console.WriteLine("EntryType: " + Entry.EntryType.ToString( )); Console.WriteLine("Source: " + Entry.Source); } }
The following method finds and displays entries generated at or after
8/24/2002, are marked as Error
type logs, and
contain an event ID of 7000
:
public void FindAnEntryInEventLog( ) { EventLog log = new EventLog("System"); EventLogEntry[] entries = EventLogSearch.FindTimeGeneratedAtOrAfter(log.entries, DateTime.Parse("8/24/2002")); entries = EventLogSearch.FindEntryType(entries, EventLogEntryType.Error); entries = EventLogSearch.FindEventID(entries, 7000); foreach (EventLogEntry entry in entries) { Console.WriteLine("Message: " + entry.Message); Console.WriteLine("EventID: " + entry.EventID); Console.WriteLine("Category: " + entry.Category); Console.WriteLine("EntryType: " + entry.EntryType.ToString( )); Console.WriteLine("Source: " + entry.Source); } }
Note that this search mechanism can search within only one event log at a time.
To illustrate how searching works, let’s assume that
you are using the FindEventID
method to search on
the EventID
. Initially, you would call the
FindEventID
search method, passing in a collection
that implements the IEnumerable
interface, such as
the EventLogEntryCollection
collection (that
contains all entries in that event log) or an array of
EventLogEntry
objects. The
EventLogEntryCollection
collection is returned by
the Entries
property of the
EventLog
class. The FindEventID
method will return an array of EventLogEntry
objects that match the search criteria (the value passed in to the
second argument of the FindEventID
method).
The real power of this searching method design is that the initial
search on the EventLogEntryCollection
returns an
array of EventLogEntry
objects. This
EventLogEntry
array may then be passed back into
another search method to be searched again, effectively narrowing
down the search query. For example, the
EventLogEntry
array returned from the
FindEventID
method may be passed into another
search method such as the FindEntryType
method to
narrow down the search to all entries that are possibly informational
entry types.