Click here to Skip to main content
15,894,017 members
Articles / Programming Languages / C#
Article

Strongly Typed Event Log Data

Rate me:
Please Sign up or sign in to vote.
4.42/5 (9 votes)
30 Oct 20055 min read 36.8K   360   19   4
A technique for using the event log as object storage.

Image 1

Background

There are different ways of storing application progress and event data. Custom log files are easy to manage, WMI is trendy and powerful, and of course there is no shortage of relational databases ready to accept your data. Another alternative is a method that's been available since Windows NT: the humble event log.

Introduction

Using event log to store custom application specific event data presents some challenges. An event log entry has a small number of discrete properties that may not be able to cover your needs. There are a couple of numeric variables, a string variable or two, and a byte array that can be bent to hold your data. You can store XML in the message field of event log, but that prevents people from using the event viewer MMC snap-in and interpreting it visually.

You probably use the intrinsic data in the event log for the following reasons:

  • The data store is ubiquitous on Windows machines.
  • The information is network accessible if permissions are configured correctly.
  • There is an existing viewer GUI, with which even non-developers are familiar.
  • It is easily programmed with the objects exposed in the .NET Framework.

On the other hand, event log entries are immutable. Your data will remain as it was written originally in the log until the entire file is purged. More annoyingly, entries are not searchable except via the old fashioned, brute-force-linear-search way.

Keeping these limitations aside, I have found the ability to store objects in the event log helpful. In this article, I'll show you how to use the raw data of an entry and .NET serialization techniques to write and read strongly typed object data using the Windows application event log, allowing you to add arbitrary amounts of easily parsed data to the event log entries.

You can get the best of both worlds: something textual for interactive users to view, and a place to store complex data that can be read programmatically.

The code

In this contrived example, the data we'll be persisting to the event log is trivial additional log information. This sort of data would fit perfectly into the existing EventLogEntry object, but I'm keeping it simple and doing it this way for illustrative purposes. The AppAlert object has two properties, an Int32 ID and a string name, and is decorated with the [Serializable] attribute. You can see the full source code in the sample project.

The serialization and the event writing code is short and easy to read. It is implemented in the sample project's cmdSave_Click event handler:

C#
// Create the custom object.
AppAlert appAlertData = 
     new AppAlert(Int32.Parse(txtID.Text), txtName.Text);

// Prepare the framework structures to save 
// the strongly-typed data.
MemoryStream   appAlertStream      = new MemoryStream();
IFormatter     appAlertFormatter   = new BinaryFormatter();

appAlertFormatter.Serialize(appAlertStream, appAlertData);
byte[] serializedAppAlertData = appAlertStream.ToArray();
appAlertStream.Close();

// The data is serialized and can be written to the log.

EventLog.WriteEntry("AppAlertData",                         // Source
   "Another app alert entered with an ID of " + txtID.Text, // Message
   EventLogEntryType.Information,                           // Event type
   0,                                                       // Event ID
   0,                                                       // Category
   serializedAppAlertData);                                 // Binary data

Basically, you're serializing the state of the new appAlertData object to a byte array in memory, which you're then passing as a parameter to the WriteEntry method of the EventLog object. Serialization traditionally occurs directly to a physical media, so the stream would ordinarily be a BinaryWriter or something of that sort, but you're doing it straight into the memory here since the event log APIs will take care of persistence to media.

You can get a glimpse of the stored data in the following snapshot of an event log entry:

Image 2

Now that you can add custom objects to the event log, you have to know how to read them. In the sample project, clicking the "Refresh" button causes the application to load the Application event log into an array and iterate over the items. When it finds an event log entry with the Source property of "AppAlertData", it adds the EventLogEntry object into the lstAppAlert ListBox's Items collection. The DrawMode property of the ListBox is set to OwnerDrawFixed, meaning you have to write the item rendering code, but don't have to worry about calculating the height of the item.

The deserialization code in the Item_Draw event is as straightforward as the serialization code:

C#
// Get the event log entry in the listbox item to draw.
EventLogEntry ele = (EventLogEntry)lstAppAlerts.Items[e.Index];

// Get the strongly typed data out of the binary data of the log entry
MemoryStream appAlertStream = new MemoryStream(ele.Data);
IFormatter appAlertFormatter = new BinaryFormatter();

AppAlert appAlert = 
    (AppAlert)appAlertFormatter.Deserialize(appAlertStream);
appAlertStream.Close();

Once that's complete, the appAlert variable contains the strongly typed object originally stored there, and can be rendered into the ListBox item. The rendering code is found in the sample project.

Conclusion

I've shown you how you can write information to the event log that doesn't clutter the GUI. You can use this information to extend the usefulness of the event log, and maybe avoid having to implement a custom logging scheme. I presented this as a technique, rather than as a library or framework, since everyone's object model is so different and there are only about 8 lines of code that will be common between implementations.

Points of interest

In the sample project, I use binary formatting. The alternative is SOAP formatting. I commented out two lines in the project (and added a reference to System.Runtime.Serialization.Formatters.Soap that's irrelevant to the project as it is) that you can uncomment to examine this feature. SOAP formatting is much more verbose than binary (668 bytes vs. 156 bytes for the "2" "App ended." data), and doesn't provide any additional benefits except being easier to parse manually in code, and cognitively while examining the event log GUI. Both of these "advantages" to SOAP serialization are pretty marginal in this case, though, especially since the viewer snap-in prevents you from reading more than 4 lines of the SOAP message at a time. If you're using the framework tools to do your work, there's no reason to avoid using binary formatting.

I have not rigorously tested the impact on performance of using this technique. On my Pentium 4 development laptop, the entire event log data store of 28,000 odd entries is queried in 2 seconds, and there is no noticeable lag in navigating or opening the event log GUI. Having said that, it's probably best to not go hog-wild and save huge objects frequently.

Another technique you could use would be to create an event log specifically for your event types, which would eliminate the need to scan irrelevant entries. I admit it's clumsy to look through all the items in the event log for a string property, as I did it in the sample project. I considered showing that here, but decided against it to keep this simple and straightforward. More information about doing this is available in this excellent CodeProject article.

Revision history

  • Oct 30th, 2005 - Initial revision.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Technical Lead
Canada Canada
I'm a graduate of the University of Toronto with a degree in zoology. I'm currently a software development manager with a large Canadian financial institution, and a passionate squash player.

I am a proud daddy to Alex and Sarah.

Comments and Discussions

 
GeneralCareful! Pin
Ri Qen-Sin17-Jan-07 10:25
Ri Qen-Sin17-Jan-07 10:25 
GeneralRe: Careful! Pin
Sean Michael Murphy17-Jan-07 10:50
Sean Michael Murphy17-Jan-07 10:50 
GeneralNice idea! Pin
DaNiko31-Oct-05 21:13
DaNiko31-Oct-05 21:13 
GeneralRe: Nice idea! Pin
Sean Michael Murphy1-Nov-05 14:34
Sean Michael Murphy1-Nov-05 14:34 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.