Live Capture of Log4Net Logging

I recently had to whip up a small diagnostics application for a client.  We were having some connection problems with a component so we wanted to wrap a WinForms GUI around the component and display some debugging information to try and diagnose it.

The component was already configured to do some logging using log4net.  The GUI was going to do some additional logging of status information directly in the UI.  The end result was a textbox in the GUI and a log file generated with log4net.  Not bad, but the client asked if we could log everything (specifically, the log4net output) into the GUI – i.e. a single place to review all of the log messages.

It took a little bit of searching, but I found an easy way to programmatically add a root appender.  All I needed was an object that implemented IAppender.  Since this was quick-and-dirty and I didn't have a lot of time, my solution was as follows:

The main GUI form implemented IAppender:

public partial class MainForm : Form, IAppender

This interface has a single method – DoAppend.  Implementing this interface doesn't give you all of the bells and whistle's (like PatternLayout or filtering– derive from AppenderSkeleton if you're looking for that), but since this was done in the interest of speed, a quick String.Format was all I needed:

public void DoAppend(log4net.Core.LoggingEvent loggingEvent)
{
    ReportProgress(String.Format("log4net - {0}: {1}", loggingEvent.Level.Name, loggingEvent.MessageObject.ToString()));
}

The ReportProgress method simple appends messages to a textbox in the GUI.

Finally, in my application's "main", I initialize log4net and then add the main form to the collection of root appenders:

XmlConfigurator.Configure();
 
var mainForm = new MainForm();
((log4net.Repository.Hierarchy.Hierarchy)log4net.LogManager.GetLoggerRepository()).Root.AddAppender(mainForm);    
Application.Run(mainForm);

Success!  My log4net messages now appear live in the GUI as the components logs them.

4 Comments

  • You might want to maintain a circular buffer mapped to a list instead of a simple text buffer. This would allow you to have last(n) rows of text instead of ever increasing log that will ultimately result in a crash.

  • Pretty clever solution!
    I first tried to write a UILogAppender class that threw an event for each DoAppend() call.
    But after catching the event in my form i would get 'invalid cross-thread operation' errors.
    It seems that your method prevents that from happening.

  • Ravi,

    In this case, the amount of log data generated was pretty small. For extensive logging of a large application, yes, I'd limit the log to just the most recent X items.

  • Ruud,

    Log4Net must have been doing logging on its own thread. Your event would not be running on the main UI-thread and therefore could not access the UI. You'd need to marshal the call to update your textbox via the Control.Invoke method (and Control.InvokeRequired would let you know if you needed to the Invoke to marshal the call back to the UI thread).

Comments have been disabled for this content.