323

我想了解人们如何处理真实应用程序中的跟踪和日志记录。以下是一些可能有助于解释您的答案的问题。

构架

你使用什么框架?

  • log4net
  • System.Diagnostics.Trace
  • System.Diagnostics.TraceSource
  • 记录应用程序块
  • 其他?

如果使用跟踪,是否使用 Trace.Correlation.StartLogicalOperation?

您是手动编写此代码,还是使用某种形式的面向方面编程来完成它?愿意分享代码片段吗?

您是否对跟踪源提供任何形式的粒度?例如,WPF TraceSources 允许您在不同级别配置它们:

  • System.Windows -所有 WPF 的设置
  • System.Windows.Animation -专门为动画覆盖。

听众

您使用什么日志输出?

  • 文本文件
  • XML 文件
  • 事件簿
  • 其他?

如果使用文件,您使用滚动日志还是仅使用单个文件?您如何使日志可供人们使用?

查看

您使用什么工具来查看日志?

  • 记事本
  • 尾巴
  • 事件查看器
  • 系统中心运营经理/微软运营经理
  • WCF 服务跟踪查看器
  • 其他?

如果您正在构建 ASP.NET 解决方案,您是否还使用 ASP.NET 健康监控?您是否在运行状况监视器事件中包含跟踪输出?Trace.axd 呢?

自定义性能计数器呢?

4

10 回答 10

232

更新:对于 System.Diagnostics 的扩展,提供一些您可能需要的缺少的侦听器,请参阅 CodePlex 上的 Essential.Diagnostics ( http://essentialdiagnostics.codeplex.com/ )


构架

问:你们使用什么框架?

答:System.Diagnostics.TraceSource,内置于 .NET 2.0。

它为应用程序提供了强大、灵活、高性能的日志记录,但是许多开发人员并没有意识到它的功能并且没有充分利用它们。

在某些领域,附加功能很有用,或者有时功能存在但没有很好的文档记录,但这并不意味着整个日志框架(设计为可扩展的)应该像一些流行的替代方案一样被丢弃并完全替换(NLog、log4net、Common.Logging 甚至 EntLib 日志记录)。

与其改变向应用程序添加日志语句的方式并重新发明轮子,不如在您需要的几个地方扩展 System.Diagnostics 框架。

在我看来,其他框架,甚至是 EntLib,都只是患有 Not Invented Here Syndrome,我认为他们浪费了时间重新发明在 System.Diagnostics 中已经很好工作的基础知识(例如您如何编写日志语句),而不是填补现有的少数空白。简而言之,不要使用它们——它们不是必需的。

你可能不知道的功能:

  • 使用采用格式字符串和参数的 TraceEvent 重载可以帮助提高性能,因为参数作为单独的引用保存,直到 Filter.ShouldTrace() 成功。这意味着在系统确认消息之前不会对参数值进行昂贵的 ToString() 调用。
  • Trace.CorrelationManager 允许您关联有关相同逻辑操作的日志语句(见下文)。
  • VisualBasic.Logging.FileLogTraceListener 适合写入日志文件并支持文件轮换。尽管在 VisualBasic 命名空间中,它也可以很容易地在 C#(或其他语言)项目中使用,只需包含 DLL。
  • 使用 EventLogTraceListener 时,如果您使用多个参数和空或 null 格式字符串调用 TraceEvent,则如果您使用本地化消息资源,则参数将直接传递给 EventLog.WriteEntry()。
  • 服务跟踪查看器工具(来自 WCF)对于查看活动相关日志文件的图表非常有用(即使您没有使用 WCF)。这确实可以帮助调试涉及多个线程/活动的复杂问题。
  • 通过清除所有侦听器(或删除默认值)来避免开销;否则 Default 会将所有内容传递给跟踪系统(并产生所有 ToString() 开销)。

您可能希望扩展的区域(如果需要):

  • 数据库跟踪侦听器
  • 彩色控制台跟踪侦听器
  • MSMQ / 电子邮件 / WMI 跟踪侦听器(如果需要)
  • 实现 FileSystemWatcher 以调用 Trace.Refresh 以进行动态配置更改

其他建议:

使用结构化事件ID,并保留一个参考列表(例如,将它们记录在一个枚举中)。

为系统中的每个(重要)事件拥有唯一的事件 ID 对于关联和查找特定问题非常有用。很容易追溯到记录/使用事件 ID 的特定代码,并且可以很容易地为常见错误提供指导,例如错误 5178 表示您的数据库连接字符串错误等。

事件 id 应该遵循某种结构(类似于电子邮件和 HTTP 中使用的回复代码理论),这允许您在不知道具体代码的情况下按类别对待它们。

例如,第一个数字可以详细说明一般类:1xxx 可用于“开始”操作,2xxx 用于正常行为,3xxx 用于活动跟踪,4xxx 用于警告,5xxx 用于错误,8xxx 用于“停止”操作,9xxx 用于致命错误,等等

第二个数字可以详细说明区域,例如21xx表示数据库信息(41xx表示数据库警告,51xx表示数据库错误),22xx表示计算模式(42xx表示计算警告等),23xx表示另一个模块等。

分配的结构化事件 ID 还允许您在过滤器中使用它们。

问:如果使用跟踪,是否使用 Trace.Correlation.StartLogicalOperation?

答: Trace.CorrelationManager 对于在任何类型的多线程环境中关联日志语句非常有用(这在当今几乎是任何事情)。

您至少需要为每个逻辑操作设置一次 ActivityId 才能关联。

然后可以将 Start/Stop 和 LogicalOperationStack 用于简单的基于堆栈的上下文。对于更复杂的上下文(例如异步操作),使用 TraceTransfer 到新的 ActivityId(在更改它之前)允许关联。

服务跟踪查看器工具可用于查看活动图(即使您不使用 WCF)。

问:您是手动编写此代码,还是使用某种形式的面向方面编程来编写?愿意分享代码片段吗?

答:您可能想要创建一个范围类,例如 LogicalOperationScope,它 (a) 在创建时设置上下文,并且 (b) 在释放时重置上下文。

这允许您编写如下代码来自动包装操作:

  using( LogicalOperationScope operation = new LogicalOperationScope("Operation") )
  {
    // .. do work here
  }

在创建范围时,如果需要,可以首先设置 ActivityId,调用 StartLogicalOperation,然后记录 TraceEventType.Start 消息。在 Dispose 上,它可以记录停止消息,然后调用 StopLogicalOperation。

问:你们是否提供任何形式的跟踪源粒度?例如,WPF TraceSources 允许您在不同级别配置它们。

答:是的,随着系统变得越来越大,多个跟踪源很有用/很重要。

虽然您可能希望始终记录所有警告及以上消息,或所有信息及以上消息,但对于任何规模合理的系统,活动跟踪(启动、停止等)和详细日志记录的数量会变得过多。

与其只有一个开关可以将其全部打开或关闭,不如能够一次为系统的一个部分打开此信息很有用。

这样,您可以从通常的日志记录(所有警告、错误等)中找到重大问题,然后“放大”您想要的部分并将它们设置为活动跟踪甚至调试级别。

您需要的跟踪源的数量取决于您的应用程序,例如,您可能希望每个程序集或应用程序的每个主要部分都有一个跟踪源。

如果您需要更精细的控制,请添加单独的布尔开关来打开/关闭特定的高容量跟踪,例如原始消息转储。(或者可以使用单独的跟踪源,类似于 WCF/WPF)。

您可能还需要考虑将活动跟踪与一般(其他)日志记录分开的跟踪源,因为它可以更容易地按照您的需要配置过滤器。

请注意,即使使用不同的源,消息仍然可以通过 ActivityId 关联,因此请根据需要使用尽可能多的消息。


听众

问:您使用什么日志输出?

这可能取决于您正在编写的应用程序类型以及正在记录的内容。通常不同的东西会出现在不同的地方(即多个输出)。

我通常将输出分为三组:

(1) 事件 - Windows 事件日志(和跟踪文件)

例如,如果编写服务器/服务,那么在 Windows 上的最佳实践是使用 Windows 事件日志(您没有要报告的 UI)。

在这种情况下,所有致命、错误、警告和(服务级别)信息事件都应转到 Windows 事件日志。信息级别应保留给这些类型的高级事件,即您想要在事件日志中进入的事件,例如“服务启动”、“服务停止”、“连接到 Xyz”,甚至可能是“计划启动” 、“用户登录”等。

在某些情况下,您可能希望将事件日志写入应用程序的内置部分,而不是通过跟踪系统(即直接写入事件日志条目)。这意味着它不会被意外关闭。(请注意,您仍然希望在跟踪系统中记录相同的事件,以便进行关联)。

相反,Windows GUI 应用程序通常会将这些报告给用户(尽管他们也可能会记录到 Windows 事件日志中)。

事件也可能有相关的性能计数器(例如错误数/秒),协调任何直接写入事件日志、性能计数器、写入跟踪系统并报告给用户以使它们发生在同时。

即,如果用户在特定时间看到错误消息,您应该能够在 Windows 事件日志中找到相同的错误消息,然后在跟踪日志中找到具有相同时间戳的相同事件(以及其他跟踪详细信息)。

(2) 活动 - 应用程序日志文件或数据库表(和跟踪文件)

这是系统进行的常规活动,例如提供网页、提交股票市场交易、接受订单、执行计算等。

活动跟踪(开始、停止等)在这里很有用(以正确的粒度)。

此外,使用特定的应用程序日志(有时称为审核日志)也很常见。通常这是一个数据库表或应用程序日志文件,包含结构化数据(即一组字段)。

根据您的应用程序,这里的情况可能会有些模糊。一个很好的例子可能是一个将每个请求写入网络日志的网络服务器;类似的示例可能是消息传递系统或计算系统,其中每个操作都与特定于应用程序的详细信息一起记录。

一个不太好的例子是股票市场交易或销售订单系统。在这些系统中,您可能已经记录了活动,因为它们具有重要的业务价值,但是将它们与其他操作相关联的原则仍然很重要。

除了自定义应用程序日志外,活动通常还具有相关的性能计数器,例如每秒的事务数。

一般来说,您应该协调跨不同系统的活动记录,即在增加性能计数器和记录到跟踪系统的同时写入应用程序日志。如果您同时执行所有操作(或在代码中一个接一个),那么调试问题会更容易(比它们都发生在代码中的不同时间/位置)。

(3) 调试跟踪 - 文本文件,或者 XML 或数据库。

这是详细级别和更低级别的信息(例如,用于打开/关闭原始数据转储的自定义布尔开关)。这提供了系统在子活动级别所做的事情的胆量或细节。

这是您希望能够为应用程序的各个部分打开/关闭的级别(因此有多个源)。您不希望这些东西弄乱 Windows 事件日志。有时会使用数据库,但更有可能是在特定时间后清除的滚动日志文件。

此信息与应用程序日志文件之间的一个很大区别在于它是非结构化的。虽然应用程序日志可能包含 To、From、Amount 等字段,但详细调试跟踪可能是程序员输入的任何内容,例如“检查值 X={value}, Y=false”或随机注释/标记,如“完成了,再试一次”。

一项重要的做法是确保您放入应用程序日志文件或 Windows 事件日志的内容也以相同的详细信息(例如时间戳)记录到跟踪系统。这允许您在调查时关联不同的日志。

如果您计划使用特定的日志查看器,因为您有复杂的相关性,例如服务跟踪查看器,那么您需要使用适当的格式,即 XML。否则,一个简单的文本文件通常就足够了——在较低级别的信息基本上是非结构化的,因此您可能会发现数组转储、堆栈转储等。如果您可以关联回更高级别的更多结构化日志,事情应该好好地。

问:如果使用文件,您是使用滚动日志还是仅使用单个文件?您如何使日志可供人们使用?

答:对于文件,通常您希望从可管理性的角度滚动日志文件(使用 System.Diagnostics,只需使用 VisualBasic.Logging.FileLogTraceListener)。

可用性再次取决于系统。如果您只是在谈论文件,那么对于服务器/服务,可以在必要时访问滚动文件。(Windows 事件日志或数据库应用程序日志将有自己的访问机制)。

如果您无法轻松访问文件系统,那么对数据库的调试跟踪可能会更容易。[即实现一个数据库 TraceListener]。

我为 Windows GUI 应用程序看到的一个有趣的解决方案是,它在运行时将非常详细的跟踪信息记录到“飞行记录器”中,然后当您将其关闭时,如果它没有问题,它就会简单地删除该文件。

但是,如果它崩溃或遇到问题,则不会删除该文件。如果它发现错误,或者下次运行时它会注意到该文件,然后它可以采取措施,例如压缩它(例如 7zip)并通过电子邮件发送或以其他方式提供。

如今,许多系统都将故障自动报告给中央服务器(在与用户核对之后,例如出于隐私原因)。


查看

问:您使用什么工具来查看日志?

答:如果您有多个日志出于不同的原因,那么您将使用多个查看器。

Notepad/vi/Notepad++ 或任何其他文本编辑器是纯文本日志的基础。

如果您有复杂的操作,例如带有传输的活动,那么您显然会使用像服务跟踪查看器这样的专用工具。(但如果你不需要它,那么文本编辑器会更容易)。

由于我通常将高级信息记录到 Windows 事件日志中,因此它提供了一种以结构化方式快速获取概览的方法(查找漂亮的错误/警告图标)。如果日志中没有足够的内容,您只需要开始搜索文本文件,尽管至少日志为您提供了一个起点。(此时,确保您的日志具有协调的整体变得有用)。

通常,Windows 事件日志还使这些重要事件可用于监控工具,如 MOM 或 OpenView。

其他 -

如果您登录到数据库,则可以轻松过滤和排序信息(例如,放大特定的活动 ID。(对于文本文件,您可以使用 Grep/PowerShell 或类似工具来过滤您想要的特定 GUID)

MS Excel(或其他电子表格程序)。如果您可以使用正确的分隔符导入结构化或半结构化信息,这对于分析结构化或半结构化信息很有用,以便不同的值进入不同的列。

在调试/测试中运行服务时,为了简单起见,我通常将它托管在控制台应用程序中,我发现彩色控制台记录器很有用(例如,红色表示错误,黄色表示警告等)。您需要实现自定义跟踪侦听器。

请注意,该框架不包含彩色控制台记录器或数据库记录器,因此,现在,如果您需要它们,则需要编写它们(这不是太难)。

让我很恼火的是几个框架(log4net、EntLib 等)浪费时间重新发明轮子并重新实现了基本的日志记录、过滤和日志记录到文本文件、Windows 事件日志和 XML 文件,每个框架都有自己的不同的方式(每个日志语句都不同);然后,每个人都实现了自己的版本,例如数据库记录器,而其中大部分已经存在,而只需要为 System.Diagnostics 提供更多的跟踪侦听器。谈论重复工作的巨大浪费。

问:如果您正在构建 ASP.NET 解决方案,您是否还使用 ASP.NET 健康监控?您是否在运行状况监视器事件中包含跟踪输出?Trace.axd 呢?

这些东西可以根据需要打开/关闭。我发现 Trace.axd 对于调试服务器如何响应某些事情非常有用,但它通常在使用频繁的环境或长期跟踪中没有用处。

问:自定义性能计数器呢?

对于专业应用程序,尤其是服务器/服务,我希望看到它完全配备了性能监视器计数器和记录到 Windows 事件日志。这些是 Windows 中的标准工具,应该使用。

您需要确保包含您使用的性能计数器和事件日志的安装程序;这些应该在安装时创建(以管理员身份安装时)。当您的应用程序正常运行时,它不需要具有管理权限(因此无法创建丢失的日志)。

这是练习以非管理员身份进行开发的一个很好的理由(当您需要安装服务等时,有一个单独的管理员帐户)。如果写入事件日志,.NET 将在您第一次写入时自动创建丢失的日志;如果您以非管理员身份开发,您将尽早发现这一点,并避免在客户安装您的系统但由于他们没有以管理员身份运行而无法使用它时出现令人讨厌的意外。

于 2009-06-02T14:40:23.197 回答
40

我必须加入推荐 log4net 的合唱团,就我而言,这是从平台灵活性(桌面 .Net/Compact Framework,32/64 位)的角度来看的。

但是,将其包装在私有标签 API 中是一种主要的反模式已经是Commons Logging包装器APIlog4net.ILogger的 .Net 对应物,因此耦合已经为您最小化,并且由于它也是一个 Apache 库,因此通常甚至不用担心,因为您没有放弃任何控制权:如果您愿意,请分叉它必须。

我见过的大多数房屋包装库也犯了一个或多个错误:

  1. 使用全局单例记录器(或等效的静态入口点),它失去了推荐的每类记录器模式的精细分辨率,而没有其他选择性增益。
  2. 未能公开可选Exception参数,导致多个问题:
    • 它使异常日志记录策略更加难以维护,因此没有对异常进行一致的处理。
    • 即使使用一致的策略,将异常格式化为字符串也会过早丢失数据。我编写了一个自定义ILayout装饰器,它对异常执行详细的向下钻取以确定事件链。
  3. 未能公开属性IsLevelEnabled,这会在关闭区域或日志记录级别时放弃跳过格式化代码的能力。
于 2009-02-23T03:08:50.357 回答
18

我不经常在 asp.net 中开发,但是当涉及到记录器时,我认为很多最佳实践是通用的。以下是我多年来学到的一些关于日志记录的随机想法:

构架

  • 使用一个记录器抽象框架——比如 slf4j(或者你自己的),这样你就可以将记录器实现与你的 API 分离。我已经看到许多记录器框架来来去去,你最好能够毫不费力地采用一个新的框架。
  • 尝试找到支持多种输出格式的框架。
  • 尝试找到支持插件/自定义过滤器的框架。
  • 使用可以由外部文件配置的框架,以便您的客户/消费者可以轻松调整日志输出,以便商业日志管理应用程序轻松读取它。
  • 确保不要过度使用自定义日志记录级别,否则您可能无法迁移到不同的日志记录框架。

记录器输出

  • 尽量避免使用 XML/RSS 样式的日志来记录可能遇到灾难性故障的日志。这很重要,因为如果在您的记录器没有写入结束标签的情况下关闭电源开关</xxx>,您的日志就会损坏。
  • 记录线程。否则,可能很难跟踪程序的流程。
  • 如果您必须国际化您的日志,您可能希望开发人员只使用英语(或您选择的语言)登录。
  • 有时,可以选择将日志记录语句插入 SQL 查询中,这可能是调试情况下的救命稻草。如:
    -- 调用类:com.foocorp.foopackage.FooClass:9021
    选择 * 从 foo;
  • 您需要类级别的日志记录。您通常也不想要记录器的静态实例 - 不值得进行微优化。
  • 标记和分类记录的异常有时很有用,因为并非所有异常都是一样的。因此,如果您有一个日志监视器需要在关键状态时发送通知,那么提前了解重要异常的子集会很有帮助。
  • 重复过滤器将节省您的视力和硬盘。您真的希望看到相同的日志记录语句重复 10^10000000 次吗?收到这样的消息不是更好吗: This is my logging statement - Repeated 100 times

另请参阅我的这个问题

于 2009-02-23T03:57:23.173 回答
17

我没有资格评论 .Net 的日志记录,因为我的生计是 Java,但在过去 8 年中,我们的日志记录发生了迁移,您可能会发现与您的问题有一个有用的类比。

我们从 JVM 中的每个线程使用的 Singleton 记录器开始,并为整个进程设置日志记录级别。如果我们不得不调试系统的一个非常特定的部分,这会导致大量的日志,所以第一课是分割你的日志。

我们当前的记录器化身允许多个实例,其中一个定义为默认值。我们可以实例化任意数量的具有不同日志级别的子日志记录器,但这种架构最有用的方面是能够通过简单地更改日志记录属性来为单个包和类创建日志记录器。第二课是创建一个灵活的系统,允许在不更改代码的情况下覆盖其行为。

我们正在使用围绕 Log4J 的 Apache commons-logging library。

希望这可以帮助!

* 编辑 *

在阅读了下面 Jeffrey Hantin 的帖子后,我意识到我应该注意到我们的内部日志包装器实际上变成了什么。它现在本质上是一个工厂,并且严格用于使用正确的属性文件(由于遗留原因尚未将其移动到默认位置)来获取工作记录器。由于您现在可以在命令行上指定日志记录配置文件,我怀疑它会变得更加精简,如果您正在启动一个新应用程序,我肯定会同意他的说法,即您甚至不应该费心包装记录器。

于 2009-02-23T00:56:47.680 回答
9

我们在工作中使用 Log4Net 作为日志记录提供程序,为日志实例使用单例包装器(尽管单例正在审查中,质疑它们是否是一个好主意)。

我们选择它的原因如下:

  • 各种环境下的简单配置/重新配置
  • 大量预先构建的附加程序
  • 我们使用的 CMS 之一已经内置
  • 大量的日志级别和围绕它们的配置

我应该提一下,这是从 ASP.NET 开发的角​​度讲的

我可以看到使用 .NET 框架中的 Trace 的一些优点,但我并不完全相信它,主要是因为我使用的组件并没有真正执行任何 Trace 调用。我经常使用的唯一一件事就是System.Net.Mail我能说的。

所以我们有一个包装 log4net 的库,在我们的代码中我们只需要这样的东西:

Logger.Instance.Warn("Something to warn about");
Logger.Instance.Fatal("Something went bad!", new Exception());

try {
  var i = int.Parse("Hello World");
} catch(FormatException, ex) {
  Logger.Instance.Error(ex);
}

在方法中,我们检查是否启用了日志记录级别,因此您没有对 log4net API 的冗余调用(因此,如果未启用调试,调试语句将被忽略),但是当我有时间时我将对其进行更新以公开这些内容,以便您可以自己进行检查。这将防止在不应该进行评估时进行,例​​如:

Logger.Instance.Debug(string.Format("Something to debug at {0}", DateTime.Now);

这将变成:

if(Logger.DebugEnabled) Logger.Instance.Debug(string.Format("Something to debug at {0}", DateTime.Now);

(节省一点执行时间)

默认情况下,我们在两个位置登录:

  1. 网站的文件系统(在非服务文件扩展名中)
  2. 发送错误和致命的电子邮件

文件以每天滚动或 10mb (IIRC) 的形式完成。我们不使用 EventLog,因为它可能需要比我们通常想要的站点更高的安全性。

我发现记事本可以很好地阅读日志。

于 2009-02-23T01:59:33.723 回答
8

你使用什么框架?

我们混合使用日志应用程序块和围绕 .Net 框架位工作的自定义日志帮助器。LAB 配置为输出相当广泛的日志文件,包括用于服务方法进入/退出的单独的一般跟踪文件和用于意外问题的特定错误文件。配置包括用于调试帮助的日期/时间、线程、pId 等以及完整的异常详细信息和堆栈(在意外异常的情况下)。

自定义日志记录助手使用 Trace.Correlation,并且在登录 WF 的上下文中特别方便。例如,我们有一个调用一系列顺序工作流的状态机。在每个调用活动中,我们记录开始(使用 StartLogicalOperation),然后在结束时使用 gereric 返回事件处理程序停止逻辑操作。

在尝试调试复杂业务序列中的故障时,这已被证明有用几次,因为它允许我们根据活动执行序列更快地确定 If/Else 分支决策等。

您使用什么日志输出?

我们使用文本文件和 XML 文件。文本文件是通过应用程序块配置的,但我们也从 WF 服务中获得了 XML 输出。这使我们能够捕获运行时事件(持久性等)以及通用业务类型异常。文本文件是按天和大小滚动的滚动日志(我相信 1MB 的总大小是一个滚动点)。

您使用什么工具来查看日志?

我们正在使用记事本和 WCF 服务跟踪查看器,具体取决于我们正在查看的输出组。如果您的输出设置正确,WCF 服务跟踪查看器真的非常方便,并且可以使读取输出变得更加简单。也就是说,如果我大致知道错误在哪里 - 只需阅读一个注释良好的文本文件也很好。

日志被发送到单个目录,然后根据源服务将其拆分为子目录。根目录通过一个网站公开,该网站的访问由支持用户组控制。这使我们能够查看生产日志,而无需提出请求并通过冗长的繁文缛节流程来获取生产数据。

于 2009-02-23T04:22:52.363 回答
6

作为该工具的作者,我们当然使用SmartInspect来记录和跟踪 .NET 应用程序。我们通常将命名管道协议用于实时日志记录,并将(加密的)二进制日志文件用于最终用户日志。我们使用 SmartInspect 控制台作为查看器和监控工具。

实际上有很多用于 .NET 的日志记录框架和工具。DotNetLogging.com上有不同工具的概述和比较。

于 2009-02-23T09:44:38.037 回答
5

答案中有很多很棒的建议。

一般的最佳实践是考虑谁将阅读日志。在我的情况下,它将是客户端站点的管理员。所以我记录了一些消息,这些消息给了他们一些他们可以采取行动的东西。例如,“无法初始化应用程序。这通常是由......引起的”

于 2011-01-24T13:13:06.803 回答
1

我们在 Web 应用程序中使用 log4net。

当应用程序在运行时出现故障并且您需要查看更多信息时,通过更改 XML 配置文件在运行时自定义日志记录的能力非常方便。

它还允许您针对特定的类或属性进行登录。当您知道错误发生在哪里时,这非常方便。一个经典的例子是 NHibernate,您只想查看进入数据库的 SQL。

编辑:

我们将所有事件写入数据库和 Trace 系统。我们用于错误或异常的事件日志。我们将大多数事件记录到数据库中,以便我们可以创建自定义报告并让用户在他们想要从应用程序中查看日志时查看日志。

于 2009-02-23T02:19:04.457 回答
1

就面向方面的日志而言,我在另一个 SO 问题上被推荐使用 PostSharp -

使用 Unity\T4\anything 的面向方面的日志记录

如果您正在评估日志框架,答案中提供的链接值得访问。

于 2010-09-30T14:14:46.953 回答