2012-07-06 14 views
5

Attualmente sto lavorando sullo spostamento di un progetto di grandi dimensioni per utilizzare Common.Logging e speravo di poter generare eventi di registrazione su più di un'implementazione di registrazione di terze parti.Common.Logging con più schede di fabbrica

Al momento disponiamo di una libreria di tracciamento sviluppata internamente che vorremmo continuare a utilizzare per la tracciatura e il debug dei messaggi. Vorrei anche iniziare a utilizzare log4net per inviare alcuni messaggi a un database per segnalare o inviare notifiche e-mail ad alcuni livelli.

Quello che sto cercando è qualcosa di simile:

<common> 
<logging> 
    <factoryAdapter type="CustomTraceFactoryAdapter, MyAssembly"> 
    <arg key="configType" value="INLINE"/> 
    </factoryAdapter> 
    <factoryAdapter type="Common.Logging.Log4Net.Log4NetLoggerFactoryAdapter, Common.Logging.Log4Net"> 
    <arg key="configType" value="INLINE"/> 
    </factoryAdapter> 
</logging> 
</common> 

Esiste un modo per fare questo con il fuori delle opzioni di configurazione scatola?

risposta

5

AFAIK, non esiste nulla in Common.Logging per quello che ti serve. Ecco un paio di alternative.

1) Sviluppare un paio di adattatori di fabbrica per logger personalizzati come descritto in http://netcommon.sourceforge.net/docs/2.1.0/reference/html/ch01.html#logging-advanced-customfactoryadapter. Una factory personalizzata, che sembra che tu abbia già sviluppato, sarebbe per la tua libreria di tracciamento interna. La seconda fabbrica personalizzata creerebbe oggetti di logger compositi combinando i logger di una o più altre fabbriche.

2) Sviluppare un appender log4net personalizzato (http://logging.apache.org/log4net/release/faq.html#custom-appender) per la libreria di analisi e configurare Common.Logging per utilizzare solo il factory log4net.

Ritengo che la seconda opzione sarebbe la più semplice in quanto non comporterebbe la modifica del comportamento di configurazione di Common.Logging in modo che possa costituire la fabbrica composita da altre fabbriche configurate.

+1

Grazie, era quello che mi aspettavo. Ho visto che qualcun altro l'ha portato su [il repository GitHub] (https://github.com/net-commons/common-logging/issues/8) in modo da poterlo eventualmente aggiungere al progetto. – omockler

+0

@omockler Questo problema di GitHub è stato risolto qualche tempo fa. Ora è possibile avere più adattatori. –

4

So che la domanda è vecchia, ma a quanto pare non c'è ancora una soluzione pronta per questo, quindi ecco un logger personalizzato che funziona per me (ispirato allo https://github.com/ramonsmits/common-logging ma ho cambiato quasi tutto alla fine). Testato con Common.Logging versione 3.1.0.

Il FactoryAdapter

/// <summary> 
/// Adapter hub for Common.Logging that can send logs to multiple other adapters 
/// </summary> 
public class MultiLoggerFactoryAdapter : AbstractCachingLoggerFactoryAdapter 
{ 
    private readonly List<ILoggerFactoryAdapter> LoggerFactoryAdapters; 

    /// <summary> 
    /// Initializes a new instance of the <see cref="MultiFactoryLoggerFactoryAdapter"/> class. 
    /// </summary> 
    public MultiLoggerFactoryAdapter(CommonLogging.Configuration.NameValueCollection properties) 
    { 
     LoggerFactoryAdapters = new List<ILoggerFactoryAdapter>(); 

     foreach(var factoryAdapter in properties.Where(e => e.Key.EndsWith(".factoryAdapter"))) 
     { 
      string adapterName = factoryAdapter.Key.Substring(0, factoryAdapter.Key.Length - 15); 
      string adapterType = factoryAdapter.Value; 

      var adapterConfig = new CommonLogging.Configuration.NameValueCollection(); 
      foreach(var entry in properties.Where(e1 => e1.Key.StartsWith(adapterName + "."))) 
      { 
       adapterConfig.Add(entry.Key.Substring(adapterName.Length + 1), entry.Value); 
      } 

      var adapter = (ILoggerFactoryAdapter)Activator.CreateInstance(Type.GetType(adapterType), adapterConfig); 
      LoggerFactoryAdapters.Add(adapter); 
     } 
    } 

    /// <summary> 
    /// Initializes a new instance of the <see cref="MultiFactoryLoggerFactoryAdapter"/> class. 
    /// </summary> 
    /// <param name="factoryAdapters">The factory adapters.</param> 
    public MultiLoggerFactoryAdapter(List<ILoggerFactoryAdapter> factoryAdapters) 
    { 
     LoggerFactoryAdapters = factoryAdapters; 
    } 

    protected override ILog CreateLogger(string name) 
    { 
     var loggers = new List<ILog>(LoggerFactoryAdapters.Count); 

     foreach (var f in LoggerFactoryAdapters) 
     { 
      loggers.Add(f.GetLogger(name)); 
     } 

     return new MultiLogger(loggers); 
    } 
} 

Il logger

/// <summary> 
/// Adapter hub for Common.Logging that can send logs to multiple other adapters 
/// </summary> 
public class MultiLogger : AbstractLogger 
{ 
    private readonly List<ILog> Loggers; 

    public static readonly IDictionary<LogLevel, Action<ILog, object, Exception>> LogActions = new Dictionary<LogLevel, Action<ILog, object, Exception>>() 
    { 
     { LogLevel.Debug, (logger, message, exception) => logger.Debug(message, exception) }, 
     { LogLevel.Error, (logger, message, exception) => logger.Error(message, exception) }, 
     { LogLevel.Fatal, (logger, message, exception) => logger.Fatal(message, exception) }, 
     { LogLevel.Info, (logger, message, exception) => logger.Info(message, exception) }, 
     { LogLevel.Trace, (logger, message, exception) => logger.Trace(message, exception) }, 
     { LogLevel.Warn, (logger, message, exception) => logger.Warn(message, exception) }, 
    }; 

    /// <summary> 
    /// Initializes a new instance of the <see cref="MultiLogger"/> class. 
    /// </summary> 
    /// <param name="loggers">The loggers.</param> 
    public MultiLogger(List<ILog> loggers) 
    { 
     Loggers = loggers; 
    } 

    public override bool IsDebugEnabled { get { return Loggers.Any(l => l.IsDebugEnabled); } } 
    public override bool IsErrorEnabled { get { return Loggers.Any(l => l.IsErrorEnabled); } } 
    public override bool IsFatalEnabled { get { return Loggers.Any(l => l.IsFatalEnabled); } } 
    public override bool IsInfoEnabled { get { return Loggers.Any(l => l.IsInfoEnabled); } } 
    public override bool IsTraceEnabled { get { return Loggers.Any(l => l.IsTraceEnabled); } } 
    public override bool IsWarnEnabled { get { return Loggers.Any(l => l.IsWarnEnabled); } } 

    protected override void WriteInternal(LogLevel level, object message, Exception exception) 
    { 
     List<Exception> exceptions = null; 
     foreach(var logger in Loggers) 
     { 
      try 
      { 
       LogActions[level](logger, message, exception); 
      } 
      catch(Exception e) 
      { 
       if(exceptions == null) 
        exceptions = new List<Exception>(); 
       exceptions.Add(e); 
      } 
     } 

     if(exceptions != null) 
      throw new AggregateException("One or more exceptions occured while forwarding log message to multiple loggers", exceptions); 
    } 
} 

E si può configurare in questo modo:

<common> 
    <logging> 
    <factoryAdapter type="MultiLoggerFactoryAdapter, YourAssemblyName"> 
     <arg key="Log4Net.factoryAdapter" value="Common.Logging.Log4Net.Log4NetLoggerFactoryAdapter, Common.Logging.Log4Net1213" /> 
     <arg key="Log4Net.configType" value="INLINE" /> 

     <arg key="Debug.factoryAdapter" value="Common.Logging.Simple.TraceLoggerFactoryAdapter, Common.Logging" /> 
    </factoryAdapter> 
    </logging> 
</common> 

Cioè, per ogni logger, si aggiunge una linea con chiave LoggerName.factoryAdapter e quindi è possibile aggiungere proprietà per questo registratore utilizzando lo stesso nome per t chiave, ad esempio LoggerName.someProperty.