Dot-Net

使用 Simple Injector 註冊 NLog ILogger

  • September 2, 2019

有什麼方法可以獲取上下文,以便我可以檢索loggerName並使用LogManager.GetLogger(loggerName)而不是LogManager.GetCurrentClassLogger()

我注意到container.RegisterConditional()可以訪問上下文。

另外,我現在想避免使用SimpleLogging.NLog 之類的解決方案。

最後,我願意接受這不是正確的做法。順便說一句,AOP 是我已經探索過的一個選項(將記錄器作為單例是一個好習慣嗎?)。

注意:我知道GetCurrentClassLogger()獲得的資訊與使用 .NET 反射檢索的資訊相同。

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 記錄器。這個代理很簡單:

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.

至於AOP。我不確定你的評論是什麼意思

必須維護的包裝器(NLog.ILogger 契約很大)。

日誌記錄是一個橫切關注點,使用裝飾器是應用橫切關注點的好方法。使用裝飾器,不可能記錄每個(私有)函式呼叫入口和出口,但你為什麼要這樣呢?正如您可以在此處閱讀的那樣,您可能不需要它。在大多數情況下,呼叫服務(將數據傳遞給該服務)並使用完整的堆棧跟踪記錄可能的異常這一簡單事實將綽綽有餘。

所以考慮一下:

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

此裝飾器將記錄所有函式呼叫以及傳遞給服務的資訊,還將記錄任何異常。

但是這種方法會將類的數量增加 2,所以不是很DRY。之所以會出現這個問題,是因為這種設計至少是次優的。使用圍繞單個開放通用抽象的設計將完全解決這個問題。您可以在此處此處閱讀有關此設計的資訊。

在這種情況下,您將有一個“LoggingDecorator”作為

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

這個單一的裝飾器將記錄你所有的命令。

這就是我對 AOP 的看法……

引用自:https://stackoverflow.com/questions/34643533