JP provides a great solution to warp log4net, textwritter and other logging service, the basic idea is to create a common interface and a common Log class used by application directly.
In Application:
Log.For(this).Info(…)
And Log class initialize different logging service might be passed in.
public class Log
{
private static ILogFactory logFactory;
public static void InitializeLogFactory(ILogFactory logFactory)
{
Log.logFactory = logFactory;
}
public static ILog For(object itemThatRequiresLoggingServices)
{
return For(itemThatRequiresLoggingServices.GetType());
}
public static ILog For(Type type){
// This is IOC style, then we should not use logFactory field which needs to be passed in when using log.
// return DependencyResolver.GetImplementationOf().CreateFor(type);
return logFactory.CreateFor(type); ;
}
}
If it’s a simple console logging service, the implementation will be like this:
public class ConsoleLogFactory : ILogFactory
{
public ILog CreateFor(Type type)
{
return new ConsoleLogger();
}
private class ConsoleLogger : ILog
{
public void Informational(string message)
{
System.Console.Out.WriteLine(message);
}
public void Informational(string messageFormat, params object[] args)
{
System.Console.Out.WriteLine(messageFormat, args);
}
And the log4net factory will be this, in which the WireUpConfiguration() method is using singleton pattern.
public class Log4NetLogFactory : ILogFactory
{
private ILog4NetInitialization initialization;
private bool initialized;
public Log4NetLogFactory(): this(new Log4NetInitialization())
{
}
public Log4NetLogFactory(string filename): this(new Log4NetInitialization(filename))
{
}
// using ILog4NetInitialization can enable logFactory read from different app config file.
public Log4NetLogFactory(ILog4NetInitialization initialization)
{
this.initialization = initialization;
}
public ILog CreateFor(Type typeThatRequiresLoggingServices)
{
WireUpConfiguration();
return new Log4NetLog(LogManager.GetLogger(typeThatRequiresLoggingServices));
}
private void WireUpConfiguration()
{
if (initialized) return;
initialization.Execute();
initialized = true;
}
}
Finally, the log4netINitialization is this: (I don’t think ILog4NetInitialization is necessary, in fact the whole Log4NetInitialization can also be moved into log4net Factory class even.)
public class Log4NetInitialization : ILog4NetInitialization
{
private readonly XmlElement configuration;
public Log4NetInitialization(){}
public Log4NetInitialization(string filename)
{
XmlDocument document = new XmlDocument();
document.Load(filename);
configuration = document.DocumentElement;
}
public Log4NetInitialization(XmlElement configuration)
{
this.configuration = configuration;
}
public void Execute()
{
if (configuration == null) XmlConfigurator.Configure();
else XmlConfigurator.Configure(configuration);
}
}
The benefit of all those work is, the front end is same based on different logging service implementation,
Log.For(this).Info(…)
Log.For(this).Debug(…)
Log.For(this).Fatal(…)
Log.For(this).Warn(…)
Log.For(this).Error(…)
