Quantcast
Channel: beefycode - log4net
Viewing all articles
Browse latest Browse all 11

Extension Methods for Deferred Log4Net Message Formatting

$
0
0

In a recent post I described some initial impressions of the MS Live Labs Simple Logging Framework (SLF).  One of the things I really like about SLF is the use of lambas as a way to defer execution of potentially slow or unchecked message formatting code.  I also railed on the idea of creating a completely new effort when log4net is an active open-source project.

So, here I am putting my money where my mouth is: I've created some extension methods for instances of ILog that accept lambdas - now if you use log4net in a C# 3.0+ environment, you can defer message formatting as easily as you can in SLF.  The code is quite simple:

using log4net;
namespace Log4NetExtensions
{    public static class Log4NetExtensionMethods    {        public static void Debug( this ILog log, Func<string> formattingCallback )        {            if( log.IsDebugEnabled )            {                log.Debug( formattingCallback() );            }        }        public static void Info( this ILog log, Func<string> formattingCallback )        {            if( log.IsInfoEnabled )            {                log.Info( formattingCallback() );            }        }        public static void Warn( this ILog log, Func<string> formattingCallback )        {            if( log.IsWarnEnabled )            {                log.Warn( formattingCallback() );            }        }        public static void Error( this ILog log, Func<string> formattingCallback )        {            if( log.IsErrorEnabled )            {                log.Error( formattingCallback() );            }        }        public static void Fatal( this ILog log, Func<string> formattingCallback )        {            if( log.IsFatalEnabled )            {                log.Fatal( formattingCallback() );            }        }     }
} 

Each method of the ILog interface gets its own override in the form of an extension method.  The method accepts a Func<string> that allows you to capture log message formatting in a lamba expression, and hence defer its execution until absolutely necessary (or avoid it altogether).  Here are some quick and dirty unit tests to demonstrate the basic use and functionality:

using NUnit.Framework;
namespace Log4NetExtensions.Tests
{    [TestFixture]    public class Log4NetExtensionTests    {        log4net.ILog Log;        log4net.Appender.MemoryAppender appender;        [TestFixtureSetUp]        public void FixtureSetUp()        {            Log = log4net.LogManager.GetLogger( System.Reflection.MethodBase.GetCurrentMethod().DeclaringType );            appender = new log4net.Appender.MemoryAppender             {                Name = "Memory Appender",                Threshold = log4net.Core.Level.Debug            };            log4net.Config.BasicConfigurator.Configure( appender );                                }        [SetUp]        public void TestSetUp()        {            appender.Clear();                        log4net.Core.LoggingEvent[] events = appender.GetEvents();            Assert.That( 0 == events.Length, "failed to clear appender of log events" );            Log.Logger.Repository.Threshold = log4net.Core.Level.Debug;        }        [Test]        public void LogViaLambdaTest()        {            Log.Debug( () => "Hello World!" );            log4net.Core.LoggingEvent[] events = appender.GetEvents();                                    Assert.That( 1 == events.Length, "failed to log via lamba" );            Assert.That(                 StringComparer.CurrentCulture.Equals(                     "Hello World!",                     events[ 0 ].RenderedMessage                                   ),                "rendered message does not match (via lambda)"            );        }        [Test]        public void LogWithLocalVariableReference()        {            string value = "World!";            Log.Debug( () => "Hello " + value );            log4net.Core.LoggingEvent[] events = appender.GetEvents();            Assert.That( 1 == events.Length, "failed to log with local variable reference" );            Assert.That(                StringComparer.CurrentCulture.Equals(                    "Hello World!",                    events[ 0 ].RenderedMessage                ),                "rendered message does not match (local variable reference)"            );        }        [Test]        public void LambdaIsNotEvaluatedAtInactiveLogLevel()        {                        Log.Logger.Repository.Threshold = log4net.Core.Level.Error;                     bool evaluated = false;            Log.Debug( () =>                 {                     evaluated = true;                    return "Hello World!";                }            );            Assert.That( ! evaluated, "lamba was evaluated at inactive log level" );            Log.Error( () =>                {                    evaluated = true;                    return "Hello World!";                }            );            Assert.That( evaluated, "lamba was not evaluated at active log level" );        }    }
}

Play with it, see if you like it.  I will to.  Any suggestions or comments are encouraged.  If there is enough interest I'll see about submitting the extensions to the apache project.


Viewing all articles
Browse latest Browse all 11

Trending Articles