使用EventSource从ETW日志记录中丢失事件的风险

时间:2013-06-22 00:48:24

标签: .net logging etw etw-eventsource

我正在使用EventSource类检测我的.NET 4.5应用程序以发出ETW事件。目标是能够捕获一些这些事件(错误级别事件)以进行错误记录。

在做了一些阅读和测试之后,我担心这种错误记录方法的可靠性,特别是关于丢弃或丢失事件的可能性。如果我的错误记录无法正常工作,我需要关闭应用程序(在我的情况下,运行未报告的错误是不安全的)。使用ETW和EventSource时,如何确定我的错误得到了正确记录?

显然,答案的一部分取决于听取事件的内容。就我而言,我计划使用最新的MS Enterprise Library中的“语义记录应用程序块”。

以下是微软谈论错过事件可能原因的一个来源: About Event Tracing

他们列出了导致失踪事件的这些可能原因

  
      
  • 总事件大小超过64K。这包括ETW标头加上数据或有效负载。由于事件大小由应用程序配置,用户无法控制这些丢失的事件。

  •   
  • ETW缓冲区大小小于总事件大小。用户无法控制这些丢失的事件,因为事件大小是由记录事件的应用程序配置的。

  •   
  • 对于实时日志记录,实时使用者不会消耗足够快的事件或者不会完全存在,然后支持文件就会填满。如果在记录事件时停止并启动事件日志服务,则会导致此问题。用户无法控制这些丢失的事件。

  •   
  • 当记录到文件时,磁盘太慢而无法跟上记录速率。

  •   

要查看是否使用EventSource类以某种方式减轻了这些问题(比如,它是否以某种方式截断了大型有效负载),我做了一些测试。我尝试记录长字符串,但对于我而言,它在30,000到35,000个字符之间失败(与64KB最大事件有效负载一致)。它只是在我的语义记录应用程序块日志中对于太大的字符串,根本没有任何事件,我只能默默地做什么。之前和之后的事件都像往常一样写。

所以每当我的有效载荷中有一个字符串时,我必须通过一些截断器传递它?我是否需要手动避免生成“太快”的事件(以及如何做到这一点)?

Microsoft模式和实践应该引导我们进行良好的模式和实践...所以也许我只是在这里遗漏了一些东西。

更新

显然,消费应用中有一些关于“事件太快”情况的通知。我今天第一次收到这个:

  

级别:警告,消息:由于跟踪会话中的缓冲区溢出或架构同步延迟,某些事件将丢失:Microsoft-SemanticLogging-Etw-svcRuntime

然后在结束会议时:

  

级别:警告,消息:在跟踪会话'Microsoft-SemanticLogging-Etw-svcRuntime'中检测到丢失1个事件。

UPDATE2:

Enterprise Library Developers Guide描述了我刚才提到的行为。

  

您应该监视语义记录应用程序块生成的日志消息,以获取有缓冲区溢出和丢失消息的任何指示。例如,带有事件ID 900和901的日志消息表明接收器的内部缓冲区已溢出;在进程外方案中,事件ID 806和807指示ETW缓冲区已溢出。您可以修改接收器的缓冲配置选项,以减少缓冲区因典型工作负载而溢出的可能性。

我的问题仍然存在,我是否可以使用语义记录,同时确保在丢失错误时我的应用程序无法运行?正常的跟踪事件可能会被删除......

我目前的想法是使用老式日志记录技术使用单独的类记录“严重”错误,并通过ETW管道保持较少的严重错误(以及调试类型事件)。那真的不会太糟糕......如果我找不到更好的建议,我可以将其作为解决方案发布。

更新3:

我收到的“丢失事件”警告与缓冲区溢出无关,事实证明,如果您将空string作为有效负载值传递,则会收到此消息。

3 个答案:

答案 0 :(得分:8)

EventSource类有两个版本,一个包含在.NET Framework中,另一个包含在NuGet包Microsoft EventSource Library中。我假设你使用NuGet包,因为它包含更新的代码。

EventSource基类的构造函数有一个带有以下文档(NuGet包版本1.0.26.0)的布尔参数throwOnEventWriteErrors的重载:

  

默认情况下,调用'WriteEvent'方法不会抛出错误(它们会以静默方式丢弃事件)。这是因为在大多数情况下,用户认为记录不是“宝贵的”,并且不希望记录失败导致程序崩溃。但是对于那些日志记录很“珍贵”的应用程序,如果它失败,调用者希望做出反应,设置'throwOnEventWriteErrors'将导致在WriteEvent失败时抛出异常。注意EventWrite成功的事实并不一定意味着事件只到写入它的操作没有失败到达目的地。

不幸的是,最后一句包含一个警告,但是如果你查看EventSource的源代码,你可以看到来自OS调用的底层返回代码用于为{{1}引发不同的异常。 }和NoFreeBuffers(和其他错误)。

因此,如果您打开EventTooBig,如果throwOnEventWriteErrors类无法将事件传递给ETW,您将获得例外。但是,如果ETW由于其他原因而失败,您将不会得到任何异常但是如果您确保您的ETW通道配置正确,那么很少会发生。但是,由于您无法容忍丢失任何错误事件,因此您应该测试极端错误情况,以确保ETW按预期运行。

答案 1 :(得分:6)

有一点在上面的讨论中有两点不明确。

  1. 与丢弃事件相关的所有问题都与ETW(Windows事件跟踪)有关,而不是与EventSource有关。这在逻辑上是EventSOurces与EventListeners的对话,并且有内置的监听器可以转发给ETW。显然,当您谈论丢弃的事件时,链中任何链接的约束都会影响流经链的数据。因此,保证完全可靠性的一种方法是使用不使用ETW但直接到达数据所在位置的EventListener。我相信(语义记录应用程序块)有这样的倾听者。

  2. ETW已被成功用于可靠地转发事件,但您必须生活在上述限制范围内(事件的大小必须保持在<64K并且您必须控制事件率请注意,如果速率太高,你会知道这一点,因为WriteEvent会失败,所以你可以重试(暂停后),从而做出一些完全可靠的东西(以减慢程序为代价)。注意这种如果你真的在谈论错误(不应该以很高的速度发生错误,并且如果它们以高速率发生,那么数据丢失就不是一个有趣的问题,它们可能是多余的(同样的事情是快速启动)

  3. 总而言之,EventSource默认支持可靠事件,默认情况下ETW不支持它,但可以支持它,但ETW的默认值通常都很好。

答案 2 :(得分:-1)

尝试查看语义日志(MS Enterprise Library 6)http://msdn.microsoft.com/en-us/library/dn440729(v=pandp.60).aspx

您可以使用事件源并创建侦听器以将日志记录到事件查看器或文件或数据库(或创建自定义解决方案)

更新:即使在IoC方案中,我也会捕获事件ID 806/807。在一个拦截器中,有一部分代码实例化了我的EventSource类:如果你错过了第一个实例的引用,那么所有其他的都在构造函数上失败并在写入事件时引发事件ID 806/807

为了记录大数据,可以应用消息拆分技术