Wednesday, 28 January 2009

Azure Event Log and log4net

I have been experimenting with Windows Azure recently for hosting a small application I wrote.  Thus far I am fairly impressed; despite a few periods of downtime and the odd bug with deployments, things seem to be stabilising fairly quickly and it’s all working well now (well I can’t complain as it’s currently free!)

Azure’s hosting platform provides a number of services which allow you to interact with the platform.  These are mostly through the Microsoft.ServiceHosting.ServiceRuntime.RoleManager class.  For example, you are able to retrieve configuration settings from the service configuration file, access local non persistent resources, and log messages to the Azure Event Log, via the RoleManager.WriteToLog method.

Messages can be copied from the log to any Azure Storage account simply by clicking a button on the configuration menu of the hosting instance:


These logs are copied to the “blobs” area of your chosen Azure Storage account (there are also tables and remote queues) and Microsoft have provided a fairly simple REST API for managing the data stored within the account.  There is also a .NET api which wraps the REST API but I am yet to look at it (I will do once I build a persistence layer for my application).

A few tools have been written for viewing the log files – Azure Storage Explorer seems to be the best that' I’ve tried, those there may be more which I’ve not found yet.  You simply put the URLs of the REST endpoints into the config file and you get a nice viewer which lets you see all the messages and delete

Now all my applications tend to standardise on log4net for logging messages, which provides configurable and customisable routing of logging messages to pretty much any target you want.  I wrote a simple log4net appender which can be used to route messages to the Azure Event Log.  Here is the source code

public class AzureAppender : AppenderSkeleton
    protected override void Append(LoggingEvent loggingEvent)
        RoleManager.WriteToLog(GetLogName(loggingEvent), loggingEvent.RenderedMessage);

    private static string GetLogName(LoggingEvent loggingEvent)
        if (loggingEvent.Level == Level.Critical)
            return EventLogNames.Critical;

        if (loggingEvent.Level == Level.Error)
            return EventLogNames.Error;

        if (loggingEvent.Level == Level.Warn)
            return EventLogNames.Warning;

        if (loggingEvent.Level == Level.Info)
            return EventLogNames.Information;

        if (loggingEvent.Level == Level.Verbose)
            return EventLogNames.Verbose;

        return EventLogNames.Error;

    private static class EventLogNames
        public const string Critical = "Critical";
        public const string Error = "Error";
        public const string Warning = "Warning";
        public const string Information = "Information";
        public const string Verbose = "Verbose";

Note that log4net has lots more log levels than Azure supports, so I just default to Error if I get a message which is not one of the matching levels.

1 comment:

Kristian J. said...

Thanks for sharing. Cheers.