2012-07-06 87 views
5

我目前正在努力移動一個大型項目使用Common.Logging,我希望能夠輸出日誌事件到多個第三方日誌記錄實施。Common.Logging與多個工廠適配器

我們現在有一個內部開發的跟蹤庫,我們想繼續使用它來跟蹤和調試消息。我還想開始使用log4net將某些消息發送到數據庫以進行報告或在某些級別發送電子郵件通知。

我正在尋找的是這樣的:

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

有什麼辦法用現成的配置選項來做到這一點?

回答

5

AFAIK,Common.Logging中不存在任何您需要的東西。這裏有幾個選擇。

1)根據http://netcommon.sourceforge.net/docs/2.1.0/reference/html/ch01.html#logging-advanced-customfactoryadapter所述開發一對自定義記錄器工廠適配器。一個自定義工廠看起來您已經開發出來了,它將用於您的內部跟蹤庫。第二個自定義工廠將通過組合來自一個或多個其他工廠的記錄器來創建複合記錄器對象。 2)爲您的跟蹤庫開發自定義log4net appender(http://logging.apache.org/log4net/release/faq.html#custom-appender),並配置Common.Logging以僅使用log4net工廠。

我覺得第二個選項最簡單,因爲它不涉及改變Common.Logging的配置行爲,所以它可以從其他配置的工廠構成複合工廠。

+1

謝謝,那正是我期待的。我確實看到有人在[GitHub repo](https://github.com/net-commons/common-logging/issues/8)中提出了這個問題,所以最終可能會將其添加到項目中。 – omockler 2012-07-06 19:19:28

+0

@omockler那個GitHub問題早就解決了。現在有多個適配器似乎是可能的。 – 2017-02-12 14:52:26

4

我知道這個問題很舊,但顯然還沒有開箱即用的解決方案,所以這裏是一個自定義記錄器,適用於我(靈感來自https://github.com/ramonsmits/common-logging,但我最終改變了所有內容)。使用Common.Logging版本3.1.0進行測試。

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

記錄器

/// <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,然後您可以通過使用相同的名稱爲t添加此記錄器的屬性他的鑰匙,如LoggerName.someProperty