收集和查看 EventSource 跟踪

本文适用范围:✔️ .NET Core 3.1 及更高版本 ✔️ .NET Framework 4.5 及更高版本

入门指南介绍了如何创建最小的 EventSource 并在跟踪文件中收集事件。 本教程介绍了不同的工具如何配置在跟踪中收集的事件,然后查看跟踪。

示例应用

你将使用以下示例应用为本教程生成事件。 编译包含以下代码的 .NET 控制台应用程序:

using System.Diagnostics.Tracing;

namespace EventSourceDemo
{
    public static class Program
    {
        public static void Main(string[] args)
        {
            DemoEventSource.Log.AppStarted("Hello World!", 12);
            DemoEventSource.Log.DebugMessage("Got here");
            DemoEventSource.Log.DebugMessage("finishing startup");
            DemoEventSource.Log.RequestStart(3);
            DemoEventSource.Log.RequestStop(3);
        }
    }

    [EventSource(Name = "Demo")]
    class DemoEventSource : EventSource
    {
        public static DemoEventSource Log { get; } = new DemoEventSource();

        [Event(1, Keywords = Keywords.Startup)]
        public void AppStarted(string message, int favoriteNumber) => WriteEvent(1, message, favoriteNumber);
        [Event(2, Keywords = Keywords.Requests)]
        public void RequestStart(int requestId) => WriteEvent(2, requestId);
        [Event(3, Keywords = Keywords.Requests)]
        public void RequestStop(int requestId) => WriteEvent(3, requestId);
        [Event(4, Keywords = Keywords.Startup, Level = EventLevel.Verbose)]
        public void DebugMessage(string message) => WriteEvent(4, message);


        public class Keywords
        {
            public const EventKeywords Startup = (EventKeywords)0x0001;
            public const EventKeywords Requests = (EventKeywords)0x0002;
        }
    }
}

配置要收集的事件

大多数事件收集工具都使用这些配置选项来确定跟踪中应包括哪些事件:

  • 提供程序名称 - 这是包含一个或多个 EventSource 名称的列表。 只有在此列表中的 EventSource 上定义的事件才有资格包含在内。 若要从前面的示例应用中的 DemoEventSource 类收集事件,需要在提供程序名称列表中包括 EventSource 名称“Demo”。
  • 事件详细级别 - 对于每个提供程序,可定义一个详细级别,详细程度高于该级别的事件将从跟踪中排除。 如果指定上述示例应用中的“Demo”提供程序应在信息详细级别进行收集,则将排除 DebugMessage 事件,因为它具有更高的级别。 指定 EventLevel LogAlways(0) 是一种特殊情况,指示应包含任何详细级别的事件。
  • 事件关键字 - 对于每个提供程序,可定义一组关键字,只有至少标记了其中一个关键字的事件才包含在内。 在上述示例应用中,如果指定了 Startup 关键字,则仅包含 AppStarted 和 DebugMessage 事件。 如果未指定任何关键字,则这是一个特殊情况,表示应包含具有任何关键字的事件。

用于描述提供程序配置的约定

尽管每个工具都确定其自己的用户界面来设置跟踪配置,但在将配置指定为文本字符串时,很多工具都使用一种常见约定。 提供程序列表被指定为一个分号分隔列表,列表中的每个提供程序元素由名称、关键字和级别组成,用冒号分隔。 例如,“Demo:3:5”使用关键字位掩码 3(Startup 位和 Requests 位)和 EventLevel 5(即 Verbose)标识名为“Demo”的 EventSource。 许多工具还允许你忽略级别和关键字(如果不需要级别或关键字筛选)。 例如,“Demo::5”仅执行基于级别的筛选,“Demo:3”仅执行基于关键字的筛选,而“Demo”不执行关键字或级别筛选。

Visual Studio

Visual Studio 探查器支持收集和查看跟踪。 它还可查看其他工具(如 dotnet-trace)提前收集的跟踪。

收集跟踪

Visual Studio 的大多数分析工具都使用预定义的提供特定用途(例如分析 CPU 使用率或分配)的事件集。 若要使用自定义事件收集跟踪,请使用事件查看器工具。

  1. 要在 Visual Studio 中打开性能探查器,请选择 Alt+F2。

  2. 选中“事件查看器”复选框。

    Visual Studio 事件查看器

  3. 选择事件查看器右侧的小齿轮图标可打开配置窗口。

    在“其他提供程序”下方的表中,单击“已启用”,然后输入提供程序名称、关键字和级别,来为想要配置的每个提供程序添加一行。 无需输入提供程序 GUID;它会自动计算。

    Visual Studio 事件查看器设置

  4. 选择“确定”以确认配置设置。

  5. 选择“开始”以开始运行应用并收集日志。

  6. 选择“停止收集”或退出应用以停止收集日志并显示收集的数据。

查看跟踪

Visual Studio 可查看其自身收集的跟踪,也可查看在其他工具中收集的跟踪。 若要查看来自其他工具的跟踪,请使用“文件”>“打开”,并在文件选取器中选择跟踪文件。 Visual Studio 探查器支持 .etl 文件(ETW 的标准格式)、.nettrace 文件(EventPipe 的标准格式)和 .diagsession 文件(Visual Studio的标准格式)。 若要了解如何在 Visual Studio 中使用跟踪文件,请参阅 Visual Studio 文档

Visual Studio 事件查看器 ETW 跟踪

注意

Visual Studio 从 ETW 或 EventPipe 自动收集某些事件,即使它们未显式配置也是如此。 如果在“提供程序名称”或“事件名称”列中看到未识别的事件,并且想要筛选出它们,请使用右侧的筛选器图标来仅选择要查看的事件。

PerfView

PerfView 是 .NET 团队创建的一款性能工具,可收集和查看 ETW 跟踪。 它还可查看其他工具以各种格式收集的跟踪文件。 在本教程中,你将收集演示应用的 ETW 跟踪,然后在 PerfView 的事件查看器中检查收集的事件。

收集跟踪

  1. 发布页下载 PerfView。 本教程使用 PerfView 版本 2.0.76 完成,但任何最新版本都应正常工作。

  2. 使用管理员权限启动 PerfView.exe。

    注意

    ETW 跟踪集合始终需要管理员权限,但如果仅使用 PerfView 查看预先存在的跟踪,则不需要特殊权限。

    PerfView 主窗口

  3. 从“收集”菜单中,选择“运行”。 这将打开一个新的对话框,你将在其中输入演示应用的路径。

    PerfView“运行”对话框

  4. 若要配置收集的事件,请展开对话框底部的“高级选项”。 在“其他提供程序”文本框中,使用前面所述的常规文本格式输入提供程序。 在本例中,你将输入“Demo:1:4”,这意味着关键字位 1(Startup 事件)和详细程度 4 (Informational)。

    PerfView“运行”对话框高级设置

  5. 若要启动应用并开始收集跟踪,请选择“运行命令”按钮。 当应用退出时,跟踪 PerfViewData.etl 保存在当前目录中。

查看跟踪

  1. 在左上角的主窗口下拉文本框中,选择包含跟踪文件的目录。 然后,双击下面的树视图中的跟踪文件。

    PerfView 主窗口选择跟踪

  2. 若要调出事件查看器,请双击跟踪文件下方树视图中出现的“事件”项。

    PerfView 事件查看器

  3. 跟踪中的所有事件类型都显示在左侧列表中。 双击事件类型(如 Demo\AppStarted),在右侧表中显示该类型的所有事件。

    PerfView 事件查看器 AppStarted 事件

了解更多

若要详细了解如何使用 PerfView,请参阅 PerfView 视频教程

dotnet-trace

dotnet-trace 是一种跨平台命令行工具,可使用 EventPipe 跟踪从 .NET Core 应用中收集跟踪。 它不支持查看跟踪数据,但它收集的跟踪可由其他工具(如 PerfViewVisual Studio)查看。 dotnet-trace 还支持将其默认的 .nettrace 格式跟踪转换为其他格式,例如 Chromium 或 Speedscope

收集跟踪

  1. 下载并安装 dotnet-trace

  2. 在命令行中,运行 dotnet-trace collect 命令:

    E:\temp\EventSourceDemo\bin\Debug\net6.0>dotnet-trace collect --providers Demo:1:4 -- EventSourceDemo.exe
    

    应显示如下所示的输出:

    E:\temp\EventSourceDemo\bin\Debug\net6.0> dotnet-trace collect --providers Demo:1:4 -- EventSourceDemo.exe
    
    Provider Name                           Keywords            Level               Enabled By
    Demo                                    0x0000000000000001  Informational(4)    --providers
    
    Launching: EventSourceDemo.exe
    Process        : E:\temp\EventSourceDemo\bin\Debug\net6.0\EventSourceDemo.exe
    Output File    : E:\temp\EventSourceDemo\bin\Debug\net6.0\EventSourceDemo.exe_20220317_021512.nettrace
    
    [00:00:00:00]   Recording trace 0.00     (B)
    Press <Enter> or <Ctrl+C> to exit...
    
    Trace completed.
    

    dotnet-trace 使用 常规文本格式来描述 --providers 参数中的提供程序配置。 有关如何使用 dotnet-trace 获取跟踪的更多选项,请参阅 dotnet-trace 文档

EventListener

System.Diagnostics.Tracing.EventListener 是一个 .NET API,可在进程中使用来接收由某个 System.Diagnostics.Tracing.EventSource 生成的事件的回调。 此 API 可用于创建自定义日志记录工具,或者用于在不序列化事件的情况下分析内存中的事件。

若要使用 EventListener,请声明一个派生自 EventListener 的类型,调用 EnableEvents 来从任何感兴趣的 EventSource 订阅事件,并重写每当有新事件可用时都将调用的 OnEventWritten。 通常,重写 OnEventSourceCreated 来发现存在哪些 EventSource 对象很有帮助,但这不是必需的。 下面是一个示例 EventListener 实现,它在收到消息时向控制台输出内容:

  1. 将此代码添加到演示应用

    class ConsoleWriterEventListener : EventListener
    {
        protected override void OnEventSourceCreated(EventSource eventSource)
        {
            if(eventSource.Name == "Demo")
            {
                EnableEvents(eventSource, EventLevel.Informational);
            }
        }
    
        protected override void OnEventWritten(EventWrittenEventArgs eventData)
        {
            Console.WriteLine(eventData.TimeStamp + " " + eventData.EventName);
        }
    }
    
  2. 修改 Main 方法以创建新侦听器的实例。

    public static void Main(string[] args)
    {
        ConsoleWriterEventListener listener = new ConsoleWriterEventListener();
    
        DemoEventSource.Log.AppStarted("Hello World!", 12);
        DemoEventSource.Log.DebugMessage("Got here");
        DemoEventSource.Log.DebugMessage("finishing startup");
        DemoEventSource.Log.RequestStart(3);
        DemoEventSource.Log.RequestStop(3);
    }
    
  3. 构建并运行应用。 以前,它没有输出,但现在它会将事件写入控制台:

    3/24/2022 9:23:35 AM AppStarted
    3/24/2022 9:23:35 AM RequestStart
    3/24/2022 9:23:35 AM RequestStop