Common.Logging with multiple factory adapters

I am currently working on the transition of a large project to use Common.Logging, and I was hoping that I would be able to output logging events to several third-party protocols.

We currently have an internally developed trace library that we would like to use to track and debug messages. I would also like to start using log4net to send some messages to the database to send or send email notifications at some levels.

I am looking for something like this:

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

Is there a way to do this using the boxless configuration options?

+5
source share
3 answers

AFAIK, Common.Logging , . .

1) log7 factory, http://netcommon.sourceforge.net/docs/2.1.0/reference/html/ch01.html#logging-advanced-customfactoryadapter. factory, , , , . factory , .

2) app log4net (http://logging.apache.org/log4net/release/faq.html#custom-appender) Common.Logging, log4net factory.

, , Common.Logging, factory .

+5

, , , -, , , ( https://github.com/ramonsmits/common-logging, ). Common.Logging 3.1.0.

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

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

:

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

LoggerName.factoryAdapter, , , LoggerName.someProperty.

+4

Now there is a built-in way to support multiple adapters, see Common.Logging.MultipleLogger . There is an example App.configthat shows how to use it here .

+2
source

All Articles