[ Team LiB ] |
20.2 Programming the Event Log ServiceThe .NET Framework exposes ELS functionality through the System.Diagnotics.EventLog class; Table 20-3 summarizes the public members of the EventLog class.
In the following sections, we demonstrate how to use the EventLog class to program the ELS. The EventLog class does not expose all of the ELS functionality, and some advanced features are not available. You must use the unmanaged Windows API to gain access to the complete ELS feature set; see the Windows API documentation for details.
Many of the examples that follow demonstrate how to program the ELS of a remote computer. This functionality requires that a trust relationship is established; consult the Windows documentation for details of how to perform this task. 20.2.1 Querying the Event Log SystemThe EventLog class defines members that query the ELS for information about event logs. The static GetEventLogs method returns all of the event logs on a specified computer, represented as an array of EventLog instances. The following statements demonstrate how to use this method to obtain a list of event log names on the local computer: # C# // get the event logs installed on the local machine EventLog[] x_logs = EventLog.GetEventLogs( ); // run through the array of event logs and print out the names foreach (EventLog x_log in x_logs) { Console.WriteLine("Log Name: {0}", x_log.Log); } # Visual Basic .NET ' get the event logs installed on the local machine Dim x_logs( ) As EventLog = EventLog.GetEventLogs( ) ' run through the array of event logs and print out the names Dim x_log As EventLog For Each x_log In x_logs Console.WriteLine("Log Name: {0}", x_log.Log) Next The output these statements produce depends on the configuration of your computer; our results are below, showing that our computer has only the three default logs: Log Name: Application Log Name: Security Log Name: System We can enumerate the event logs on another computer by using the overloaded version of the GetEventLog method, which accepts the computer name as an argument, as shown below for the computer called FILESERVER: # C# // get the event logs installed on another computer EventLog[] x_logs = EventLog.GetEventLogs("FILESERVER"); # Visual Basic .NET ' get the event logs installed on another computer Dim x_logs( ) As EventLog = EventLog.GetEventLogs("FILESERVER") We can determine if a specific log exists by using the static Exists method; the following statements demonstrate how to test for the existence of a log called MyEventLog—see the Section 20.2.5 for details of how to create and delete event logs: # C# bool x_log_exists = EventLog.Exists("MyEventLog"); Console.WriteLine("Log Exists: {0}", x_log_exists); # Visual Basic .NET Dim x_log_exists As Boolean = EventLog.Exists("MyEventLog") Console.WriteLine("Log Exists: {0}", x_log_exists) The following statements determine the existence of MyEventLog on the computer called FILESERVER, using the overloaded form of the Exists method: # C# bool x_log_exists = EventLog.Exists("MyEventLog", "FILESERVER"); Console.WriteLine("Log Exists: {0}", x_log_exists); # Visual Basic .NET Dim x_log_exists As Boolean = EventLog.Exists("MyEventLog", "FILESERVER") Console.WriteLine("Log Exists: {0}", x_log_exists) 20.2.2 Using Event SourcesWe register an event source with the static CreateEventSource method; this is an overloaded method with forms that register an event source locally or on another computer. The following statements demonstrate how to register an event source named MyEventSource, associated with the Application event log on the local computer and a second event source named MyOtherEventSource associated with the System event log on the FILESERVER computer: # C# // create "MyEventSource" on the local computer EventLog.CreateEventSource("MyEventSource", "Application"); // create "MyOtherEventSource" on the FILESERVER computer EventLog.CreateEventSource("MyOtherEventSource", "System", " FILESERVER "); # Visual Basic .NET ' create "MyEventSource" on the local computer EventLog.CreateEventSource("MyEventSource", "Application") ' create "MyOtherEventSource" on the FILESERVER computer EventLog.CreateEventSource("MyOtherEventSource", "System", "FILESERVER") If you do not specify an event log name as an argument to the CreateEventSource method (by using the empty string ""), the event source will be associated with the Application log. Event sources are persistent, as we explained in Section 20.1.2 of this chapter; attempting to register an event source that already exists throws an instance of the System.ArgumentException exception class. We can check to see if an event source has been registered using the static SourceExists method; the following statements demonstrate how to use this method to ensure that our two example event sources are registered and will create them if they are not: # C# // check to see if we need to create the local event source if (!EventLog.SourceExists("MyEventSource")) { // create "MyEventSource" on the local computer EventLog.CreateEventSource("MyEventSource", "Application"); } // check to see if we need to create the remote event source if (!EventLog.SourceExists("MyOtherEventSource", "FILESERVER")) { // create "MyOtherEventSource" on the FILESERVER computer EventLog.CreateEventSource("MyOtherEventSource", "System", "FILESERVER"); } # Visual Basic .NET ' check to see if we need to create the local event source If Not EventLog.SourceExists("MyEventSource") Then ' create "MyEventSource" on the local computer EventLog.CreateEventSource("MyEventSource", "Application") End If ' check to see if we need to create the remote event source If Not EventLog.SourceExists("MyOtherEventSource", "FILESERVER") Then ' create "MyOtherEventSource" on the FILESERVER computer EventLog.CreateEventSource("MyOtherEventSource", "System", "FILESERVER") End If The static LogNameFromSourceName method determines the log with which an event source is associated, as shown by the following statements: # C# // obtain the name of the log associated with the local event source string x_log_name = EventLog.LogNameFromSourceName("MyEventSource", "."); // write out the log name Console.WriteLine(x_log_name); // obtain the name of the log associated with the remote event source x_log_name = EventLog.LogNameFromSourceName("MyOtherEventSource", "FILESERVER"); // write out the log name Console.WriteLine(x_log_name); # Visual Basic .NET ' obtain the name of the log associated with the local event source Dim x_log_name As String = EventLog.LogNameFromSourceName("MyEventSource", ".") ' write out the log name Console.WriteLine(x_log_name) ' obtain the name of the log associated with the remote event source x_log_name = EventLog.LogNameFromSourceName("MyOtherEventSource", "FILESERVER") ' write out the log name Console.WriteLine(x_log_name) Notice that unlike the other methods covered in this section, the LogNameFromSourceName method does not have separate overridden forms for dealing with local and remote computers; the local machine is specified by a period. We can remove an event source registration by using the overloaded DeleteEventSource method. The following statements demonstrate how to remove the event sources we created earlier: # C# // delete the local event source EventLog.DeleteEventSource("MyEventSource"); // delete the remote event source EventLog.DeleteEventSource("MyOtherEventSource", "FILESERVER"); # Visual Basic .NET ' delete the local event source EventLog.DeleteEventSource("MyEventSource") ' delete the remote event source EventLog.DeleteEventSource("MyOtherEventSource", "FILESERVER") Attempting to delete an event source that is not registered (or whose registration has already been removed) will throw an instance of System.ArgumentException. 20.2.3 Reading Event LogsThe first step towards reading the contents of an event log is to create a new instance of the EventLog class, specifying the name of the log we want to read from as a constructor argument. The following statements demonstrate how to create new instances of the EventLog that refer to the local Application log and the System log on the FILESERVER computer: # C# // create a new instance that refers to the local Application log EventLog x_local_log = new EventLog("Application"); // create a new instance which refers to the System log on FILESERVER EventLog x_remote_log = new EventLog("System", "FILESERVER"); # Visual Basic .NET ' create a new instance that refers to the local Application log Dim x_local_log As EventLog = New EventLog("Application") ' create a new instance which refers to the System log on FILESERVER Dim x_remote_log As EventLog = New EventLog("System", "FILESERVER") Once we have created an instance of the EventLog class, we can call the Entries property, which returns an instance of the EventLogEntryCollection class, containing the events in the log. Table 20-4 summarizes the public methods of the EventLogEntryCollection class, which implements the System.Collections.ICollection and System.Collections.IEnumerable interfaces.
The EventLogEntryCollection class represents the collection of events stored in a log, each of which is represented by an instance of the EventLogEntry class. Table 20-5 summarizes the public members of the EventLogEntry class; not all of the properties relate to ELS functionality supported by the .NET EventLog class. Consult the Windows API documentation for details of advanced ELS functionality.
The following statements demonstrate how to use the EventLog.Entries property to obtain an EventLogEntryCollection for the Application log and print out details of the events using the EventLogEntry class: # C# // create a new instance that refers to the local Application log EventLog x_local_log = new EventLog("Application"); // obtain a collection of the events through the Entries property EventLogEntryCollection x_collection = x_local_log.Entries; // write out the number of events in the log Console.WriteLine("There are {0} entries in the event log", x_collection.Count); // iterate through the entry collection and write out information // about each event in turn foreach (EventLogEntry x_entry in x_collection) { Console.WriteLine("Event Source: {0}, Event ID {1}, Event Message {2}", x_entry.Source, x_entry.EventID, x_entry.Message); } # Visual Basic .NET ' create a new instance that refers to the local Application log Dim x_local_log As EventLog = New EventLog("Application") ' obtain a collection of the events through the Entries property Dim x_collection As EventLogEntryCollection = x_local_log.Entries ' write out the number of events in the log Console.WriteLine("There are {0} entries in the event log", x_collection.Count) ' iterate through the entry collection and write out information ' about each event in turn Dim x_entry As EventLogEntry For Each x_entry In x_collection Console.WriteLine("Event Source: {0}, Event ID {1}, Event Message {2}", _ x_entry.Source, x_entry.EventID, x_entry.Message) Next 20.2.4 Writing EventsThe first step towards writing events is to create an instance of the EventLog class configured for the log and the computer that you wish to receive your event data; the following statements demonstrate how to use the overloaded EventLog constructor to create instances that refer to the Application log on the local and FILESERVER computers: # C# // create a new instance that refers to the local Application log EventLog x_local_log = new EventLog("Application"); // create a new instance that refers to the remote Application Log EventLog x_remote_log = new EventLog("Application", "FILESEVER"); # Visual Basic .NET ' create a new instance that refers to the local Application log Dim x_local_log As EventLog = New EventLog("Application") ' create a new instance that refers to the remote Application Log Dim x_remote_log As EventLog = New EventLog("Application", "FILESEVER") We can achieve the same affect by using the default EventLog constructor in conjunction with the MachineName and Log properties, as illustrated by the following statements (had we wanted to refer to the local machine we would have set the MachineName property to be a period): # C# // create a new instance that refers to the local Application log EventLog x_local_log = new EventLog( ); x_local_log.MachineName = "FILESERVER"; x_local_log.Log = "Application"; # Visual Basic .NET ' create a new instance that refers to the local Application log Dim x_local_log As EventLog = New EventLog( ) x_local_log.MachineName = "FILESERVER" x_local_log.Log = "Application" Having created the EventLog instance, we must specify the event source that we want to use when writing an event; we do this with the Source property, as the following statements show: # C# // create a new instance that refers to the local Application log EventLog x_local_log = new EventLog("Application"); // specify the event source that we'll use to record events x_local_log.Source = "MyEventSource"; # Visual Basic .NET ' create a new instance that refers to the local Application log Dim x_local_log As EventLog = New EventLog("Application") ' specify the event source that we'll use to record events x_local_log.Source = "MyEventSource" Once we have specified the computer, the event log, and the event source to use, we can use the WriteEntry method to write an event to the log; this method is overloaded with 10 different versions, which allows you to log an event with increasing levels of detail. The simplest version of the WriteEntry method accepts only the human-readable message element, whereas the most complex version accepts values for all of the event structure elements we described in Section 20.1.3. In the following statements, we write an error message to log an unexpected process-termination event to the Application log on the local computer: # C# // create a new instance that refers to the local Application log EventLog x_local_log = new EventLog( ); x_local_log.MachineName = "."; x_local_log.Log = "Application"; // specify the event source that we'll use to record events x_local_log.Source = "MyEventSource"; // define the binary data that will assist in debugging the problem byte[] x_debugging_data = new byte[] {0xCA, 0xFE}; // write the event x_local_log.WriteEntry( "MyApplication exited unexpectedly", // this is the event message EventLogEntryType.Error, // specify an error message 100, // this is the application-specific ID 200, // this is the application-specific category x_debugging_data // this is the binary data ); # Visual Basic .NET ' create a new instance that refers to the local Application log Dim x_local_log As EventLog = New EventLog( ) x_local_log.MachineName = "." x_local_log.Log = "Application" ' specify the event source that we'll use to record events x_local_log.Source = "MyEventSource" ' define the binary data that will assist in debugging the problem Dim x_debugging_data( ) As Byte = New Byte( ) {&HCA, &HFE} ' write the event x_local_log.WriteEntry( _ "MyApplication exited unexpectedly", _ EventLogEntryType.Error, _ 100, _ 200, _ x_debugging_data _ ) We specify the type of event we want to write by using a value from the System.Diagnostics.EventLogEntryType enumeration; Table 20-6 lists the defined values, which correspond to the event types detailed in Table 20-2.
20.2.5 Using Custom Event LogsYou can create custom event logs by specifying the name you wish to use with the Log property of the EventLog class. When you write the first event to the log with the WriteEntry method, the ELS will create the custom log automatically. The event source specified by the Source property will be registered and associated with the new custom log. The following statements demonstrate how to create the custom log MyCustomEventLog; ELS does not create the custom log until the WriteEntry statement is executed: # C# // create a new instance that refers to the custom log EventLog x_local_log = new EventLog( ); x_local_log.MachineName = "."; x_local_log.Log = "MyCustomEventLog"; // specify the event source that we'll use to record events x_local_log.Source = "MyCustomEventSource"; // write a log entry - the custom log will not be created until this point x_local_log.WriteEntry("MyApplication exited unexpectedly"); # Visual Basic .NET ' create a new instance that refers to the custom log Dim x_local_log As EventLog = New EventLog( ) x_local_log.MachineName = "." x_local_log.Log = "MyCustomEventLog" ' specify the event source that we'll use to record events x_local_log.Source = "MyCustomEventSource" ' write a log entry - the custom log will not be created until this point x_local_log.WriteEntry("MyApplication exited unexpectedly") Custom logs can be deleted with the Delete method defined by the EventLog class, as demonstrated by the following statements: # C# // delete the custom event log EventLog.Delete("MyCustomEventLog"); # Visual Basic .NET ' delete the custom event log EventLog.Delete("MyCustomEventLog") Use the Delete method with caution; the event log will be removed and all of the entries and event sources will be lost permanently. An instance of the System.InvalidOperationException exception is thrown by the Delete method if you attempt to delete a log that does not exist.
20.2.6 Monitoring Event LogsThe EventLog class provides an event mechanism that allows us to monitor an event log. In this section, we demonstrate how to use this feature, which relies on the .NET event delegate mechanism; consult the .NET documentation if you are unfamiliar with .NET delegates. We can register for event notification by adding an instance of the EntryWrittenEventHandler delegate to the EntryWritten event defined by the EventLog class, as demonstrated by the statements below. The delegate method signature defines the EntryWrittenEventArgs class, which makes the event that has been written available as an instance of EventLogEntry accessible through the Entry property: # C# using System; using System.Diagnostics; public class EventLogMonitor { public static void Main( ) { // create a new instance of the EventLog class EventLog x_local_log = new EventLog("MyCustomEventLog"); // create a delegate to process events from the ELS EntryWrittenEventHandler x_handler = new EntryWrittenEventHandler(MyOnEntryWrittenMethod); // add the delegate to the EventLog event x_local_log.EntryWritten += x_handler; // enable event processing x_local_log.EnableRaisingEvents = true; // wait to read a lone from the console - just to stop // the application from exiting Console.ReadLine( ); } public static void MyOnEntryWrittenMethod(object p_source, EntryWrittenEventArgs p_args) { // extract the event object from the event arguments EventLogEntry x_entry = p_args.Entry; // write out the event details Console.WriteLine("Event Source: {0}, Event ID {1}, Event Message {2}", x_entry.Source, x_entry.EventID, x_entry.Message); } } # Visual Basic .NET Imports System.Diagnostics Class EventLogMonitor Shared Sub Main( ) ' create a new instance of the EventLog class Dim x_local_log As EventLog = New EventLog("MyCustomEventLog") ' create a delegate to process events from the ELS AddHandler x_local_log.EntryWritten, AddressOf MyOnEntryWrittenMethod ' enable event processing x_local_log.EnableRaisingEvents = True ' wait to read a lone from the console - just to stop ' the application from exiting Console.ReadLine( ) End Sub Public Shared Sub MyOnEntryWrittenMethod(ByVal p_source As Object, _ ByVal p_args As EntryWrittenEventArgs) ' extract the event object from the event arguments Dim x_entry As EventLogEntry = p_args.Entry ' write out the event details Console.WriteLine("Event Source: {0}, Event ID {1}, Event Message {2}", _ x_entry.Source, x_entry.EventID, x_entry.Message) End Sub End Class Events will not be raised until the value of the EnableRaisingEvents property is set to true (C#) or True (Visual Basic .NET). The EventWritten event is raised five seconds after an entry has been added to the monitored event log; if several events have been written during the five-second period, only the last event will be signaled via the delegate.
|
[ Team LiB ] |