A Façade for Simple and Framework Independent Logging in C#

Logging is an important aspect of every application, but you probably don't like to have dependencies on a specific logging framework all over the place. This logging façade provides you with a common interface that decouples the logging framework of your choice from your code. Basically, a façade just provides you with a common interface that decouples the used logging framework from your code. The ILogger is the facade. Behind the scenes, a framework of your choice is used it.

During the initialization of your application, you will have to specify the logger implementation that is supposed to be used. This might happen declaratively or directly in code. Here’s the initialization code from NetDrives, which makes a logger available through the IOC container. 

Note that I’m registering a ConsoleLogger for debug builds, while release builds write into a log file. These are completely different classes, but it doesn’t matter - they both implement the ILogger interface:

//init IOC container builder
var builder = new ContainerBuilder();

//register single logger instance
ILogger logger;

#if (DEBUG)
  logger = new ConsoleLogger();
#else
  logger = BitFactoryLogger.CreateSingleFileLogger(AppUtil.LogFile);
#endif

//register logger
builder.Register(logger).As<ILogger>();

I prefer to initialize and access my logger through an IOC container, but you can do it however you like. If you’re lacking a place to make your ILogger globally accessible, you can use the static LoggerService class:

public void InitApp()
{
  //create a file logger (use BitFactory facade)
  string logFile = @"C:\MyLogFile.txt";
  ILogger logger = BitFactoryLogger.CreateSingleFileLogger(logFile);

  //register as globally used logger
  LoggerService.SetLogger(logger);
}

private void Foo()
{
  try
  {
    DoSomethingWrong();
  }
  catch(Exception e)
  {
    //get registered logger and log exception
    ILogger logger = LoggerService.Logger;
    logger.Log(e);
  }
} 
A nice thing about LoggerService: It always guarantees you a valid ILogger instance. If no logger is set, it just falls back to a NullLogger implementation that does not create any output at all. Here’s the implementation:

namespace Hardcodet.Util.Logging
{
  /// <summary>
  /// Provides a global repository for a given <see cref="ILogger"/>
  /// instance. This class ensures that the <see cref="Logger"/>
  /// property is never nullo - in case no logger is defined, it
  /// automatically installs a <see cref="NullLogger"/>
  /// instance.
  /// </summary>
  public static class LoggerService
  {
    private static ILogger logger = new NullLogger();

    /// <summary>
    /// Gets the installed <see cref="ILogger"/> implementation.
    /// </summary>
    /// <remarks>This property always returns a valid
    /// logger.</remarks>
    public static ILogger Logger
    {
      get { return logger; }
    }

    /// <summary>
    /// Installs a given logger or resets the <see cref="Logger"/>
    /// to a <see cref="NullLogger"/> instance if the
    /// <paramref name="loggerImplementation"/> is a null
    /// reference.
    /// </summary>
    /// <param name="loggerImplementation">The logger to be
    /// used globally, or a null reference in order to reset
    /// the service.</param>
    public static void SetLogger(ILogger loggerImplementation)
    {
      logger = loggerImplementation ?? new NullLogger();
    }
  }
} 
In case you want to use another logging framework (e.g., NLog or Log4Net), creating a new façade is very easy by implements ILogger interface directly.


Vikash Chauhan

C# & .NET experienced Software Engineer with a demonstrated history of working in the computer software industry.

Post a Comment

Previous Post Next Post

Contact Form