【问题标题】:System.Diagnostics.Debug namespace vs Other logging solutions (log4net, MS Enterprise Library, etc.)System.Diagnostics.Debug 命名空间与其他日志记录解决方案(log4net、MS Enterprise Library 等)
【发布时间】:2011-03-13 21:54:28
【问题描述】:

我目前正在调查 .net 项目的各种日志记录可能性,我无法在 System.Diagnostics.Debug/Trace 功能和第三方库(如 log4net、MS Enterprise Library、NLog 等)之间做出决定。
目前我发现了这一点:

  • System.Diagnostics 配置和使用相当困难,因为您需要显式配置所有侦听器、过滤器、源等。它似乎也缺少对 DB 的批量插入(考虑写入 100'000 日志每个条目都有自己的插入,很可怕,不是吗?)。但是有些人认为不使用额外的库来做像 Logging 这样的“基本”事情是“很酷的”(当然,在某些时候,减少项目所依赖的 3rd 方库的数量是有意义的,但这次不是,我想)
  • 第三方功能更强大,通常更快,更易于使用,但配置有时也很痛苦,而且这些库通常不太可靠(例如 EntLib 神秘地突然停止日志记录等)
  • Common.Logging 怎么样?是否值得尝试(因为,正如我所听说的,它提供了各种日志记录框架的插件,并充当应用程序和所需库之间的接口)?


如果有人能指出我上面给出的比较的正确方向或纠正(或添加一些东西),我将不胜感激!也许如果你鼓励我使用第三方,你可以建议一些特定的(考虑到我们的应用程序很可能不需要任何花哨的东西,如 UDP、滚动文件等 - 只是普通文件、电子邮件、数据库和事件日志)?
提前致谢!

【问题讨论】:

  • 只要将 DEBUG/TRACE 常量内置到您的代码中(即调试,而不是发布,构建),System.Diagnostics.Debug/Trace 是否仅相关(甚至编译到代码中) ?因此,与功能齐全的日志框架相比,使用 S.D.Debug 的好处相当小。
  • 据我所知,SDDebug 仅在您以 Debug 模式构建应用程序时有效,但如果您以 Release 模式构建它,您只会获得使用 SDTrace 记录的消息(看起来与 Debug 几乎相同)。

标签: .net log4net enterprise-library system.diagnostics


【解决方案1】:

您可以通过更一般的谷歌搜索在 StackOverflow 上找到有关 log4net 和 NLog 的大量信息。

您还可以找到很多关于 System.Diagnostics 的信息。关于 System.Diagnostics 需要注意的一件事,我认为您会在 StackOverflow 上找到很多关于使用 Debug.Write/WriteLine 和 Trace.Write/WriteLine 的参考资料。一个可以说是“更好”的方法是使用 TraceSources。 TraceSources 类似于 log4net 和 NLog 中的记录器。 TraceSources 允许您对日志消息具有更高的粒度,从而更容易打开和关闭一些日志(除按级别外,按类或类别)。 TraceSources 确实有一个缺点,与 log4net 和 NLog 相比,您在代码中创建的每个 TraceSource 都必须在 app.config 中显式配置(如果您希望它实际记录)。

log4net 和 NLog 有一个分层概念,如果您要求的确切记录器未明确配置,则检查其“祖先”以查看是否配置了任何“祖先”,如果是,则请求的记录器“继承”那些设置。祖先只是记录器名称中由“.”分隔的部分。 (因此,如果您请求一个名为 "ABC.DEF.GHI" 的记录器,则祖先将是 "ABC.DEF""ABC")。也有可能(需要?)在 app.config 中有一个“根”记录器配置,如果没有显式配置并且没有配置祖先,所有记录器请求都将退回到该配置。因此,您可以只配置一个“根”记录器以在某个级别进行记录,并且您代码中的所有记录器都将在该级别记录。或者,您可以将“根”记录器配置为“关闭”,然后显式打开一个或多个记录器(或通过配置祖先)。这样,除了那些已配置的记录器之外,没有记录器会记录。

如果您查看here,您会发现一个有趣的 System.Diagnostics TraceSources 包装器,它提供了与 log4net 和 NLog 非常相似的继承能力。

举例说明:

log4net 和 NLog 中记录器的常见使用模式是获取这样的记录器:

//log4net
static ILog logger = LogManager.GetLogger(
                     System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); 

//NLog
static Logger logger = LogManager.GetCurrentClassLogger();

在这两种情况下,记录器的名称都是完全限定的类型名称。

在 app.config 文件中,如果需要,您可以只配置“根”记录器,并且两个记录器都将继承根记录器的设置(级别、附加程序/目标等)。或者,您可以为某些命名空间配置记录器。任何类型在该命名空间中定义的记录器都将继承这些记录器设置。

足够多的 log4net 和 NLog,您可能已经知道它们是如何工作的。

上面的链接说明了一个基于 TraceSource 的包装器,它允许类似的配置。所以,如果你愿意,你可以在你的课堂上做这样的事情:

static TraceSource ts = new TraceSource(
               System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

使用上面链接的包装器,您可以在更高级别(类/命名空间层次结构,而不是级别)配置 TraceSource,并在较低级别的记录器中继承这些设置。

因此,如果您的完全限定类型名称是这样的:ABC.DEF.GHI,那么您可以为 ABC 或 ABC.DEF(命名空间级别)配置 TraceSource,并且“GHI”类将继承这些设置。这确实可以减少您必须执行的配置量。

请注意,您不限于(使用任何这些日志记录平台)使用类的类型或类型名称来获取记录器。您可以定义自己的记录器命名方案,可能基于功能区域(“Communication”、“Communication.Send”、“Communication.Receive”等)。同样,您可以请求最高粒度(或不)的 logger/TraceSource,然后以任何有意义的粒度级别进行配置。

因此,您可以像这样在代码中请求记录器:

ILog logger = LogManager.GetLogger("Communication.Receive");
ILog logger = LogManager.GetLogger("Communication.Send");

Logger logger = LogManager.GetLogger("Communication.Receive");
Logger logger = LogManager.GetLogger("Communication.Send");

TraceSource ts = new TraceSource("Communication.Receive");
TraceSource ts = new TraceSource("Communication.Send");

如果您在 app.config 文件中仅配置“通信”,则所有记录器都将继承这些设置(因为它们是“通信”的后代)。如果您仅配置“Communication.Receive”,则只有“Communication.Receive”记录器会记录。 “Communication.Send”记录器将被禁用。如果同时配置“Communication”和“Commuincation.Receive”,则“Communication.Receive”记录器将记录在“Communication.Receive”设置中,而“Communication.Sender”记录器将记录在“Communication”设置中。在 log4net 和 NLog 中,继承可能不止这些,但我知道的还不够多。

您在使用 System.Diagnostics 时错过的一件事是非常轻松地格式化日志输出格式的灵活性。有一个第三方库为基于 TraceSource 的日志记录提供了非常好的可配置格式。你可以找到它here

我用过Common.Logging 一些。主要用于原型设计,但我可能会在我们的下一个项目中使用它。它工作得很好,编写自己的日志抽象来插入它相对容易(例如,如果你想编写一个类似于我上面链接的 TraceSource 抽象)。 Common.Logging 现在缺少两个重要的东西(尽管他们的网站说他们计划在“下一个”版本中发布)是日志记录上下文(如 log4net 和 NLog NDC/MDC/GDC 对象和 System.Diagnostics.CorrelationManger.LogicalOperationStack ) 和 Silverlight 的兼容性。在使用 Common.Logging 时,您仍然可以与代码中的 log4net 或 NLog 上下文对象进行交互,但这违背了它的目的,不是吗。

我不知道我有没有帮助!

以下是关于 log4net、NLog 和 TraceSource 的一些要点:

log4net - 非常流行,可能需要一些更新 - 至少是基于 .NET 4.0 构建的,几年前的最后一个版本,非常灵活。

NLog - 在许多方面与 log4net 非常相似,现在是新版本(NLog 2.0 的测试版刚刚发布)

TraceSource - 没有第三方依赖,无需您(或某人)的一些努力,不如 log4net 或 NLog 强大(关键缺陷 - 记录器层次结构,输出格式 - 两者都可以通过上面的链接轻松解决),微软提供了许多他们的组件与 System.Diagnostics 这样您就可以获得 Microsoft 的日志记录输出和交错的日志记录输出。 (通常,在其他日志系统中捕获 System.Diagnostics 很容易,因此可能不是大问题)。

虽然我没有经常使用 log4net 或 NLog,但在两者之间我会倾向于 NLog,主要是因为刚刚发布的新版本(测试版)。我认为 TraceSource 也是一个合理的选择,如果更基本的话,特别是如果您实现记录器层次结构并使用上面链接的 Ukadc.Diagnostics 库。

或者,使用 Common.Logging,您可以避免或延迟为您的底层日志记录平台做出决定,直到您准备好。无论如何,Common.Logging 的一个非常有用的方面是,您可以在开发产品时“试驾”日志平台,而无需更改任何应用程序代码。您不必等到决定使用特定的日志记录平台才能将日志记录添加到您的代码中。现在通过 Common.Logging api 添加它。当您接近交付时,您应该缩小您的日志平台选择范围。使用该平台交付(如果您重新分发日志平台),您就完成了。如果您愿意,您以后仍然可以更改。

【讨论】:

    【解决方案2】:

    我知道这是旧的,但如果您保持简单,System.Diagnostics.Trace 很容易配置。多年来,我一直在使用简单的文本编写器配置块,直接从 MSDN 文档中复制出来。

    没有人经常提到这一点,但在您的代码中,您可以使用内置的 Trace.TraceInformation、Trace.TraceWarning 和 Trace.TraceError 轻松分离 3 级跟踪输出和然后在配置文件中选择要输出的级别(参见下面的配置)。如果您在配置的“EventTypeFilter”中选择信息,您将在输出中获得全部 3 个信息。如果您选择错误,您将只会在输出中收到 TraceError 消息。大多数时候,我只是让我的错误,所以如果我的应用程序中确实发生了某些事情,我已经在我的跟踪文件中拥有该输出。在我的 Catch 块中,我将添加 TraceError 代码以输出有用的信息。 TraceInformation 非常适合输出您通过的代码中的时间或点等内容,并在此过程中转储变量值。 TraceWarning 适用于可处理但不可取的事情 - 例如 Web 服务可能需要很长时间才能完成,或者返回的数据记录数量超过可能导致未来问题的阈值。

    有一个小缺点,即所有这些跟踪代码行仍然执行,无论编译级别如何。如果将它们设置为不输出,那应该会大大减少开销。但如果您正在编写高性能代码,您可能希望将这些行包含在条件编译标记中。

    <system.diagnostics>
      <sharedListeners>
        <add name="MyTraceListener" traceOutputOptions="DateTime" type="System.Diagnostics.TextWriterTraceListener, System, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" initializeData="MyApplicationName_Trace.log">
         <!--
            Off - Does not allow any events through. 
            Error - Allows Error events through. 
            Warning - Allows Error, and Warning events through. 
            Information - Allows Error, Warning, and Information events through. 
         -->
         <filter type="System.Diagnostics.EventTypeFilter" initializeData="Error" />
        </add>
      </sharedListeners>
      <trace autoflush="true" indentsize="4">
        <listeners>
           <add name="MyTraceListener" />
        </listeners>
      </trace>
    </system.diagnostics>
    

    【讨论】:

      【解决方案3】:

      记录和跟踪是不同的关注点。日志记录与操作反馈有关。跟踪(包括由 Debug 方法提供的跟踪)与开发和测试有关。不应将跟踪代码编译到发布程序集中。 Trace 和 Debug 类通过编译器注释 (ConditionalAttribute) 实现这一点。应该优化此类代码以收集大量数据,而不是为了性能。另一方面,操作日志需要根据系统管理员/操作团队的要求针对性能和更广泛的存储机制进行优化。

      因此,我建议将 Trace/Debug 用于开发以及更强大的日志记录包用于操作。

      【讨论】:

      • 我真的怀疑某些第三方 java 端口是否比 BCL 的一部分更健壮
      【解决方案4】:

      从开发人员的角度来看,类似于 orm 的日志记录等问题不应该是手写的。有很多不错的可靠的第三方库。当然,有时需要完成一些配置工作,但与手动滚动您自己的解决方案相比,这只是水中的一滴水。

      我个人的偏好是 log4net,但这取决于您的需求。我最好的建议是查看解决方案的文档,例如 log4net 或 EntLib Logging Application Block,然后决定什么最适合您。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2010-12-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多