January 27, 2021
Hot Topics:

Building a Logging Object in .NET

  • By Mark Strawmyer
  • Send Email »
  • More Articles »

Creating the Logging Object to Write to the Event Log

The .NET Framework includes classes for interfacing with the Windows Event Log. The classes are located in the System.Diagnostics namespace. The classes allow you to write to any of the existing log locations, or it allows you to create your own Event Log. There are different message types that can be logged to the event log, which is where I got the definition of the types that I used (informational, failure, warning, and error).

It is important to note that the Event Log was designed to hold information about normal application errors. It is designed to hold items of a more catastrophic system level. In the course of normal application errors it should be logged to another location such as a file or a database.

Below we'll create an object that extends our Log base class and that uses the Event log classes in the System.Diagnostics namespace to write a message to the event log.

Sample Event Logging Class

using System;using System.Diagnostics;using System.Text;namespace CodeGuru.ErrorLog.Logs{  /// <remarks>  /// Log messages to the Windows Event Log.  /// </remarks>  public class EventLog : Log  {   // Internal EventLogName destination value   private string _EventLogName = "";   /// <value>Get or set the name of the destination log</value>   public string EventLogName   {     get { return this._EventLogName; }     set { this._EventLogName = value; }   }   // Internal EventLogSource value   private string _EventLogSource;      /// <value>Get or set the name of the source of entry</value>   public string EventLogSource      {     get { return this._EventLogSource; }     set { this._EventLogSource = value; }   }   // Internal MachineName value   private string _MachineName = "";   /// <value>Get or set the name of the computer</value>   public string MachineName   {     get { return this._MachineName; }     set { this._MachineName = value; }   }   /// <summary>   /// Constructor   /// </summary>   public EventLog()   {     this.MachineName = ".";     this.EventLogName = "MyEventLog";     this.EventLogSource = "MyApplication";   }   /// <summary>   /// Log an exception.   /// </summary>   /// <param name="Message">Exception to log.</param>   /// <param name="Severity">Error severity level.</param>   public override void RecordMessage(Exception Message,              Log.MessageType Severity)   {     this.RecordMessage(Message.Message, Severity);   }   /// <summary>   /// Log a message.   /// </summary>   /// <param name="Message">Message to log.</param>   /// <param name="Severity">Error severity level.</param>   public override void RecordMessage(string Message,             Log.MessageType Severity)   {     StringBuilder message = new StringBuilder();     System.Diagnostics.EventLog eventLog =             new System.Diagnostics.EventLog();              // Create the source if it does not already exist     if( !System.Diagnostics.EventLog.SourceExists(       this._EventLogSource) )     {       System.Diagnostics.EventLog.CreateEventSource(          this._EventLogSource, this._EventLogName);     }     eventLog.Source = this._EventLogSource;     eventLog.MachineName = this._MachineName;              // Determine what the EventLogEventType should be      // based on the LogSeverity passed in     EventLogEntryType type = EventLogEntryType.Information;     switch(Severity.ToString().ToUpper())     {      case "INFORMATIONAL":         type = EventLogEntryType.Information;         break;      case "FAILURE":         type = EventLogEntryType.FailureAudit;         break;      case "WARNING":         type = EventLogEntryType.Warning;         break;      case "ERROR":         type = EventLogEntryType.Error;         break;     }         message.Append(Severity.ToString()).Append(",").Append(              System.DateTime.Now).Append(",").Append(Message);     eventLog.WriteEntry(message.ToString(), type);   }  }}

Building the Logger

Now to tie it all together we need to create our logger object to interact with the individual log classes. The sample code is given below. An item of note is how the set accessor method of the LogType property results in the appropriate log object being created. The actual RecordMessage methods do nothing more than call the appropriate method on the desired log class.

The actual object used to do the logging is declared of type Logs.Log. This will allow us to create and use any objects that extend Log as its base class.

Sample Logging Class

using System;namespace CodeGuru.ErrorLog{  /// <remarks>  /// Managing class to provide the interface for and control   /// application logging.  It utilizes the logging objects in   /// ErrorLog.Logs to perform the actual logging as configured.    /// </remarks>  public class Logger  {   /// <value>Available log types.</value>   public enum LogTypes   {       /// <value>Log to the event log.</value>     Event = 1,     /// <value>Log to a file location.</value>     File = 2   }   // Internal logging object   private Logs.Log _Logger;   // Internal log type   private LogTypes _LogType;   /// <value></value>   public LogTypes LogType   {     get { return this._LogType; }     set      {      // Set the Logger to the appropriate log when      // the type changes.      switch( value )      {         case LogTypes.Event:         this._Logger = new Logs.EventLog();            break;        default:         this._Logger = new Logs.FileLog();         break;      }     }   }   /// <summary>   /// Constructor   /// </summary>   public Logger()   {     this.LogType = LogTypes.File;   }   /// <summary>   /// Log an exception.   /// </summary>   /// <param name="Message">Exception to log.</param>   /// <param name="Severity">Error severity level.</param>   public void RecordMessage(Exception Message, Logs.Log.MessageType Severity)   {     this._Logger.RecordMessage(Message, Severity);   }   /// Log a message.   /// </summary>   /// <param name="Message">Message to log.</param>   /// <param name="Severity">Error severity level.</param>   public void RecordMessage(string Message,                              Logs.Log.MessageType Severity)   {     this._Logger.RecordMessage(Message, Severity);   }  }}

Using the Logger

Now that we've built our logger object that we'll use to do all of the logging and its supporting log objects, let's give it a try. The example below should result in a file c:\mylog.txt being written and an MyEventLog being added to the Windows Event Log.

Sample Logger Usage

Logger logger = new Logger();         // Log to a file (default settings)logger.RecordMessage("Testing", Logs.Log.MessageType.Error);logger.RecordMessage(new Exception("My test exception"),      Logs.Log.MessageType.Error);// Log to the event loglogger.LogType = Logger.LogTypes.Event;logger.RecordMessage("Testing", Logs.Log.MessageType.Error);logger.RecordMessage(new Exception("My test exception"),      Logs.Log.MessageType.Error);

Possible Enhancements

Now we have an object that can be used for logging information and errors. There are all sorts of enhancements that could make this even more valuable. Here are some ideas that you can consider for yourself.

  • Create additional log objects to log to locations such as a database or send an email to a desired address.
  • Setup the logger to have a backup logging location in the event that the primary location fails.
  • Setup the logger to log to multiple locations simultaneously depending upon the severity of the error. This would allow you the capability to log informational types of messages to a place other than the event log.
  • Setup the logger to read the logging configuration from a configuration file of some sort. Have the logger configure the appropriate logging location based on the contents of the configuration instead of the current hard coding.

Future Columns

The next column is yet to be determined. It is likely that it will be something dealing with COM Interop. If you have something in particular that you would like to see explained here you could reach me at mstrawmyer@crowechizek.com.

About the Author

Mark Strawmyer, MCSD, MCSE (NT4/W2K), MCDBA is a Senior Architect of .NET applications for large and mid-size organizations. Mark is a technology leader with Crowe Chizek in Indianapolis, Indiana. He specializes in architecture, design and development of Microsoft-based solutions. You can reach Mark at mstrawmyer@crowechizek.com.

# # #

Page 2 of 2

This article was originally published on February 19, 2003

Enterprise Development Update

Don't miss an article. Subscribe to our newsletter below.

Thanks for your registration, follow us on our social networks to keep up-to-date