I've scoured through Stack Overflow to get an idea on how I can have logging in my C# application and keep the usage requirements specific to my application. The following questions that have previously been answered have helped assist me:
- Implementation and usage of logger wrapper for log4net
- Logger wrapper best practice
- log4net with DI Simple Injector
These implementations seem to want me to pass log4net.ILog to the constructor of my implementation or to the base implementation of log4net's LogImpl. However, I was having trouble configuring my abstract logger using Simple Injector.
As I see it, my implementation is working really well, but I dont know what some draw backs might exist, or perhaps other ways of doing this.
What I've Got So Far
- I have an
ILogger
interface that requires avoid Log(LogEntry entry)
method. - An Adapter (I adapted it from the above referenced sources) -
public class Log4netAdapter<T> : ILogger
- DI container Simple Injector with the following registration:
Source Code
Simple Injector DI Container:
private SimpleInjector.Container container;
[SetUp]
public void SetUp()
{
// init log4net
XmlConfigurator.Configure();
container = new SimpleInjector.Container();
container.RegisterConditional(
typeof(ILogger),
c => typeof(Log4netAdapter<>).MakeGenericType(c.Consumer.ImplementationType),
Lifestyle.Singleton,
c => true);
}
Logger interface:
public interface ILogger
{
void Log(LogEntry entry);
}
public class Log4netAdapter<T> : ILogger
{
private readonly log4net.ILog Logger;
public Log4netAdapter()
{
this.Logger = LogManager.GetLogger(typeof(T));
}
public void Log(LogEntry entry)
{
if (entry.Severity == LoggingEventType.Debug)
Logger.Debug(entry.Message, entry.Exception);
else if (entry.Severity == LoggingEventType.Information)
Logger.Info(entry.Message, entry.Exception);
else if (entry.Severity == LoggingEventType.Warning)
Logger.Warn(entry.Message, entry.Exception);
else if (entry.Severity == LoggingEventType.Error)
Logger.Error(entry.Message, entry.Exception);
else
Logger.Fatal(entry.Message, entry.Exception);
}
}
Extensions for ILogger
:
public static class LoggerExtensions
{
public static void Log(this ILogger logger, string message)
{
logger.Log(new LogEntry(LoggingEventType.Information, message));
}
public static void Log(this ILogger logger, Exception exception)
{
logger.Log(new LogEntry(LoggingEventType.Error, exception.Message, exception));
}
}
What I want to know
I want to know if this follows SOLID principles and is there a better way? If there is a better way, can anyone provide me with the reason for it following an example via C#.
What I dont like
My Implementation does not allow me to just call a specific method on any class that I am passing Ilogger
into the constructor. It requires me to have Extensions created on the ILogger
interface, which then redirects to my Log4netAdapter
.