【问题标题】:Setting the name of a log4net logger设置 log4net 记录器的名称
【发布时间】:2011-01-24 15:00:44
【问题描述】:

我在我的应用程序(MVC3 Web 应用程序)中使用带有 log4net 的 Castle 日志记录工具。但是,我没有直接使用 ILogger 接口,而是通过创建另一个接口 (IAuditor) 来抽象它,并使用具体实现 Log4NetAuditor(参见下面的代码)。

您可能会问我为什么这样做,因为 ILogger 的目的是抽象底层的日志记录实现。我这样做是因为严格遵守 onion architecture 抽象所有基础架构问题的原则。

现在,除了所有记录器的名称都相同之外,这一切正常:MyProject.Infrastructure.Log4NetAuditor:

2011-01-24 13:26:11,746 [11] DEBUG MyProject.Infrastructure.Log4NetAuditor [] - Attempting login...
2011-01-24 13:26:11,845 [11] DEBUG MyProject.Infrastructure.Log4NetAuditor [] - Authentication result is Authenticated

IAuditor 作为 AuditableComponent 上的属性公开,它是一个抽象类,所有需要日志记录的组件都从该类派生。

public abstract class AuditableComponent
{
    private IAuditor _auditor = NullAuditor.Instance;

    public IAuditor Auditor
    {
        get { return _auditor; }
        set { _auditor = value; }
    }

    //....
}

Log4NetAuditor 类如下所示:

public class Log4NetAuditor : IAuditor
{
    private ILogger _logger = NullLogger.Instance;

    public ILogger Logger
    {
        get { return _logger; }
        set { _logger = value; }
    }

    public void Trace(string message)
    {
        _logger.Debug(message);
    }
}

现在,为什么所有日志语句都具有相同的记录器名称的原因很清楚了:ILogger 被注入到 Log4NetAuditor 类中。

那么,如何确保记录器的名称与扩展 AuditableComponent 的类的名称相对应?

【问题讨论】:

  • 你为什么不使用 LoggingFacility?它提供了 OOTB 的功能
  • 您好 Krzystof,我正在使用 LoggingFacility。但是,我不希望在我的客户端应用程序中引用 ILogger(即 Windsor)。这就是 IAuditor 抽象的用武之地。
  • 然后看看该设施是如何工作的,您可以复制它。它是 OSS 伴侣 - 您可以随意使用和修改该代码 :)
  • 这是一个很好的建议,很明显我没有想到它 ;-) 我创建了一个工厂来为我解决问题,并在后台保留了对设施的使用,这样我的审核员可以将任何日志记录实现插入其中。好的!谢谢 Krzysztof!

标签: logging log4net asp.net-mvc-3 castle-windsor


【解决方案1】:

我和你做了同样的事情,但我还包含了一个静态 LogManager 类,它的工作是实例化你的记录器。我在 Logger 类(您的审计员类)上制作了内部构造函数,因此无法直接创建它们。这意味着任何外部实体都需要通过 LogManager 类获取它们的引用。

public static class LogManager
{
    public static readonly ILogger Log = CreateLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

    /// <summary>
    /// Creates the logger for the specified type.
    /// </summary>
    /// <param name="loggerType">Type of the logger.</param>
    /// <returns></returns>
    public static Logger CreateLogger(Type loggerType)
    {
        return new Logger(loggerType);
    }

    /// <summary>
    /// Creates the logger for the specified name.
    /// </summary>
    /// <param name="loggerName">Name of the logger.</param>
    /// <returns></returns>
    public static Logger CreateLogger(string loggerName)
    {
        return new Logger(loggerName);
    }
}

现在这些类型将能够通过将它们自己的类型传递给 Create 方法来实例化您的 Auditor。

更新 --

我也使用 Unity 容器将依赖项注入到此代码中。相关位是 InjectionFactory。它允许我在本地指定一个静态方法来根据某些条件注入一个类型。

DependencyInjection.Container.RegisterType<IFormatter>(
    new ContainerControlledLifetimeManager(),
    new InjectionFactory(c => CreateFormatter(filename, outputType)));

...

        private static IFormatter CreateFormatter(string filename, OutputType outputType)
        {
            TextWriter textWriter = (filename.Length > 0) ? new StreamWriter(filename) : new StreamWriter(Console.OpenStandardOutput());
            var formatter = (outputType == OutputType.Xml) ? (IFormatter)new XmlFormatter(textWriter) : new CsvFormatter(textWriter);

            return formatter;
        }

...
// Calling it
using (var formatter = DependencyInjection.Container.Resolve<IFormatter>())
{
    if (timeLimit <= 1000) retval = OutputResults(results, formatter, msxQuery);
    else TimedOutputResults(results, formatter, msxQuery, timeLimit, OutputResults);
}

嗯,至少对我有用!

【讨论】:

  • 感谢您的回答;这很有帮助。但是,我很难看到如何将这种方法与城堡容器结合起来?目前 IAuditor 是通过 AuditableComponent 上的属性注入的。我似乎无法弄清楚如何使用工厂方法来调用您的 LogManager...我偏离轨道了吗?
  • 我正在使用 Unity 容器。我将更新上面的代码以包含正确注入它的 Unity 代码。我停止使用 Castle Windsor 并且不记得它有这个功能。但是你仍然可以使用 windsor 来做到这一点。
  • 感谢您的帮助。你的方法很好,虽然我不知道如何将它应用到我的解决方案中,因为我在代码中的任何地方也没有引用我的容器。也就是说,你给了我一些想法,如果我能做到,我会在这里更新我的解决方案。再次感谢您。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-09-14
  • 1970-01-01
  • 1970-01-01
  • 2010-12-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多