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:
C#,
log4net