Intercept or Decorate calls to ILogger

ぃ、小莉子 提交于 2019-12-07 09:08:42

问题


I'm currently using castle windsor, along with it's logging facility in my application.

However, in my logging I would like to include some contextual information that is not within the logged message, but stored within the CallContext.

I have tried to do this by intercepting the calls to ILogger using the following:

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

But the variable logger is of type NLog.Loggger rather than the dynamic proxy I was expecting.


回答1:


Some digging with ILSpy seems to show that you won't be able to intercept calls to the ILogger instantiation. The ILogger intance is created directly by the NLogFactory (same thing for all logging factories I looked into, log4net, console, etc)

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

If this is really necessary you should be able to inherit the factories you're interested into (basically, NLogFactory and ExtendedNLogFactory) in order to override the ILogger creation. Then create a instance-based proxy of the ILogger and plug in your custom interceptors. Finally inform the LoggingFacility that you want to use a custom factory.

I started being pessimist about your problem but I found the solution to be quite simple to implement, so you shouldn't have too many problems to achieve what you want. Code? Of course :)

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


来源:https://stackoverflow.com/questions/25790258/intercept-or-decorate-calls-to-ilogger

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!