Search code examples
c#-4.0typesdependency-injectionlog4netcastle-windsor

Log4Net with castle windsor


I am configuring logging for my application and for logging I am using log4net and castle windsor for DI.

I want logging framework to be wrap inside custom implementation so it can be changed in future.

public interface ICustomLogger
{
    void Debug(object message, Exception ex = null);
    void Info(object message, Exception ex = null);
    void Warn(object message, Exception ex = null);
    void Error(object message, Exception ex = null);
    void Fatal(object message, Exception ex = null);
}

public class CustomLogger : ICustomLogger
{
    private readonly log4net.ILog _log;
    private readonly log4net.ILog _log1;

    public CustomLogger()
    {
        //approach1
        var stack = new StackTrace();
        var frame = stack.GetFrame(1);
        var method = frame.GetMethod();
        Type type = method.DeclaringType;
        _log = log4net.LogManager.GetLogger(type);

        //approach2
        var dtype = System.Reflection.MethodBase.GetCurrentMethod().DeclaringType;
        _log1 = log4net.LogManager.GetLogger(dtype);
    }

    public CustomLogger(string name)
    {
        _log = log4net.LogManager.GetLogger(name);
    }

    public CustomLogger(Type type)
    {
        _log = log4net.LogManager.GetLogger(type);
    }

    public void Debug(object message, Exception ex = null)
    {
        if (_log.IsDebugEnabled)
        {
            if (ex == null)
            {
                _log.Debug(message);
            }
            else
            {
                _log.Debug(message, ex);
            }
        }
    }

    public void Info(object message, Exception ex = null)
    {
        if (_log.IsInfoEnabled)
        {
            if (ex == null)
            {
                _log.Info(message);
            }
            else
            {
                _log.Info(message, ex);
            }
        }
    }

    public void Warn(object message, Exception ex = null)
    {
        if (_log.IsWarnEnabled)
        {
            if (ex == null)
            {
                _log.Warn(message);
            }
            else
            {
                _log.Warn(message, ex);
            }
        }
    }

    public void Error(object message, Exception ex = null)
    {
        if (_log.IsErrorEnabled)
        {
            if (ex == null)
            {
                _log.Error(message);
            }
            else
            {
                _log.Error(message, ex);
            }
        }
    }

    public void Fatal(object message, Exception ex = null)
    {
        if (_log.IsFatalEnabled)
        {
            if (ex == null)
            {
                _log.Fatal(message);
            }
            else
            {
                _log.Fatal(message, ex);
            }
        }
    }
}

To register this custom implementation with DI...

   container.Register(Component.For<ICustomLogger>()
                                   .ImplementedBy<CustomLogger>()
                                   .LifeStyle.Transient);

Problem comes when I ask DI to resolve logger, then it always return logger for Customlogger type not the class where I want to use it.

class ABC
{
    ICustomLogger _logger;

    public ABC(ICustomLogger logger)
    {
        _logger = logger; // type of this logger is CustomLogger not ABC
    }
}

Both the approach are not working to resolve logger as ABC. Can anyone help me to understand what's wrong here and how to fix the issue.


Solution

  • You can do this via a custom dependency resolver.

    You first need to create an implementation of ISubDependencyResolver that can resolve dependencies of type ICustomLogger:

    public class LoggerResolver : ISubDependencyResolver
    {
        public bool CanResolve(
            CreationContext context,
            ISubDependencyResolver contextHandlerResolver,
            ComponentModel model,
            DependencyModel dependency)
        {
            //We can only handle dependencies of type ICustomLogger 
            return dependency.TargetType == typeof (ICustomLogger);
        }
    
        public object Resolve(
            CreationContext context,
            ISubDependencyResolver contextHandlerResolver,
            ComponentModel model,
            DependencyModel dependency)
        {
            //We pass the requested type, e.g. ABC, to the constructor of CustomLogger
            return new CustomLogger(context.RequestedType);
        }
    }
    

    You then need to register this resolver with the container like this:

    container.Kernel.Resolver.AddSubResolver(new LoggerResolver());