如何使用Unity获取LogManager(NLog)的命名记录器

时间:2013-10-03 12:39:31

标签: c# dependency-injection unity-container ioc-container nlog

这将是一个冗长的问题,但请耐心等待。我正在尝试为我们的应用程序创建一个Logging组件,它可以扩展到插件新的日志记录框架(NLog,Log4Net ec)。现在我知道我们已经有了由Ben Foster编写的Common.Logging外观,但我想尝试一些更加个性化的东西。我们的主要要求之一是,我们需要一种使用日志框架(在本例中为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
{
     ....
}

哪个被提升为:

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(从NLog中的TargetWithLayout继承)登录到数据库,并使用同样的File Logger。 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>

到目前为止一切顺利。我为每个记录器进行了几次测试,并且它们可以很好地记录到各自的目标。

然后我写了一个Logger工厂,它将根据记录器类型返回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");
    }

所以我要用Unity连接它。这是我快速测试的情况(我知道它需要重新分解,但它仅用于说明目的):

    [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 个答案:

答案 0 :(得分:3)

查看这个问题和我的答案。

How to Inject Log4Net ILog implementations using Unity 2.0

问题是如何使用unity来解析命名的log​​4net记录器,但我认为您应该能够将相同的过程应用于NLog和统一。

该问题的OP写了一个nice blog post,描述了他为实现这个目的而采取的确切程序。从他的博客文章中,这些是所需的步骤(假设有一些统一的知识):

在Unity中实现此功能需要三个步骤。

  1. 创建构建跟踪扩展
  2. 创建记录器创建扩展
  3. 将扩展程序连接到Unity
  4. 祝你好运!