Semantic Logging to Windows Event Log

Enterprise Library 6.0 has released Semantic Logging. If you don’t know about it then you should first read the excellent documentation here. SLAB (Semantic Logging  Application Block) helps you create ETW traces very easily. It provides many listeners out of box, e.g  Flat File, Rolling File, SQL DB or Azure Table. Here is a very good video to learn about it.

If you don’t know about it then I suggest you stop here and learn about it.  I am not going to repeat the information which is already described in the Book.

Ok, once you read everything about it, you fall in love and ready to use it, you will realize that there is no Window Event Log listener is provided by Unity, and there is no one talking about it. All those 2000 blogs which cut and paste the MSDN examples they just keep repeating the information already provided in Unity Book. Hence this blog post.

To create an EventLog  listener, implement a class derived from EventListener.


public class MyTraceListner : EventListener
    {
        EventLog _elog = null;

        public  MyTraceListner (string eventLogName, string source)
        {
            _elog = new EventLog(eventLogName, ".", source);
            //This code needs Admin permission. Create the Source by an install script and remove this code
            //from here.
            if (!EventLog.SourceExists(source))
            {
                EventLog.CreateEventSource(source, eventLogName);
            }
        }

        public IDisposable Subscribe(IObserver<EventEntry> observer)
        {
            return null;
        }

        protected override void OnEventWritten(EventWrittenEventArgs eventData)
        {
            switch (eventData.Level)
            {
                case EventLevel.LogAlways:
                    _elog.WriteEntry(string.Format(eventData.Message, eventData.Payload.ToArray<object>()),
                    EventLogEntryType.Information,
                    eventData.EventId);
                    break;
                case EventLevel.Critical:
                    _elog.WriteEntry(string.Format(eventData.Message, eventData.Payload.ToArray<object>()),
                    EventLogEntryType.Error,
                    eventData.EventId);
                    break;
                case EventLevel.Error:
                    _elog.WriteEntry(string.Format(eventData.Message, eventData.Payload.ToArray<object>()),
                    EventLogEntryType.Error,
                    eventData.EventId);
                    break;
                case EventLevel.Informational:
                    _elog.WriteEntry(string.Format(eventData.Message, eventData.Payload.ToArray<object>()),
                    EventLogEntryType.Information,
                    eventData.EventId);
                    break;
                case EventLevel.Verbose:
                    _elog.WriteEntry(string.Format(eventData.Message, eventData.Payload.ToArray<object>()),
                    EventLogEntryType.Information,
                    eventData.EventId);
                    break;
                case EventLevel.Warning:
                    _elog.WriteEntry(string.Format(eventData.Message, eventData.Payload.ToArray<object>()),
                    EventLogEntryType.Warning,
                    eventData.EventId);
                    break;
            }
        }
    }

Here is the code for Event Source.

 public class MyEventLog : EventSource
    {
        public static MyEventLog Log = new MyEventLog();

        [Event(200, Level = EventLevel.Critical, Message = "Error: {0} StackTrace: {1} InnerMessage: {2}")]
        public void LogException(string message, string stackTrace = null, string innerMessage = null)
        {
            if (this.IsEnabled(EventLevel.LogAlways, EventKeywords.None))
            {
                this.WriteEvent(200, message, stackTrace, innerMessage);
            }
        }

        [Event(100, Level = EventLevel.Verbose, Message = "Application Starting: {0}")]
        public void ApplicationStarting(string message)
        {
            if (this.IsEnabled())
            {
                this.WriteEvent(100, message);
            }
        }
    }

Here is the code to create the listeners and connect EventSource together. To have this code running you need to reference Microsoft.Practices.EnterpriseLibrary.Logging, SemanticLogging, Common etc.

using Microsoft.Practices.EnterpriseLibrary.SemanticLogging;
using System;
using System.Diagnostics;
using System.Diagnostics.Tracing;
using System.Linq;

class Program
    {
        static void Main(string[] args)
        {

            EventListener rollingFileListner = RollingFlatFileLog.CreateListener(@"trace.txt", 100, "d", 0, 0);
            EventListener consoleEventListner = ConsoleLog.CreateListener(); //Console
            MyTraceListner myEventTraceListner = new MyTraceListner("MyApplication", "mySource"); //EventLog

            //Register all the listners for EventSource
            consoleEventListner.EnableEvents(MyEventLog.Log, EventLevel.Informational | EventLevel.Verbose);
            rollingFileListner.EnableEvents(MyEventLog.Log, EventLevel.Informational);
            myEventTraceListner.EnableEvents(MyEventLog.Log, EventLevel.LogAlways);

            MyEventLog.Log.LogException("This is a message to be logged", "This will the stack trace", "This is the inner message");
            MyEventLog.Log.ApplicationStarting(DateTime.Now.ToLongDateString());

            Console.Read();

        }
    }

I spent some time searching EventLog writer for Semantic Logging but could not find anything. I hated the manual mapping, I have to do for EventLogEntryType to EventLevel. And I am still not sure, why Unity and Semantic Logging does not have a default Windows EventLog writer.  HTH.

Advertisements

One thought on “Semantic Logging to Windows Event Log

  1. One of the reader reported that they have error for eventData.Payload.ToArray() statement. This may be because of different version of mscorlib version. However, you can easily convert readonly collection to an array as follows:

    string[] arr = new string[eventData.Payload.Count];
    eventData.Payload.CopyTo(arr, 0);

    and then write

    _elog.WriteEntry(string.Format(eventData.Message, arr), EventLogEntryType.Error, eventData.EventId);

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s