Avoiding the use of static variables when using log4net

The typical usage for log4net is to define static variable as follows:

public class FileRegistratorJob : IJob
{
private static readonly ILog _log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);

public FileRegistratorJob()
{
}

public void Execute(IJobExecutionContext context)
{
try
{
// do something here
_logger.Debug("Job completed!");

}
catch (Exception ex)
{
_logger.Error("An error occured", ex);
}
}
}

The use of this static variable _log bothers me, as I tend to avoid using static variables whenever I can. I want something that works nicely with my inversion of control container (StructureMap), and so I want my logging mechanism to be injected instead of hardcoded like this.

The solution is to first create a logging interface that contains all the logging operations:

public interface ILogger

void Debug(string message);
void Debug(string message, Exception ex);
void Info(string message);
void Info(string message, Exception ex);
void Warn(string message);
void Warn(string message, Exception ex);
void Error(string message);
void Error(string message, Exception ex);
void Fatal(string message);
void Fatal(string message, Exception ex);
}

 

Then we create the actual implementation for it that uses log4net to do the logging:

public class Log4NetLogger : ILogger
{
private readonly ILog _log;

/// <summary>
/// Constructor.
/// </summary>
/// <param name="type"></param>
public Log4NetLogger(Type type)
{
_log = LogManager.GetLogger(type);
}

public void Debug(string message)
{
_log.Debug(message);
}

public void Debug(string message, Exception ex)
{
_log.Debug(message, ex);
}

public void Info(string message)
{
_log.Info(message);
}

public void Info(string message, Exception ex)
{
_log.Info(message, ex);
}

public void Warn(string message)
{
_log.Warn(message);
}

public void Warn(string message, Exception ex)
{
_log.Warn(message, ex);
}

public void Error(string message)
{
_log.Error(message);
}

public void Error(string message, Exception ex)
{
_log.Error(message, ex);
}

public void Fatal(string message)
{
_log.Fatal(message);
}

public void Fatal(string message, Exception ex)
{
_log.Fatal(message, ex);
}
}

All it takes to actually use this is to set it up in a StructureMap registry:

public class StructureMapRegistry : Registry
{
public StructureMapRegistry()
{
// Logging
For<ILogger>().AlwaysUnique().Use(s => s.ParentType == null ? new Log4NetLogger(s.BuildStack.Current.ConcreteType) : new Log4NetLogger(s.ParentType));
var applicationPath = Path.GetDirectoryName(Assembly.GetAssembly(GetType()).Location);
var configFile = new FileInfo(Path.Combine(applicationPath, "app.config"));
XmlConfigurator.ConfigureAndWatch(configFile);

// Other registrations here
}
}

And then you could constructor inject it in your classes as follows:

public class FileRegistratorJob : IJob
{
private ILogger _logger;

public FileRegistratorJob(ILogger logger)
{
_logger = logger;
}

public void Execute(IJobExecutionContext context)
{
try
{
//
_logger.Debug("Job completed!");

}
catch (Exception ex)
{
_logger.Error("An error occured", ex);
}
}
}

 

I much cleaner solution because we removed the coupling to log4net.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s