问题
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