2013-10-03 46 views
2

這將是一個漫長的問題,但請耐心等待。我正在嘗試爲我們的應用程序創建一個Logging組件,該組件可以擴展到插件新的日誌記錄框架(NLog,Log4Net ec)。現在我知道我們已經有了Ben Foster編寫的Common.Logging外觀,但我想嘗試更多的自定義內容。在我們的例子中,主要的要求之一就是我們需要一個使用日誌框架(在這種情況下爲NLog)將各個參數/值記錄到數據庫的自定義機制。所以我有一個簡單的日誌接口:如何使用Unity爲LogManager(NLog)獲取指定的記錄器

/// <summary> 
/// Interface for implementing a Logger Provider. 
/// </summary> 
public interface ILogger 
{ 
    /// <summary> 
    /// Logs an Info level diagnostics message. 
    /// </summary> 
    /// <param name="logInfo">The Log Info object.</param> 
    void Info(LogInfo logInfo); 

    /// <summary> 
    /// Logs a Warn level diagnostics message. 
    /// </summary> 
    /// <param name="logInfo">The Log Info object.</param> 
    void Warn(LogInfo logInfo); 

    /// <summary> 
    /// Logs a Debug level diagnostics message. 
    /// </summary> 
    /// <param name="logInfo">The Log Info object.</param> 
    void Debug(LogInfo logInfo); 

    /// <summary> 
    /// Logs an Error level diagnostics message. 
    /// </summary> 
    /// <param name="logInfo">The Log Info object.</param> 
    void Error(LogInfo logInfo); 

    /// <summary> 
    /// Logs an Fatal level diagnostics message. 
    /// </summary> 
    /// <param name="logInfo">The Log Info object.</param> 
    void Fatal(LogInfo logInfo); 
} 

LogInfo對象包含所有必要的日誌信息。我有一個實現接口的抽象類:

public abstract class NLogLoggerBase : ILogger 
{ 
    .... 
} 

這是sublcassed到:

public class NLogDatabaseLogger : NLogLoggerBase 
{ 
    public NLogDatabaseLogger(ILogUtility logUtility) 
     : base(logUtility) 
    { 
     //Make sure the custom target is registered for use BEFORE using it. 
     ConfigurationItemFactory.Default.Targets.RegisterDefinition("DatabaseLog", typeof(DatabaseLogTarget)); 

     //initialize the _logger 
     _logger = LogManager.GetLogger("DatabaseLogger"); 
    } 
} 

public class NLogFileLogger : NLogLoggerBase 
{ 
    .... 
} 

數據庫記錄器使用自定義DatabaseTarget(從TargetWithLayout繼承了NLOG )登錄到數據庫,同上文件記錄器。 NLog的基本設置在App.Config中有線連接:

<?xml version="1.0" encoding="utf-8" ?> 
<configuration> 
    <configSections> 
    <section name="nlog" type="NLog.Config.ConfigSectionHandler, NLog" /> 
    </configSections> 
    <nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
     autoReload="true" throwExceptions="false" internalLogFile="C:\Temp\nlog.txt" internalLogLevel="Info" 
     internalLogToConsole="false"> 
    <targets async="true"> 
     <target name="CustomDatabaseLog" xsi:type="DatabaseLog" /> 
     <target name="CustomFileLog" xsi:type="File" /> 
    </targets> 

    <rules> 
     <logger name="DatabaseLogger" minlevel="Info" writeTo="CustomDatabaseLog" /> 
     <logger name="FileLogger" minlevel="Info" writeTo="CustomFileLog" /> 
    </rules> 
    </nlog> 
</configuration> 

到目前爲止這麼好。我對每個記錄儀都進行了一些測試,並且他們可以很好地記錄到各自的目標。

然後我寫了一個記錄器工廠,這將返回正確實施ILogger接口的基礎上,記錄類型:

/// <summary> 
/// Provides an interface for a factory which returns a logger component. 
/// </summary> 
public interface ILoggerFactory 
{ 
    /// <summary> 
    /// Creates an instance of logger component based on dependency registration key. 
    /// </summary> 
    /// <param name="loggerName">The dependency registration key.</param> 
    /// <returns>An Instance of logger component.</returns> 
    ILogger CreateLogger(string loggerName); 
} 

和實現:

/// <summary> 
/// Implementation of ILoggerFactory interface. 
/// </summary> 
public class NLogLoggerFactory : ILoggerFactory 
{ 
    private readonly ILogger _nlogDatabaseLogger; 
    private readonly ILogger _nlogFileLogger; 

    public NLogLoggerFactory(ILogger nlogDatabaseLogger, ILogger nlogFileLogger) 
    { 
     if (nlogDatabaseLogger == null) 
      throw new ArgumentNullException("nlogDatabaseLogger"); 

     if (nlogFileLogger == null) 
      throw new ArgumentNullException("nlogFileLogger"); 

     _nlogDatabaseLogger = nlogDatabaseLogger; 
     _nlogFileLogger = nlogFileLogger; 
    } 

    /// <summary> 
    /// Creates an instance of logger component based on dependency registration key. 
    /// </summary> 
    /// <param name="loggerKey">The dependency registration key.</param> 
    /// <returns>An Instance of logger component.</returns> 
    public ILogger CreateLogger(string loggerKey) 
    { 
     if (loggerKey.Equals(DependencyRegistrationKeys.NLogDatabaseLoggerKey)) 
      return _nlogDatabaseLogger; 

     if (loggerKey.Equals(DependencyRegistrationKeys.NLogFileLoggerKey)) 
      return _nlogFileLogger; 

     throw new ArgumentException("Invalid loggerKey"); 
    } 

所以我去佈線這一切都與統一。這是快速的測試情況下,我懷孕了(我知道這需要重新分解,但它是用於說明目的):

[Test] 
    public void Test_if_logger_factory_returns_correct_implementation() 
    { 
     var container = new UnityContainer(); 
     container.RegisterType<ILogUtility, NLogUtility>(); 
     container.RegisterType<ILogger, NLogDatabaseLogger>(DependencyRegistrationKeys.NLogDatabaseLoggerKey); 
     container.RegisterType<ILogger, NLogFileLogger>(DependencyRegistrationKeys.NLogFileLoggerKey); 
     container.RegisterType<ILoggerFactory, NLogLoggerFactory>(
      new InjectionConstructor(
       new ResolvedParameter<ILogger>(DependencyRegistrationKeys.NLogDatabaseLoggerKey), 
       new ResolvedParameter<ILogger>(DependencyRegistrationKeys.NLogFileLoggerKey))); 

     var loggerFactory = container.Resolve<ILoggerFactory>(); 
     Assert.IsAssignableFrom<NLogLoggerFactory>(loggerFactory); 

     var logger = loggerFactory.CreateLogger(DependencyRegistrationKeys.NLogDatabaseLoggerKey); 
     Assert.IsNotNull(logger); 
     Assert.IsAssignableFrom<NLogDatabaseLogger>(logger); 
    } 

一切都很好,直到我打了一行:

var loggerFactory = container.Resolve<ILoggerFactory>(); 

這似乎打NLogDatabaseLogger的構造符合市場預期,並與例外在這條線炸燬:

//initialize the _logger 
_logger = LogManager.GetLogger("DatabaseLogger"); 

例外:

Required parameter 'FileName' on 'File Target[CustomFileLog_wrapped]' was not specified. 

我的猜測是,Unity正在努力獲取NLog,以獲取命名記錄器實例。有沒有人遇到過這個?這是否有辦法解決這個問題?整整一個早晨,我都爲此感慨萬分,但沒有骰子。任何幫助將非常感激!

+1

LogManager的代碼在哪裏?那是來自NLog嗎?因爲LogManager.GetLogger看起來像是一個靜態方法調用,所以我不認爲Unity是問題,NLogLoggerBase會是我認爲有問題的代碼的位置 –

+0

確實,LogManager是由NLog公開的靜態類。我結束了將FileTarget代碼移動到app.config文件 – tranceporter

回答

3

看看這個問題和我的答案。

How to Inject Log4Net ILog implementations using Unity 2.0

的問題是有關解決使用統一命名log4net的記錄器,但我認爲你應該能夠在同一過程適用於NLOG和統一。

該問題的OP寫了一個nice blog post,描述了他經歷這個工作的確切過程。從他的博客文章中,這些是所需的步驟(假設一些統一知識):

在Unity中實現此步驟需要三個步驟。

  1. 創建構建跟蹤擴展
  2. 創建一個記錄器創建擴展
  3. 線擴展到Unity

祝你好運!

+0

乾杯!我已經有一個LoggingUnityExtension,但我不知道使用BuildStrategies。我現在有它的工作,但如果它再次停止工作,我已經爲博客文章添加了書籤! – tranceporter

+0

很高興能幫到你! – wageoghe