我目前正在使用Castle windsor,以及我的应用程序中的日志工具。
但是,在我的日志记录中,我想要包含一些不在记录消息中但存储在CallContext
内的上下文信息。
我试图通过使用以下内容拦截对ILogger
的调用来实现此目的:
internal class Program
{
private static void Main(string[] args)
{
var container = new WindsorContainer();
container.AddFacility<LoggingFacility>(f => f.UseNLog());
container.Kernel.Resolver.AddSubResolver(new LoggerResolver(container.Kernel));
var logger = container.Resolve<ILogger>();
}
}
public class LoggerResolver: ISubDependencyResolver
{
private readonly IKernel _kernel;
private static ProxyGenerator _proxyGenerator;
static LoggerResolver()
{
_proxyGenerator = new ProxyGenerator();
}
public LoggerResolver(IKernel kernel)
{
_kernel = kernel;
}
public bool CanResolve(CreationContext context, ISubDependencyResolver contextHandlerResolver, ComponentModel model, DependencyModel dependency)
{
return dependency.TargetType == typeof(ILogger);
}
public object Resolve(CreationContext context, ISubDependencyResolver contextHandlerResolver, ComponentModel model, DependencyModel dependency)
{
return _proxyGenerator.CreateInterfaceProxyWithTarget(_kernel.Resolve<ILogger>(), new LoggingInterceptor());
}
}
public class LoggingInterceptor: IInterceptor
{
public void Intercept(IInvocation invocation)
{
//Some modification to message here
invocation.Proceed();
}
}
但变量logger
的类型为NLog.Loggger
,而不是我期望的动态代理。
答案 0 :(得分:2)
对ILSpy的一些挖掘似乎表明您将无法拦截对ILogger
实例化的调用。 ILogger
intance是由NLogFactory
直接创建的(我查看的所有日志工厂,log4net,控制台等都是一样的)
// Castle.Services.Logging.NLogIntegration.NLogFactory
public override ILogger Create(string name)
{
Logger logger = LogManager.GetLogger(name);
return new NLogLogger(logger, this);
}
如果这确实是必要的,您应该能够继承您感兴趣的工厂(基本上是NLogFactory
和ExtendedNLogFactory
),以覆盖ILogger
创建。然后创建ILogger的基于实例的代理并插入自定义拦截器。最后告知LoggingFacility
您要使用自定义工厂。
我开始对你的问题感到悲观,但我发现解决方案很容易实现,所以你不应该有太多的问题来实现你想要的。 码?当然:))
public class MyFactory : NLogFactory
{
public override ILogger Create(string name)
{
var il = base.Create(name);
var pg = new ProxyGenerator();
return pg.CreateInterfaceProxyWithTarget<ILogger>(il, new LoggingInterceptor());
}
}
public class LoggingInterceptor : IInterceptor
{
public void Intercept(IInvocation invocation)
{
//Some modification to message here
invocation.Proceed();
}
}
internal class Program
{
private static void Main(string[] args)
{
var container = new WindsorContainer();
container.AddFacility<LoggingFacility>(f => f.UseNLog().LogUsing<MyFactory>());
var logger = container.Resolve<ILogger>();
logger.Debug("data"); // we intercept this call, success
Console.ReadLine();
}
}