记录共享和映射的诊断上下文

时间:2008-12-23 21:29:47

标签: java .net logging apache-commons

据我所知,其他人做了什么来解决Commons Logging项目(针对.NET和Java)不支持Mapped或Nested Diagnostic Contexts的事实?

4 个答案:

答案 0 :(得分:2)

执行摘要:

我们选择直接使用实现者日志框架(在我们的例子中是log4j)。

答案很长:

您是否需要抽象的日志框架来满足您的要求?它们非常适合希望在最终使用的任何主机环境中都能很好地运行的库,但如果您正在编写应用程序,则可以在许多情况下直接使用实现日志记录框架(即通常没有任何理由)为什么日志记录实现者应该在应用程序的生命周期中进行更改。

我们选择直接使用实现者日志框架(在我们的例子中是log4j)。 Commons-Logging在类路径中可用,但它只是为了依赖它的库而存在。在我们的案例中,这是一个简单的选择,因为我所工作的公司多年来一直将log4j作为强制性标准而且不太可能改变,但即使这不太明显,也归结为一些成本/收益分析

  • NDC和其他专业功能给我的好处是什么?
  • 我必须更改日志记录实现者的机会是什么,如果必须的话,成本是多少?

并且可能:

  • 我是否必须在同步部署中支持不同的日志记录实现者?

在我们的例子中,如果我们需要更改日志记录实现者,我们将进行一些重构,但是对于org.apache.log4j包中的所有内容,这既不困难也不是非常冒险的重构 1 。 log4e Eclipes插件将自动转换实际的日志记录语句; NDC对象可能是一个问题,因为并非所有日志框架都支持这样的事情。您可以考虑在您自己控制的实用程序类中隐藏NDC.enter()和NDC.leave()方法,我们没有打扰。

<小时/> 1 )着名的最后一句

答案 1 :(得分:2)

这不是您问题的直接答案,但您是否可以选择使用Commons Logging以外的其他内容?如果你对它开放,SLF4J(简单日志外观 - http://www.slf4j.org/)是另一个似乎支持映射诊断上下文的日志抽象API。

我应该提到我没有亲自使用它,但一直在考虑使用我的下一个主要项目,因为他们声称比Commons Logging好得多。许多较新的主要开源项目似乎也在使用它(Hibernate,Spring Modules,几个Apache项目)。

答案 2 :(得分:0)

为了完整起见,我最终编写了自己非常简单的通用接口:

public interface IDiagnosticContextHandler
{
    void Set(string name, string value);
}

然后实现了Log4Net特定版本:

public class Log4NetDiagnosticContextHandler : IDiagnosticContextHandler
{
    private readonly Assembly assembly;

    private readonly Type mdcType;

    public Log4NetDiagnosticContextHandler()
    {
        this.assembly = Assembly.Load("log4net");
        this.mdcType = this.assembly.GetType("log4net.MDC", true);
    }

    public void Set(string name, string value)
    {
        this.mdcType.InvokeMember("Set", BindingFlags.InvokeMethod, null, null, new object[] { name, value });
    }
}
然后,我使用了一个IoC容器(Spring.Net)来引入正确的实现。如果稍后需要一个不同的日志记录框架,那么编写一个不同的接口实现就可以改变IoC配置。

答案 3 :(得分:0)

与原始问题和最近(已接受)的答案相比,这是迟到的,但我会将其发布给未来的搜索者。

根据Common.Logging (NET)网站,下一个版本(当前版本是2.0)应该支持这个东西。但是,目前尚不清楚何时计划此版本。 2.0于2009年4月发布。该网站称下一版本计划于“6月”发布。没有提到年份。 2009年6月和2010年6月已经过去了。

话虽如此,至少在Castle项目的git源代码库中实现了log4net / NLog“上下文”抽象。启动here并查看ExtendedLog4netLogger,GlobalContextProperties,ThreadContextProperties,ThreadContextStack和ThreadContextStacks,以了解Castle如何公开NDC和MDC。 Castle for NLog中存在类似的实现。

如果.NET的Common.Logging要实现类似的抽象,你可以通过你从LogManager返回的logger实例设置上下文值,如下所示:

ILog logger = LogManager.GetCurrentClassLogger();
logger.ThreadContextProperties["EventID"] = 123;
logger.GlobalContextPropeties["USER"] = GetUser();

除此之外,如果你想为所有日志消息设置一个特定的上下文(比如你自己的代码中传递的上下文),你可以编写自己的log4net和/或NLog抽象来插入Common.Logging以自动填充该信息。例如,假设您的应用程序具有传递的“上下文”,这有助于跟踪给定“事务”的信息。另外,为简单起见,假设您可以通过静态类(如“MyContext”)访问它。

你的WriteInternal(当你编写一个记录器抽象来插入Common.Logging时实现的东西)可能看起来像这样(这是针对NLog的.log4net可能会略有不同):

protected override void WriteInternal(CommonLoggingLogLevel logLevel, object message, Exception exception)
{
  LogLevelNLog level = GetLevel(logLevel);
  LogEventInfo logEvent = new LogEventInfo(level, _logger.Name, null, "{0}", new object[] { message }, exception);

  //Access these context values for output formatting using the event-context:item token
  logEvent.Context["ActivityID"] = MyContext.ActivityID;
  logEvent.Context["SessionID"] = MyContext.SessionID;
  logEvent.Context["TransactionStartTime"] = MyContext.TransactionStartTime;

  //Note that you can also set NDC and/or MDC here:
  NLog.MDC.Set("SoftwareVersion", MyContext.Version.ToString());
  _logger.Log(declaringType, logEvent);
}

如果您(或其他人)使用Common.Logging(NET)需要现在公开的log4net / NLog上下文属性,您可以执行类似于Castle通过日志记录抽象接口公开它们所做的事情。如果您想使用可以从日志记录调用中获取的信息自动设置上下文,您可以执行类似于我上面建议的操作。