18

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

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


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

4

4 回答 4

23

您可以通过更一般的谷歌搜索在 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 中有一个“根”记录器配置,如果没有显式配置并且没有配置祖先,所有记录器请求都将退回到该配置。因此,您可以仅配置一个“根”记录器以在某个级别进行记录,并且您代码中的所有记录器都将在该级别记录。或者,您可以将“根”记录器配置为“关闭”,然后显式打开一个或多个记录器(或通过配置祖先)。这样,除了那些配置的记录器之外,没有记录器会记录。

如果你看这里,你会发现一个有趣的 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 的日志记录提供了非常好的可配置格式。你可以在这里找到它。

我用过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 添加它。当您接近交付时,您应该缩小您的日志平台选择范围。使用该平台交付(如果您重新分发日志平台),您就完成了。如果您愿意,您仍然可以稍后更改。

于 2010-10-01T18:51:47.523 回答
0

我知道这很旧,但是如果您保持简单,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>
于 2015-06-11T17:10:39.840 回答
-1

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

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

于 2010-07-09T14:28:46.093 回答
-1

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

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

于 2011-02-21T02:24:55.620 回答