记录最佳实践

时间:2009-02-23 00:38:58

标签: .net asp.net logging tracing

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

框架

您使用哪些框架?

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

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

您是手动编写此代码,还是使用某种形式的面向方面编程来执行此操作?小心共享代码片段?

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

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

监听

您使用什么日志输出?

  • 文本文件
  • XML文件
  • 事件日志
  • 其他?

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

查看

您可以使用哪些工具查看日志?

  • 记事本
  • 活动查看器
  • Systems Center Operations Manager / Microsoft Operations Manger
  • WCF服务跟踪查看器
  • 其他?

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

自定义性能计数器怎么样?

10 个答案:

答案 0 :(得分:232)

答案 1 :(得分:40)

我必须加入推荐log4net的合唱团,在我的情况下来自平台灵活性(桌面.Net / Compact Framework,32/64-bit)的观点。

但是,将其包装在私有标签API中是主要反模式log4net.ILogger已经是Commons Logging包装器API的.Net对应物,因此已经为您最小化了耦合,并且由于它也是一个Apache库,因此通常不会引起关注“不要放弃任何控制:如果必须的话,请把它分开。”

我见过的大多数房屋包装工具库也会犯下一连串的错误:

  1. 使用全局单例记录器(或等效的静态入口点),如果没有其他选择性增益,则会失去建议logger-per-class pattern的精细分辨率。
  2. 未公开可选的Exception参数,导致多个问题:
    • 它使异常日志记录策略更难以维护,因此没有任何事情与异常一致。
    • 即使使用一致的策略,将异常格式化为字符串也会过早丢失数据。我编写了一个自定义ILayout装饰器,可以对异常执行详细的深入分析,以确定事件链。
  3. 未公开IsLevelEnabled属性,这会在关闭区域或级别的日志记录时放弃跳过格式化代码的功能。

答案 2 :(得分:18)

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

框架

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

记录器输出

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

另见this question of mine

答案 3 :(得分:17)

我没有资格评论.Net的日志记录,因为我的面包和黄油是Java,但是我们在过去8年中的日志记录中有一个迁移,你可能会发现你的问题有用的类比。 / p>

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

我们目前的记录器版本允许多个实例定义为默认值。我们可以实例化具有不同日志记录级别的任意数量的子记录器,但是该体系结构最有用的方面是只需更改日志记录属性即可为各个包和类创建记录器。第二课是创建一个灵活的系统,允许在不改变代码的情况下覆盖其行为。

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

希望这有帮助!

*编辑*

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

答案 4 :(得分:9)

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

我们选择它的原因如下:

  • 在各种环境下进行简单配置/重新配置
  • 预先建好的appender数量
  • 我们使用的其中一个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进行冗余调用(因此,如果未启用Debug,则会忽略调试语句),但是当我得到一些时间我会更新它以暴露那些,这样你就可以自己做检查。这将阻止在不应该进行评估时进行评估,例如:

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. 电子邮件发送错误&amp;致命
  3. 文件以每天滚动或10mb(IIRC)的形式完成。我们不使用EventLog,因为它可能需要比我们通常想要提供站点更高的安全性。

    我发现Notepad在阅读日志时效果很好。

答案 5 :(得分:8)

您使用哪些框架?

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

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

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

您使用了哪些日志输出?

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

您可以使用哪些工具查看日志?

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

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

答案 6 :(得分:6)

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

实际上有很多针对.NET的日志框架和工具。对DotNetLogging.com上的不同工具进行了概述和比较。

答案 7 :(得分:5)

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

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

答案 8 :(得分:1)

我们在网络应用程序上使用log4net。

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

它还允许您定位特定的类或属性以进行登录。当您知道错误发生的位置时,这非常方便。一个典型的例子是NHibernate,你只想看到进入数据库的SQL。

编辑:

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

答案 9 :(得分:1)

就面向方面的日志记录而言,我在另一个问题上推荐了PostSharp -

Aspect Oriented Logging with Unity\T4\anything else

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