How do I create an asynchronous wrapper for log4net?

This is how I do it:

Task.Factory.StartNew(() => log.Info("My Info"));

That way log4net performs logging on a separate thread, asynchronously...

BTW, Task class is in System.Threading.Tasks namespace.


Just wanted to provide my complete solution for reference. Couple of important items, the FixFlags let you capture the thread that's actually doing the logging. The Blocking Collection is in the ReactiveExtensions. The jist here is that your forwarding appender handles the Asynchronous stuff and then just forwards on the LoggingEvent to a standard Log4Net appender, which lets Log4Net do all of the things that it's good at. No re-inventing the wheel.

/// <summary>
/// Provides an extension for the log4net libraries to provide ansynchronous logging capabilities to the log4net architecture
/// </summary>
public class AsyncLogFileAppender : log4net.Appender.ForwardingAppender
{
    private static int _asyncLogFileAppenderCount = 0;
    private readonly Thread _loggingThread;
    private readonly BlockingCollection<log4net.Core.LoggingEvent> _logEvents = new BlockingCollection<log4net.Core.LoggingEvent>();

    protected override void Append(log4net.Core.LoggingEvent loggingEvent)
    {
        loggingEvent.Fix = FixFlags.ThreadName;
        _logEvents.Add(loggingEvent);
    }

    public AsyncLogFileAppender()
    {

        _loggingThread = new Thread(LogThreadMethod) { IsBackground = true, Name = "AsyncLogFileAppender-" + Interlocked.Increment(ref _asyncLogFileAppenderCount), };
        _loggingThread.Start();
    }

    private void LogThreadMethod()
    {
        while (true)
        {
            LoggingEvent le = _logEvents.Take();
            foreach (var appender in Appenders)
            {
                appender.DoAppend(le);
            }
        }
    }
}

Then, in your log4net.xml you setup the appenders thusly

<!-- Standard form output target location and form -->
<appender name="StandardAppender" type="TSUIC.Logging.AsyncLogFileAppender">
<appender-ref ref="StandardAppenderSync" />
</appender>

<appender name="StandardAppenderSync" type="log4net.Appender.RollingFileAppender">
    <!-- The standard pattern layout to use -->
    <file value="log\Log_" />
    <appendToFile value="true" />
    <rollingStyle value="Date" />
    <maxSizeRollBackups value="-1" />
    <maximumFileSize value="5GB" />
    <lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
    <staticLogFileName value="false" />
    <datePattern value="yyyyMMdd'.txt'" />
    <layout type="log4net.Layout.PatternLayout">
        <conversionPattern value="%date [%thread] %-5level %logger - %message%newline" />
    </layout>
</appender>

Update:

If you want to use context in log4net like "log4net.ThreadContext.Properties["CustomColumn"]"

Then you need to update above code like

loggingEvent.Fix = FixFlags.All;

If you go to the log4net website, you can find some examples, at least one of which is an asynchronous Appender.

http://logging.apache.org/log4net/release/example-apps.html

Note that I have not used any of these examples, so I cannot vouch for them one way or the other.

Here is a link to the actual asynchronous appender from the log4net Examples area in their code repository:

http://svn.apache.org/viewvc/logging/log4net/trunk/examples/net/2.0/Appenders/SampleAppendersApp/cs/src/Appender/AsyncAppender.cs?view=markup

I looked at it briefly, and it apparently acts as a wrapper around one or more "conventional" Appenders. On each logging request (containing one or more LoggingEvent objects), a ThreadPool thread is used to forward the LoggingEvents to the list of wrapped Appenders.

Tags:

C#

Log4Net