使用简单注入器注册NLog ILogger [英] Registering NLog ILogger with Simple Injector

查看:532
本文介绍了使用简单注入器注册NLog ILogger的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有什么办法可以获取上下文,以便可以检索loggerName并使用LogManager.GetLogger(loggerName)而不是LogManager.GetCurrentClassLogger()?

Is there any way I can get the context so I can retrieve the loggerName and use LogManager.GetLogger(loggerName) instead of LogManager.GetCurrentClassLogger()?

我注意到container.RegisterConditional()可以访问上下文.

I noticed container.RegisterConditional() has access to the context.

此外,我现在暂时避免使用类似 SimpleLogging.NLog 之类的解决方案.

Also, I want to avoid solutions like SimpleLogging.NLog for now.

最后,我愿意接受这不是正确的方法.顺便说一句,AOP是我已经探讨过的一种选择(

Finally, I am willing to accept this is not the right approach. BTW, AOP is an option that I've already explored (Is it a good practice to have logger as a singleton?).

注意:我知道GetCurrentClassLogger()获得的信息与通过.NET反射检索的信息相同.

Note: I am aware that GetCurrentClassLogger() gets the same information I'd retrieve with .NET reflection.

using NLog;
using SimpleInjector;

namespace DependencyInjection
{
    class Program
    {
        private static Container _container;
        static void Main(string[] args)
        {
            Bootstrap();
            _container.GetInstance<Greeter>().Greet();
        }

        private static void Bootstrap()
        {
            _container = new Container();

            _container.Register<ILogger>(() => LogManager.GetCurrentClassLogger(), Lifestyle.Transient);
            _container.Register<Greeter>();

            _container.Verify();
        }

        public class Greeter
        {
            private ILogger _logger;

            public Greeter(ILogger logger)
            {
                _logger = logger;
            }

            public void Greet()
            {
                _logger.Log(LogLevel.Info, "Hello world!");
            }
        }
    }
}

推荐答案

您需要定义一个代理记录器,它将消息路由到正确的Nlog记录器.该代理非常简单:

You need to define a proxy logger which routes the message to the correct Nlog Logger. This proxy is pretty simple:

public class NLogProxy<T> : ILogger
{
    private static readonly NLog.ILogger logger = 
                 LogManager.GetLogger(typeof (T).FullName);

    void ILogger.Log(string message)
    {
        logger.Log(LogLevel.Info, message);
    }
}

您可以将其注册为

container.RegisterConditional(typeof(ILogger), 
     context => typeof(NLogProxy<>).MakeGenericType(context.Consumer.ImplementationType), 
     Lifestyle.Singleton, context => true);

每个需要记录的地方都只需注入ILogger.

Everywhere you need logging you only will have to inject ILogger.

关于AOP.我不确定这句话的意思

As for AOP. I'm unsure what you mean by this comment

必须维护的包装器(NLog.ILogger合同巨大).

A wrapper that has to be maintained (NLog.ILogger contract is huge).

记录是交叉关注,并使用此处中阅读,您可能不需要它.在大多数情况下,调用服务(将数据传递给该服务)并用完整的堆栈跟踪记录可能的异常这一简单事实就足够了.

Logging is a cross cutting concern and using a decorator is a great way to apply cross cutting concerns. With a decorator it won't be possible to log every (private) function call entrance and exit but why would you want that? As you can read here you probably don't need that. The simple fact that a service is called (with the data passed to this service) and possible exceptions are logged with the complete stacktrace will be more than sufficient in most cases.

因此,请考虑以下问题:

So consider this:

public interface ISomeService
{
    void DoSomething(string someParameter);
}

public class SomeServiceDecorator : ISomeService
{
    private readonly ISomeService decoratee;
    private readonly ILogger logger;

    public SomeServiceDecorator(ISomeService decoratee, ILogger logger)
    {
        this.decoratee = decoratee;
        this.logger = logger;
    }

    public void DoSomething(string someParameter)
    {
        try
        {
            this.logger.Log(string.Format("Do something called with {0}", someParameter));
            this.decoratee.DoSomething(someParameter);
        }
        catch (Exception e)
        {
            this.logger.Log(e.ToString());                
            throw;
        }
    }
}

此装饰器将记录所有函数调用以及传递给服务的信息,还将记录任何异常.

This decorator will log all function calls with the information passed to the service and will also log any exception.

但是这种方法会使类的数量增加2个,所以不是 DRY .引起该问题的原因是该设计至少不是次优的.使用围绕单个开放通用抽象的设计将完全解决此问题.您可以在此处此处.

But this approach would increase the number of classes by 2, so not very DRY. This problem is caused because this design is at least suboptimal. Using a design around a single open generic abstraction will totally solve this problem. You can read about this design here and here.

在这种情况下,您将有一个`LoggingDecorator'作为

In this case you would have a single `LoggingDecorator' as

public class LoggingCommandHandlerDecorator<T> : ICommandHandler<T>
{
    private readonly ICommandHandler<T> decoratee;
    private readonly ILogger logger;

    public LoggingCommandHandlerDecorator(ICommandHandler<T> decoratee, ILogger logger)
    {
        this.decoratee = decoratee;
        this.logger = logger;
    }

    public void Handle(T command)
    {
        // serialize command to json and log
        this.logger.Log(serializedcommandData);
        this.decoratee.Handle(command);
    }
}

这个装饰器将记录您的所有命令.

And this single decorator will log all your commands.

那是我对AOP的看法.

That's my vision of AOP....

这篇关于使用简单注入器注册NLog ILogger的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆