【问题标题】:Windsor Logging Facility: Control log nameWindsor Logging Facility:控制日志名称
【发布时间】:2012-12-12 19:57:45
【问题描述】:

我正在使用 Windsor Logging Facility 和 NLog 集成向项目添加日志记录。

我没有遵循 Windsor 文档的推荐做法,即向我想要支持日志记录的每个类添加一个 Log 属性,而是决定尝试使用动态拦截来实现它。到目前为止,拦截器相当基本;它只是使用构造函数注入来获取ILogger 的实例:

class LoggingInterceptor : IInterceptor
{
    private readonly ILogger _logger;
    public LoggingInterceptor(ILogger logger)
    {
        if (logger == null) throw new ArgumentNullException("logger");
        _logger = logger;
    }

    public void Intercept(IInvocation invocation)
    {
        // just a placeholder implementation, I'm not actually planning to do this ;)
        _logger.Info(invocation.Method.Name);
        invocation.Proceed();
    }
}  

除此之外,我所做的只是注册拦截器并将其应用到组件的最低要求,其余的由日志记录工具负责。

container.Register(Component.For<LoggingInterceptor>().LifeStyle.Transient);

container.Register(
    Component.For<IEmployeeRepository>()
    .ImplementedBy<EmployeeRepository>()
    .Interceptors(InterceptorReference.ForType<LoggingInterceptor>()).First);

到目前为止一切都很好 - 有点。我得到的记录器遵循 NLog 推荐的每类一个记录器的做法。在这种情况下,我认为这不是一个很好的选择。这意味着每条消息都会发送到名为“MyApplication.Interceptors.LoggingInterceptor”的日志中,这并不是非常有用。

我希望日志以记录器应用到的抽象命名。例如,如果记录器已应用于IEmployeeRepository 的实现,则日志应命名为EmployeeRepository。这可行吗?

编辑: 我尝试实现自定义ILoggerFactory 并指示容器使用它。但是我很快遇到了一个障碍:当 Windsor 调用工厂时,提供的唯一信息是获取记录器的对象的类型。没有提供有关该对象的其他信息,因此ILoggerFactory 无法找出拦截器应用到的抽象。

我注意到ILoggerFactory.Create() 有两个重载,它们接受字符串作为参数。温莎似乎并没有直接使用它们中的任何一个,但人们会认为它们必须在那里是有原因的。 fluent 注册 API 中是否有任何内容可用于指定使用特定字符串?

【问题讨论】:

    标签: c# castle-windsor nlog


    【解决方案1】:

    这是一个与您的问题非常相似的问题,它有一个公认的答案。在链接中,发布答案的人建议使拦截器依赖于 ILoggerFactory,并在 Intercept 方法中,使用 IInvocation.TargetType 作为发送到 ILoggerFactory 以获取适当记录器的类型。

    注意,我不使用 Castle,所以我不能对此建议发表更多评论。

    public class LoggingInterceptor : IInterceptor
    {
        private readonly ILoggerFactory _loggerFactory;
    
        public LoggingInterceptor(ILoggerFactory loggerFactory)
        {
            _loggerFactory = loggerFactory;
        }
    
        public void Intercept(IInvocation invocation)
        {
            var logger = _loggerFactory.Create(invocation.TargetType);
            if (logger.IsDebugEnabled)
            {
                logger.Debug(CreateInvocationLogString(invocation));
            }
            try
            {
                invocation.Proceed();
            }
            catch (Exception e)
            {
                logger.Warn(CreateInvocationLogString(invocation));
                throw;
            }
            logger.Info(CreateInvocationLogString(invocation));
        }
    
        private static String CreateInvocationLogString(IInvocation invocation)
        {
            var sb = new StringBuilder(100);
            sb.AppendFormat("Called: {0}.{1}(", invocation.TargetType.Name, invocation.Method.Name);
            foreach (var argument in invocation.Arguments)
            {
                var argumentDescription = argument == null ? "null" : argument.ToString();
                sb.Append(argumentDescription).Append(",");
            }
            if (invocation.Arguments.Any())
            {
                sb.Length--;
            }
            sb.Append(")");
            return sb.ToString();
        }
    }
    

    Castle: How can i get the correct ILogger in the logging interceptor?

    您可能已经看过这个,但这里有一个 Castle 示例的链接,该示例展示了如何创建日志拦截器,以及显然如何为包装类型创建记录器:

    http://docs.castleproject.org/Windsor.Introduction-to-AOP-With-Castle.ashx

    编辑:ILoggerFactory 的 nlog 实现是 ExtendedNLogFactory,它在 Castle.Core-NLog nuget 包中 (http://www.nuget.org/packages/Castle.Core-NLog)

    【讨论】:

    • 你的 Google-fu 显然比我的好。这应该是完美的 - 唯一的额外细节是获取以抽象类型而不是具体类型命名的日志。我想我会通过在具体类型的接口中搜索遵循约定的接口来做到这一点。
    猜你喜欢
    • 1970-01-01
    • 2012-03-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-28
    相关资源
    最近更新 更多