使用.NET 4.5.1,如何使用ETW提供的一些非直观属性?

时间:2014-01-22 19:49:02

标签: .net tracing etw

With the advancements in .NET v4.5.1,我想跳上ETW的潮流。但是,目前还不清楚如何最好地使用某些属性来创建直观的自定义跟踪。如何使用EventAttribute提供的一些非直观属性?鉴于框架和支持工具的发展,这些属性很少使用历史工件吗?

直观的属性:

  • 频道
  • 等级
  • 消息
  • 关键字(过滤事件的推荐机制)

非直觉属性:

  • 操作码
  • 任务

例如,给定ServiceInbound等自定义事件,我可以看到使用OpCodes来区分Begin和End。但是由于API我必须创建两个单独的方法,为什么我要使用OpCode属性?

    public static class CustomOpcode
    {
        public const EventOpcode Begin = (EventOpcode) 0x0001;
        public const EventOpcode End = (EventOpcode) 0x0002;
    }

    [Event(1, 
        Level = EventLevel.Informational,
        Channel = EventChannel.Operational, 
        Opcode = CustomOpcode.Begin)]
    public void ServiceInboundBegin(string message)
    {
        WriteEvent(1, message);
    }

    [Event(2, 
        Level = EventLevel.Informational,
        Channel = EventChannel.Operational, 
        Opcode = CustomOpcode.End)]
    public void ServiceInboundEnd(string message)
    {
        WriteEvent(2, message);
    }

1 个答案:

答案 0 :(得分:12)

杰森,

我决定在这里详细解答,所以我在博客文章中做到了,你可以在这里找到:http://msmvps.com/blogs/kathleen/archive/2014/01/24/how-are-event-parameters-best-used-to-create-an-intuitive-custom-evnetsourcetrace.aspx

Kathleen Dollard


来自博客文章的内容

<强>频道

ETW支持四种基本渠道和自定义渠道的潜力。 EventSource不支持自定义渠道(如果您有用户故事,请与我或团队联系)。默认通道和当前支持内联清单的唯一通道是调试通道。

Channel参数仅存在于NuGet版本中,仅用于访问其他渠道,主要是访问EventViewer以获取管理员消息的管理员渠道。我是为这种能力而奋斗的人之一,但它是针对一组非常有限的案例。几乎所有事件都在逻辑上写入您的频道 - 默认频道 - 调试频道。

要写入EventViewer,您需要写入管理员频道并在目标计算机上安装清单。这在我的视频中的规范中有记录,我确定有几篇博客文章。写入管理通道的任何内容都应该可以通过ETW(Windows)指南进行操作。

仅当操作和分析渠道属于您的应用程序要求或您支持特定工具时才使用它。

在几乎所有情况下,忽略Event属性上的Channel参数,并允许跟踪事件转到Debug通道。

<强>等级

适用于管理频道

如果您正在写入管理员频道,那么它应该是可操作的。信息很少可以采取行动。如果您希望告诉他们(不是您,不是后来的开发者,而是操作员),请使用警告您希望他们担心。也许响应时间接近SLA的容差。使用错误告诉他们做某事。也许组织中的某个人正试图做一些他们不被允许做的事情。只告诉他们他们需要知道什么。很少有消息,但相对冗长且非常清楚发生了什么,可能包括响应建议。这是“危险,危险将罗宾逊”的时间。

对于调试通道

这是您与未来的开发人员或未来版本合并的时间旅行思路。

我很幸运能与Vance,Dan和Cosmin多次坐下来,这是他们几乎完全陷入困境的问题之一。绝大多数情况下,您的应用程序可以并且可能应该在打开默认信息的情况下运行。

如果您正在查看一个明确代表您作为开发人员所关注的事件 - 您想要吓唬后来的开发人员,因为它会吓到您 - 就像严重失败的断言 - 使用警告。如果某人持有一万个条目的跟踪文件,那么您认为三件事或十件事情告诉他们问题在哪里?如果他们在警告(非信息级别)上运行,他们真正需要知道什么?

如果是错误,请使用错误级别。

如果这是一个非常频繁,很少有趣的事件,请使用详细信息。频繁发生的频率是每秒数千次。

在大多数情况下,请使用Event属性的Level参数的默认信息级别。根据团队理念,忽略它或记录它。

<强>关键字

如果您有详细的事件,则需要以智能方式打开和关闭它们。一组详细事件需要关键字才能执行此操作。

警告和错误级别不需要关键字。它们应该打开,读者想要所有这些。

错过事件的危险远大于收集信息事件的成本,而信息事件应该在不关心关键字的情况下开启。如果不打算使用关键字来过滤集合,则它们唯一的值是过滤跟踪输出。有很多其他方法可以过滤跟踪,关键字没有用处。

在大多数情况下,仅将Event属性的Keywords参数用于详细事件,并使用它们对可能需要的详细事件进行分组。使用关键字尽可能描述预期的调试任务。事件可以包括几个关键字。

<强>任务

在生活的过山车上,我们刚刚进入一个可怕的隧道 - ETW跟踪事件命名的阴暗世界。就ETW而言,您的事件使用数字ID进行标识。周期。

跟踪事件的消费者有一个清单 - 要么是因为它是内联的(调试通道的默认值,由PerfView支持并逐渐受到WPR / WPA的支持),要么安装在消耗跟踪的计算机上。清单不包含消费者使用的事件名称。

按照惯例,消费者会从您的任务和操作码中命名。

EventSource的存在是为了隐藏ETW的古怪(和优雅)。因此它采用您的方法的名称并将其转换为任务。除非您指定任务。然后,它将您的任务用作任务,并忽略您的方法的名称。知道了吗?

在几乎所有情况下,不要为Event属性指定Task参数,但要将方法的名称视为Task名称(请参阅Opcode for exception)。

<强>操作码

我希望我能够止步于此,但杰森指出了一个关键问题。 Start和Stop操作码对于评估跟踪非常重要,因为它们允许计算经过的时间。当您提供这些操作码时,您希望提供任务以确保正确命名。

请考虑人类。他们看到方法的名称,他们认为这是消费者中显示的名称。为了善良,使它成为现实。如果指定任务和操作码,请确保方法名称是串联。请

这很乱。我正在研究一些IDE生成快捷方式来简化EventSource的创建,这是一个关键原因。我认为这会有所帮助,但需要下一次公开发布Roslyn。

几乎从不使用开始/停止以外的操作码参数。

当使用开始/停止操作码时,还提供一个任务并确保方法的名称是为了人类而与操作码连接的任务。

版本

您可以使用Event属性的version参数来告知消费者是否有正确版本的清单。版本控制不是ETW的优势 - 事件在我们开发参与之前很少改变,现在我们有内联清单(到调试通道)。您可以使用它,您正在使用的特定消费者可以使用它做出聪明的事情。即便如此,在使用已安装清单的任何机器上都会正确安装清单。

总的来说,我看到这条路上有些痛苦。

版本化ETW事件的广泛规则不是。除了在最后添加额外的数据(方法和WriteEvent调用的参数)之外,不要更改它们。特别是,永远不要以可能赋予价值不同含义的方式重新排列。如果必须删除值,请强制指示缺失的默认值或标记值。如果必须更改跟踪输出,请创建新事件。是的,这个建议很糟糕。最后以“2”结束的新事件很糟糕。尽可能做好前期规划(包括保密问题),以避免以后对有效负载结构进行更改。

最初忽略Event属性的Version参数(使用默认值),但在更改事件有效内容时递增。但只能在最后添加有效负载项,除非你可以肯定没有已安装的清单(我认为你不能)。

<强>消息

您是否注意到我说到目前为止,很少使用Event属性中的任何参数?几乎从不使用它们。

另一方面,Message参数是你的朋友。

EventSource最重要的方面是记录代码调用者需要的事件。这是Event方法的声明。传递的每个项目应尽可能小,非机密,并且具有非常清晰的参数名称。

针对您的事件撰写的人看到了一个可用的日志方法声明,例如“IncomingDataRequest(string Entity,string PrimaryKey)。”他需要多长时间才能获得这行代码? “IncomingRequest(string msg)”让开发人员想知道消息是什么,或者它是否是正确的方法。我在即将发布的关于使用泛型的视频中得到了一些内容,使其更加具体。

不仅通过加快编写将调用Event方法的代码(从调用点删除所有决策)来特别关注事件方法参数,而且(大多数)消费者将此数据视为单独的列。他们将以非常漂亮的方式展示它。大多数消费者允许按任何列进行排序和过滤。甜!

这就是强类型事件的全部内容。

像“msg”这样的方法参数不会削减它。周期。

除了清晰度问题之外,字符串相对于事件有效负载而言相对较大。您希望能够输出大量事件 - 您不希望大事件有效负载填满您的磁盘。如果你还使用String.Format准备一条可能永远不会输出的消息,那么性能就会很快开始吸收。

有时参数的含义从事件名称中显而易见。通常情况并非如此。 Message参数的内容包含在清单中,允许使用者显示包含文字的友好文本字符串,以及事件有效负载的任何部分看起来很有趣。类似于String.Format() - “Message”参数实际上更好地描述为“格式”参数。由于它在清单中,它应该包含所有可重复的部分。让强类型数据仅包含对跟踪事件的特定调用的唯一性。

Message参数使用花括号,让您感到温暖和模糊。真好。但是您在参数中键入的实际字符串将传递给使用者,并使用ETW友好百分号替换花括号。不要指望消费者能够识别String.Format()的丰富性。至少不是今天的消费者。

通过将数据拆分为强类型块并提供单独的Message参数,评估跟踪的人员可以按列排序并阅读您的消息。事件有效负载仅包含数据,清单允许您使用漂亮的罗嗦消息。喝啤酒也喝。

尚未售出?如果您正在写入使用已安装清单的频道,则还可以本地化该邮件。如果您要写入管理员频道以便在EventViewer中使用,这可能很重要。

几乎总是使用Message,因此消费者可以提供人类友好的强类型事件有效负载视图。

<强>摘要

EventSource使用有四个基本规则:

  1. 提供良好的事件方法名称
  2. 提供强类型的有效载荷数据 - 考虑机密性 - 并努力在第一时间获得有效载荷内容(尽可能小)
  3. 使用event属性的Message参数获取友好的友好消息
  4. 对于每个其他Event属性参数 - 简化,简化和简化。使用默认值,除非您尝试执行默认设置不允许的操作