2012-07-06 12 views
5

Actualmente estoy trabajando en mover un proyecto grande para utilizar Common.Logging y esperaba poder generar eventos de registro en más de una implementación de registro de terceros.Common.Logging con varios adaptadores de fábrica

Actualmente tenemos una biblioteca de seguimiento desarrollada internamente que nos gustaría seguir usando para rastrear y depurar mensajes. También me gustaría comenzar a usar log4net para enviar algunos mensajes a una base de datos para informar o enviar notificaciones por correo electrónico en algunos niveles.

Lo que estoy buscando es algo como esto:

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

¿Hay alguna manera de hacer esto con la salida de las opciones de configuración de la caja?

Respuesta

5

AFAIK, nada existe en Common.Logging para lo que necesita. Aquí hay un par de alternativas.

1) Desarrolle un par de adaptadores de fábrica de registradores personalizados como se describe en http://netcommon.sourceforge.net/docs/2.1.0/reference/html/ch01.html#logging-advanced-customfactoryadapter. Una fábrica personalizada, que parece que ya ha desarrollado, sería para su biblioteca de rastreo interno. La segunda fábrica personalizada crearía objetos de registrador compuestos combinando registradores de una o más fábricas.

2) Desarrolle un apilador de log4net personalizado (http://logging.apache.org/log4net/release/faq.html#custom-appender) para su biblioteca de rastreo y configure Common.Logging para que solo use la fábrica de log4net.

Creo que la segunda opción sería la más fácil ya que no implicaría cambiar el comportamiento de configuración de Common.Logging para que pueda constituir la fábrica compuesta de otras fábricas configuradas.

+1

Gracias, eso era lo que esperaba. Vi que alguien más lo mencionó en [el repositorio de GitHub] (https://github.com/net-commons/common-logging/issues/8) para que eventualmente se agregue al proyecto. – omockler

+0

@omockler Ese problema de GitHub se resolvió hace un tiempo. Tener múltiples adaptadores parece ser posible ahora. –

4

Sé que la pregunta es antigua, pero aparentemente todavía no hay una solución lista para usar, así que aquí hay un registrador personalizado que funciona para mí (inspirado en https://github.com/ramonsmits/common-logging pero cambié casi todo al final) Probado con Common.Logging versión 3.1.0.

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

El registrador

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

Y se puede configurar de esta manera:

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

Es decir, para cada registrador, se agrega una línea con clave LoggerName.factoryAdapter, y luego puede agregar propiedades para este registrador usando el mismo nombre para t la clave, como LoggerName.someProperty.

Cuestiones relacionadas