Hiding loggers implementations using Unity

Loggers are one of most popular examples about interfaces for sure. And there are a lot of implementations of loggers. Some implementations are simple and yet powerful, some implementations may be more complex. All we have to is to select implementation we need and integrate it to our application. It seems like good idea at first place but as soon as we need to switch from one implementation to another we discover nasty dependencies we have to change in all places where we are logging. Let’s see how to avoid these dependencies.

Analysis

To keep our application independent from logger implementation we need an interface that all our loggers will use. Our own loggers can implement our interface directly and for third-party loggers we can write wrapper classes that implement our interface. This way or other we logger interface.

Besides errors we may want to write also other messages to error log. We may need informative messages, warnings and debugging messages. To support different message types we need an enumerator.

Design

Our analysis gave us two objects: interface for loggers and enumerator for log message types. Our logger class looks like this.

ILogger interface

In code we have ILogger interface and LogEntryType enumerator.

public interface ILogger
{
   
void Log(LogEntryType type, string
message);
   
void Log(Exception
exception);
}

public enum LogEntryType
{
    Info,
    Warning,
    Error
}

LogEntryType is very simple here because it is for example purposes. In real life this enum may be way longer than here. Good example is TraceSeverity enum from my blog post SharePoint: Writing messages to ULS (Unified Logging System).

Implementing ILogger

Let’s create now two logger implementations. One of these classes is our own logger class and the other one will be wrapper for log4net logger.

DebugLogger

DebugLogger is simple logger that writes all log messages to console. It does nothing special – it writes all the output to debug window.

public class DebugLogger : ILogger
{
   
public void Log(LogEntryType entryType, string
message)
    {
       
var
logMessage = GetLogMessage(entryType, message);
       
Debug
.WriteLine(logMessage);
    }

   
public void Log(Exception
ex)
    {
       
var logMessage = GetLogMessage(LogEntryType
.Error, ex.ToString());
       
Debug
.WriteLine(logMessage);
    }

   
private string GetLogMessage(LogEntryType entryType, string
message)
    {
       
var messageBuilder = new StringBuilder
();
        messageBuilder.Append(DateTime.Now.ToLongTimeString());
        messageBuilder.Append(
" "
);
        messageBuilder.Append(
Enum.GetName(typeof(LogEntryType
), entryType));
        messageBuilder.Append(
" "
);
        messageBuilder.Append(message);
       
return messageBuilder.ToString();
    }
}

Output of DebugLogger is shown on following screenshot.

Debug logger output

Log4NetLogger

Log4NetLogger is simple wrapper class. It only writes messages to log4net log. All other details are handled by log4net.

public class Log4NetWrapper : ILogger
{
   
private static readonly ILog log = LogManager.GetLogger(typeof(Log4NetWrapper
));

   
static
Log4NetWrapper()
    {
       
XmlConfigurator
.Configure();
    }

   
public void Log(LogEntryType entryType, string
message)
    {
       
lock
(log)
        {
           
switch
(entryType)
            {
               
case LogEntryType
.Error:
                    log.Error(message);
                   
break
;
               
case LogEntryType
.Warning:
                    log.Warn(message);
                   
break
;
               
default
:
                    log.Info(message);
                   
break
;
            }
        }
    }

   
public void Log(Exception
ex)
    {
       
lock (log)
        {
            log.Error(ex);
        }
    }
}

In the case of file output we get result like this.

log4net wrapper output

Breaking dependencies

Now it’s time to add logging support to our application. All logging clients must see only ILogger interface and LogEntryType enum. Plus one thing more – they have to know how to get logger. We will use Unity as IoC container. We want to keep information about mappings in application configuration file. To make unity read this configuration we need some place where we can initialize Unity. Look at Main() method (and Unity configuration) from my blog entry Unity and singletons (it’s not long). Now, if we need some logging we can ask logger simply by writing the following code.

var logger = container.Resolve<ILogger>();

To keep Unity logic away from your classes you can use some wrapper class that uses Unity IoC container internally. Also it is possible to write generic wrapper for IoC containers so your code knows only one concrete IoC wrapper class. In this case IoC implementation details are hidden for your client code.

Gunnar Peipman

Gunnar Peipman is ASP.NET, Azure and SharePoint fan, Estonian Microsoft user group leader, blogger, conference speaker, teacher, and tech maniac. Since 2008 he is Microsoft MVP specialized on ASP.NET.

    9 thoughts on “Hiding loggers implementations using Unity

    • April 21, 2009 at 10:21 am
      Permalink

      By doing this, your log4net logger will only be linked to the Log4NetWrapper class and log4net filters won’t work.

    • April 21, 2009 at 10:31 am
      Permalink

      Log4NetWrapper is the only point in *MY* code where something really knows about log4net. All logic must be carried out by this class.

      As you can see I have pretty simple and thin interface for logging and I can easily change implementation of logger or logging logic.

    • August 4, 2009 at 1:38 pm
      Permalink

      DUDE – WHY DID U PUT LOCK in your code?
      this is a huge mistake and has massive impact on performance!
      Log4net is thread safe by design and you don’t have to use any thread safe code when accessing it!
      Any calls to the logger!

      Please – do not use it.

    • August 4, 2009 at 1:48 pm
      Permalink

      Sorry, my bad – I was bad code copy-paste gangsta again. I try to be better in (near) future :)

    • August 6, 2009 at 1:43 pm
      Permalink

      Reading it again, i was a bit… angry… sorry :)

    • August 6, 2009 at 2:01 pm
      Permalink

      No problem, I like angry people and heavy metal :)

    • March 5, 2010 at 10:33 pm
      Permalink

      So you lost the ability to config the logger, everything now from Log4NetWrapper, too bad.

    • March 6, 2010 at 8:00 pm
      Permalink

      micro, you don’t lose ability to conf the logger because configuration is in web.config or app.config file. There is no way to make specifics of concrete logger visible in classes where these specifics are not welcome.

    • June 20, 2011 at 7:41 pm
      Permalink

      Hiding loggers implementations using unity.. May I repost it? :)

    Leave a Reply

    Your email address will not be published. Required fields are marked *