拦截或装饰对ILogger的调用

本文关键字:ILogger 调用 | 更新日期: 2023-09-27 18:21:28

我目前正在使用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,而不是我所期望的动态代理。

拦截或装饰对ILogger的调用

ILSpy的一些挖掘似乎表明,您将无法拦截对ILogger实例化的调用。ILogger实体是由NLogFactory直接创建的(我调查过的所有日志工厂、log4net、控制台等都是一样的)

// Castle.Services.Logging.NLogIntegration.NLogFactory
public override ILogger Create(string name)
{
    Logger logger = LogManager.GetLogger(name);
    return new NLogLogger(logger, this);
}

如果这真的是必要的,您应该能够继承您感兴趣的工厂(基本上是NLogFactoryExtendedNLogFactory),以便覆盖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();
    }
}