Nimble Coder

Adventures in Nimble Coding
posts - 76, comments - 39, trackbacks - 0

Friday, January 30, 2009

Using a delegate and Custom Appender with log4net to display live log text

log4netAppender sample Recently I needed to display the text that was sent to log4net in a TextBox in a Form. It turns out this is very easy to do using a custom appender and the AppenderSkeleton. The custom appender uses a delegate to allow the host program to define a callback function to handle the log text as necessary.

1. Create a new custom appender class

I named my appender DelegateAppender because it needed to use a delegate to pass the text to the Form.

using log4net.Core;

namespace log4net.Appender
{
    public delegate void LogTextAppend(string text);

    public class DelegateAppender : log4net.Appender.AppenderSkeleton
    {
        private LogTextAppend logTextAppend;

        public LogTextAppend LogTextMethod
        {
            get { return logTextAppend; }
            set { logTextAppend = value; }
        }

        public DelegateAppender()
        {
            logTextAppend = EmptyAppend;
        }

        private void EmptyAppend(string text)
        {
            // Do nothing
        }

        protected override void Append(LoggingEvent loggingEvent)
        {
            if (logTextAppend != null)
                logTextAppend(RenderLoggingEvent(loggingEvent));
        }
    }
}

2. Create and assign the delegate to the appender

As far as I could tell, there was no easy way to specify the delegate to use in the configuration of the DelegateAppender. Therefore I added a simple method to assign the delegate in the Form to the DelegateAppender.

public void AddStatus(string message)
{
    textBoxStatus.AppendText(message);
}

private void InitializeLogging()
{
    bool initialized = false;

    if (!log.Logger.Repository.Configured)
    {
        log4net.Config.XmlConfigurator.Configure();
        textBoxStatus.AppendText("WARNING: log4net not automatically configured. " +
            "Check AssemblyInfo.cs for - " +
            "[assembly: log4net.Config.XmlConfigurator(Watch=true)]\r\n");
    }

    foreach (log4net.Appender.IAppender appender in log.Logger.Repository.GetAppenders())
    {
        if (appender.GetType() == typeof(log4net.Appender.DelegateAppender))
        {
            log4net.Appender.DelegateAppender delegateAppender = (log4net.Appender.DelegateAppender) appender;
            // .NET 2.0+
            delegateAppender.LogTextMethod = this.AddStatus;
            // .NET 1.1
            //delegateAppender.LogTextMethod = new log4net.Appender.LogTextAppend(this.AddStatus);
            initialized = true;
        }
    }

    if (!initialized)
    {
        textBoxStatus.AppendText("ERROR: Unable to add DelegateAppender to logging!\r\n");
    }
}

3. Add the log4net configuration to app.config and AssemblyInfo.cs

The code for AssemblyInfo.cs just tells log4net to configure itself and also watch for changes.

[assembly: log4net.Config.XmlConfigurator(Watch = true)]

The app.config is as follows: 

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
 <configSections>
  <section
   name="log4net"
   type="log4net.Config.Log4NetConfigurationSectionHandler, log4net"
  />
 </configSections>

 <log4net>
  <logger name="log4netAppender.LogTestForm">
   <level value="ALL"/>
  </logger>
  <root>
   <level value="ALL" />
   <appender-ref ref="DelegateAppender" />
  </root>
  <appender
    name="DelegateAppender"
    type="log4net.Appender.DelegateAppender" >
   <layout type="log4net.Layout.PatternLayout">
    <param
     name="ConversionPattern"
     value="%m%n"
    />
   </layout>
  </appender>
 </log4net>
</configuration>

And there is a simple example of how to create a custom appender with log4net and hook it into an application.

Technorati tags: ,

posted @ Friday, January 30, 2009 12:42 PM | Feedback (4) | Filed Under [ C# ]

Powered by: