6

loggerNameを取得してLogManager.GetCurrentClassLogger()の代わりにLogManager.GetLogger(loggerName)を使用できるように、コンテキストを取得する方法はありますか?シンプルなインジェクターでNLog ILoggerを登録する

私は気づいたcontainer.RegisterConditional()コンテキストにアクセスできます。

また、私は今のところSimpleLogging.NLogのような解決策を避けたいと思います。

最後に、私はこれを受け入れることを望んでいますが、正しいアプローチではありません。ところで、AOPは私がすでに検討しているオプションです(Is it a good practice to have logger as a singleton?)。

注:私は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!"); 
      } 
     } 
    } 
} 
+0

あなたは 'loggerName'の値をどのようにしたいですか? – qujck

+1

関連:https://stackoverflow.com/q/32952701/264697 – Steven

+1

AOP技術を適用することは非常に便利ですが、コード織りツールから離れて滞在してください。デコレータを使用してAOPを適用します。関連:https://stackoverflow.com/a/9915056/264697 – Steven

答えて

7

正しいNlog Loggerにメッセージをルーティングするプロキシロガーを定義する必要があります。このプロキシは非常に単純です:あなたが唯一の​​を注入する必要がありますログインする必要がどこ

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

としてこれを登録することができます。

AOPと同様です。私はこのコメントであなたが何を意味するのかよく分かりません

(NLog.ILoggerの契約が大きい)維持する必要があるラッパー。

ロギングcross cutting concernあり、decoratorを使用して横断的関心事を適用するための素晴らしい方法です。デコレータを使用すると、すべての(プライベートな)関数呼び出しの入口と出口を記録することはできませんが、なぜそれを望みますか? hereを読むことができるので、それはおそらく必要ありません。サービスが呼び出され(データがこのサービスに渡されている)単純な事実と可能性のある例外が記録され、完全なスタックトレースはほとんどの場合十分です。

だから、このことを考慮してください。

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。この問題は、このデザインが少なくとも最適ではないために発生します。単一の開かれた汎用抽象化を中心としたデザインを使用すると、この問題は完全に解決されます。このデザインについてはherehereを読むことができます。この場合

あなたは

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

として単一 `LoggingDecorator」を持っているだろうと、この単一のデコレータは、すべてのコマンドをログに記録します。

これは私のAOPビジョンです....

+1

私はあなたの答えは唯一のスティーブンのコメントに対処しないと思いますが、またログのジェフ・アトウッドのテイク浮き彫りに:[ログを通報します](http://blog.codinghorror.com/the-problem-with-logging/を)。面白い古い、しかし良い議論は、建築家が扱う必要があります。 –

+0

本当に有益です、ありがとう – james

関連する問題