【问题标题】:Log4Net with castle windsorLog4Net 与温莎城堡
【发布时间】:2016-10-07 05:05:31
【问题描述】:

我正在为我的应用程序配置日志记录,我使用log4net 和castle windsor 进行日志记录。

我希望日志框架包含在自定义实现中,以便将来可以更改。

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);
            }
        }
    }
}

要向 DI 注册此自定义实现...

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

当我要求 DI 解析记录器时出现问题,然后它总是返回 Customlogger 类型的记录器,而不是我想使用它的类。

class ABC
{
    ICustomLogger _logger;

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

这两种方法都无法将记录器解析为 ABC。 谁能帮我理解这里出了什么问题以及如何解决这个问题。

【问题讨论】:

    标签: c#-4.0 types dependency-injection log4net castle-windsor


    【解决方案1】:

    您可以通过自定义dependency resolver 来做到这一点。

    您首先需要创建一个ISubDependencyResolver 的实现,它可以解析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);
        }
    }
    

    然后你需要像这样在容器中注册这个解析器:

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

    【讨论】:

      【解决方案2】:

      对于您的具体问题 - 在这两种方法中,您永远不会真正离开班级的“范围”。第一个是创建一个新的 StackTrace,另一个是构造函数的声明类型是该类本身。

      但是您实现了一个可以接收类型的构造函数所以为什么不使用它。目前,您的 CustomLogger 已在您的默认构造函数中注册:

      //There is no place here that you tell castle to resolve using the constructor 
      //that receives `ABS` 
      container.Register(Component.For<ICustomLogger>()
                                  .ImplementedBy<CustomLogger>()
                                  .LifeStyle.Transient);
      

      请参阅Castle Windsor passing constructor parameters 以了解如何传递参数并调用所需的构造函数


      此外 - 值得重新思考:

      虽然在这种情况下在代码和外部源之间创建这样的抽象是个好主意,但我不会这样做,我会解释原因:

      1. 根据我的经验,在代码启动并运行后,并没有真正改变日志框架。特别是因为您正在使用一个成熟且优秀的框架 - Log4Net。它具有许多内置功能,非常适合各种需求:从消息的不同格式到将日志输出到数据库、文件等不同来源,如果我没记错的话,还有用于弹性搜索之类的附加程序。
      2. 您正在使用Castle Windsor,它与Log4Net 有很好的集成,并且为您提供了一个现成的Logging Facility 到Log4Net。请参阅this question,了解添加它的简单程度。
      3. 最后一点是,如果您已经编写了良好的 SOLID 代码并将您的记录器作为 ILogger 传递给所有组件(而不是特定实现),那么他们可能会调用不同的 Debug/Info/ Warn/Error/Fatal 方法 - 任何其他成熟的日志框架都会有。因此,在您必须进行更改的那一天(我认为这不会发生),您可以编写一个看起来像 Log4Net 的接口的接口,以及一个可以适应您的新日志框架的实现。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多