2012-12-12 9 views
5

Sto lavorando per aggiungere la registrazione a un progetto utilizzando Windsor Logging Facility e l'integrazione di NLog.Windsor Logging Facility: nome registro di controllo

Piuttosto che seguire la pratica consigliata dalla documentazione di Windsor di aggiungere una proprietà Log a ogni classe per cui desidero supportare la registrazione, ho deciso di provare a utilizzare la modalità di intercettazione dinamica per farlo. Finora l'intercettore è abbastanza di base; solo utilizza l'iniezione di costruzione per ottenere un'istanza di ILogger:

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

di là di questo, tutto quello che ho fatto è il minimo per la registrazione del intercettore e la sua applicazione a un componente, e la funzione di registrazione si prende cura di tutto il resto .

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

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

Fin qui tutto bene, una specie di. Il logger che ottengo segue la pratica raccomandata da NLog di un logger per classe. Non penso che sia una buona scelta in questo caso. Significa che ogni singolo messaggio sta per un log denominato "MyApplication.Interceptors.LoggingInterceptor", che non è terribilmente utile.

Preferirei avere i log chiamati dopo l'astrazione a cui è stato applicato il logger. Ad esempio, se il logger è stato applicato a un'implementazione di IEmployeeRepository, il registro deve essere denominato EmployeeRepository. È fattibile?

Edit: Ho provato l'attuazione di un personalizzato ILoggerFactory e istruire il contenitore per usarlo al posto. Tuttavia, ho colpito rapidamente un posto di blocco: quando Windsor chiama in fabbrica, l'unica informazione fornita è il tipo di oggetto per il quale viene acquisito il logger. Non sono fornite altre informazioni sull'oggetto, quindi lo ILoggerFactory non ha modo di scoprire l'astrazione a cui è stato applicato l'intercettore.

Ho notato che ci sono due sovraccarichi di ILoggerFactory.Create() che accettano stringhe come argomenti. Windsor non sembra utilizzare nessuno dei due direttamente, ma si presume che debbano essere lì per un motivo. C'è qualcosa nella fluente API di registrazione che può essere usata per specificare che una stringa particolare debba essere usata?

risposta

6

Ecco una domanda che è molto simile alla tua e ha una risposta accettata. Nel collegamento, la persona che invia la risposta suggerisce di rendere l'intercettore dipendente da ILoggerFactory e nel metodo Intercept, utilizzare IInvocation.TargetType come tipo da inviare a ILoggerFactory per ottenere il logger appropriato.

Nota, non uso Castle, quindi non posso commentare molto di più su questo suggerimento.

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?

Probabilmente avrete già visto questo, ma qui è un link ad un esempio Castello che mostra come creare un intercettore di registrazione e di come, a quanto pare, per creare un logger per il tipo avvolto:

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

EDIT: l'attuazione del ILoggerFactory per nlog è ExtendedNLogFactory, è nel pacchetto NuGet Castle.Core-nLog (http://www.nuget.org/packages/Castle.Core-NLog)

+1

Il tuo Google-fu è chiaramente migliore del mio. Questo dovrebbe essere perfetto: l'unico dettaglio in più è ottenere un log chiamato per il tipo astratto piuttosto che il tipo concreto.Sto pensando che lo farò cercando le interfacce del tipo concreto per quelle che seguono una convenzione. –

+0

Sono contento di essere stato in grado di aiutare! – wageoghe