2012-12-12 7 views
5

Ich arbeite daran, die Protokollierung zu einem Projekt mit Windsor Logging Facility und der NLog-Integration hinzuzufügen.Windsor Logging Facility: Name des Steuerungsprotokolls

Anstatt die empfohlene Vorgehensweise der Windsor-Dokumentation zu befolgen, eine Log-Eigenschaft zu jeder Klasse hinzuzufügen, für die ich die Protokollierung unterstützen möchte, habe ich beschlossen, den Weg der dynamischen Überwachung zu gehen. Bis jetzt ist der Abfangjäger ziemlich einfach; es nutzt nur Konstruktor Injektion eine Instanz von ILogger zu bekommen:

class LoggingInterceptor : IInterceptor 
{ 
    private readonly ILogger _logger; 
    public LoggingInterceptor(ILogger logger) 
    { 
     if (logger == null) throw new ArgumentNullException("logger"); 
     _logger = logger; 
    } 

    public void Intercept(IInvocation invocation) 
    { 
     // just a placeholder implementation, I'm not actually planning to do this ;) 
     _logger.Info(invocation.Method.Name); 
     invocation.Proceed(); 
    } 
} 

Darüber hinaus, alles, was ich getan habe, ist das Minimum für die Abfangjäger zu registrieren und es zu einer Komponente der Anwendung, und die Protokollierungsfunktion kümmert sich um den Rest .

container.Register(Component.For<LoggingInterceptor>().LifeStyle.Transient); 

container.Register(
    Component.For<IEmployeeRepository>() 
    .ImplementedBy<EmployeeRepository>() 
    .Interceptors(InterceptorReference.ForType<LoggingInterceptor>()).First); 

So weit so gut - irgendwie. Der Logger, den ich bekomme, folgt NLogs empfohlenem Training eines Loggers pro Klasse. Ich denke nicht, dass das in diesem Fall eine sehr gute Wahl ist. Das bedeutet, dass jede einzelne Nachricht in ein Protokoll mit dem Namen "MyApplication.Interceptors.LoggingInterceptor" geleitet wird, was nicht besonders nützlich ist.

Ich hätte lieber Logs benannt nach der Abstraktion, auf die der Logger angewendet wurde. Wenn der Logger beispielsweise auf eine Implementierung von IEmployeeRepository angewendet wurde, sollte das Protokoll den Namen EmployeeRepository haben. Ist das machbar?

Edit: Ich habe versucht, die Implementierung einer benutzerdefinierten ILoggerFactory und Anweisen der Behälter, den er anstatt zu verwenden. Ich treffe jedoch schnell eine Straßensperre: Wenn Windsor in die Fabrik ruft, ist die einzige Information, die geliefert wird, der Typ des Objekts, für das der Logger erfasst wird. Es werden keine weiteren Informationen über das Objekt geliefert, so dass ILoggerFactory keine Möglichkeit gibt, die Abstraktion zu ermitteln, auf die der Interzeptor angewendet wurde.

Ich bemerke, dass es zwei Überladungen von ILoggerFactory.Create() gibt, die Zeichenfolgen als Argumente akzeptieren. Windsor scheint beide nicht direkt zu benutzen, aber man nimmt an, dass sie aus einem bestimmten Grund da sein müssen. Gibt es etwas in der fließenden Registrierungs-API, das verwendet werden kann, um anzugeben, dass eine bestimmte Zeichenfolge verwendet werden soll?

Antwort

6

Hier ist eine Frage, die Ihrer sehr ähnlich ist und eine akzeptierte Antwort hat. In der Verknüpfung schlägt die Person, die die Antwort veröffentlicht, vor, den Interceptor von ILoggerFactory abhängig zu machen und in der Intercept-Methode den IInvocation.TargetType als den Typ zu verwenden, der an die ILoggerFactory gesendet wird, um die entsprechende Protokollfunktion zu erhalten.

Hinweis, ich benutze nicht Castle, also kann ich nicht viel mehr zu diesem Vorschlag kommentieren.

public class LoggingInterceptor : IInterceptor 
{ 
    private readonly ILoggerFactory _loggerFactory; 

    public LoggingInterceptor(ILoggerFactory loggerFactory) 
    { 
     _loggerFactory = loggerFactory; 
    } 

    public void Intercept(IInvocation invocation) 
    { 
     var logger = _loggerFactory.Create(invocation.TargetType); 
     if (logger.IsDebugEnabled) 
     { 
      logger.Debug(CreateInvocationLogString(invocation)); 
     } 
     try 
     { 
      invocation.Proceed(); 
     } 
     catch (Exception e) 
     { 
      logger.Warn(CreateInvocationLogString(invocation)); 
      throw; 
     } 
     logger.Info(CreateInvocationLogString(invocation)); 
    } 

    private static String CreateInvocationLogString(IInvocation invocation) 
    { 
     var sb = new StringBuilder(100); 
     sb.AppendFormat("Called: {0}.{1}(", invocation.TargetType.Name, invocation.Method.Name); 
     foreach (var argument in invocation.Arguments) 
     { 
      var argumentDescription = argument == null ? "null" : argument.ToString(); 
      sb.Append(argumentDescription).Append(","); 
     } 
     if (invocation.Arguments.Any()) 
     { 
      sb.Length--; 
     } 
     sb.Append(")"); 
     return sb.ToString(); 
    } 
} 

Castle: How can i get the correct ILogger in the logging interceptor?

Sie haben wahrscheinlich schon gesehen, aber hier ist ein Link zu einem Schloss Beispiel, das zeigt, wie ein Logging-Abfangjäger zu erstellen und wie es scheint, einen Logger für den umschlossenen Typen zu erstellen:

http://docs.castleproject.org/Windsor.Introduction-to-AOP-With-Castle.ashx

EDIT: die Implementierung von ILoggerFactory für nlog ExtendedNLogFactory ist, ist es in der Castle.Core-nLog NuGet Paket (http://www.nuget.org/packages/Castle.Core-NLog)

+1

Ihr Google-Fu ist eindeutig besser als meins. Dies sollte perfekt sein - das einzige zusätzliche Detail besteht darin, ein Protokoll zu erhalten, das nach dem abstrakten Typ und nicht nach dem konkreten Typ benannt wird.Ich denke, dass ich das tun werde, indem ich die Schnittstellen des konkreten Typs nach denen suche, die einer Konvention folgen. –

+0

Ich bin froh, dass ich helfen konnte! – wageoghe