我正在使用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()
有两个重载接受字符串作为参数。温莎似乎没有直接使用其中任何一个,但人们会认为他们必须在那里是有原因的。流畅的注册API中是否有可用于指定使用特定字符串的内容?
答案 0 :(得分:6)
这是一个与你非常相似的问题,它有一个公认的答案。在链接中,发布答案的人建议使拦截器依赖于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 for nlog的实现是ExtendedNLogFactory,它位于Castle.Core-NLog nuget包中(http://www.nuget.org/packages/Castle.Core-NLog)