TraceLogging C/C++ 快速入门

以下部分介绍将 TraceLogging 添加到 C/C++ 用户模式代码所需的基本步骤。

先决条件

  • Microsoft Visual Studio 2013 或更高版本。
  • 编写用户模式提供程序需要 Windows 10 软件开发工具包 (SDK) 。
  • 需要 Windows 10 的 Windows 驱动程序工具包 (WDK) 才能编写内核模式提供程序。

重要

若要避免未解决EventRegister的链接器错误或EventWriteTransferEventUnregister函数,请与编译这些示例时链接advapi32.lib

若要从这些示例收集和解码事件,需要使用 tracelog 或 traceview 等工具启动跟踪,运行该示例,使用 tracelog 或 traceview 等工具停止跟踪,并使用 tracefmt 或 traceview 等解码工具对跟踪进行解码。 例如,如果我的提供程序是使用 GUID {0205c616-cf97-5c11-9756-56a2cee02ca7}定义的,我可以使用 Windows SDK 工具 跟踪日志tracefmt 查看这些示例中的事件,如下所示:

  • tracelog -start MyTraceSession -f MyTraceFile.etl -guid #0205c616-cf97-5c11-9756-56a2cee02ca7
  • 运行示例。
  • tracelog -stop MyTraceSession
  • tracefmt -o MyTraceFile.txt MyTraceFile.etl
  • notepad MyTraceFile.txt

SimpleTraceLoggingExample.h

此示例标头包括 TraceLogging API 和转发声明将用于记录事件的提供程序句柄。 任何希望使用 TraceLogging 的类都将包含此标头,然后可以开始日志记录。

#pragma once

#include <windows.h> // Definitions required by TraceLoggingProvider.h
#include <TraceLoggingProvider.h> // The C/C++ TraceLogging API

// Forward-declare the g_hMyComponentProvider variable that you will use for tracing in this component
TRACELOGGING_DECLARE_PROVIDER(g_hMyComponentProvider);

头文件包括 TraceLoggingProvider.h 定义 C/C++ TraceLogging API。 必须首先包含 windows.h ,因为它定义由 TraceLoggingProvider.h它使用的常量。

头文件转发声明将传递给 TraceLogging API 以记录事件的提供程序句柄 g_hMyComponentProvider 。 此句柄需要可供任何希望使用 TraceLogging 的代码访问。

TRACELOGGING_DECLARE_PROVIDER 是一个宏,它使用提供的名称创建 extern const TraceLoggingHProvider 句柄,如上 g_hMyComponentProvider例所示。 你将在代码文件中分配实际的提供程序句柄变量。

SimpleTraceLoggingExample.cpp

以下示例注册提供程序、记录事件并取消注册提供程序。

#include "SimpleTraceLoggingExample.h"

// Define a handle to a TraceLogging provider
TRACELOGGING_DEFINE_PROVIDER(
    g_hMyComponentProvider,
    "SimpleTraceLoggingProvider",
    // {0205c616-cf97-5c11-9756-56a2cee02ca7}
    (0x0205c616,0xcf97,0x5c11,0x97,0x56,0x56,0xa2,0xce,0xe0,0x2c,0xa7));

void main()
{

    char sampleValue[] = "Sample value";

    // Register the provider
    TraceLoggingRegister(g_hMyComponentProvider);

    // Log an event
    TraceLoggingWrite(g_hMyComponentProvider, // handle to my provider
        "HelloWorldTestEvent",              // Event Name that should uniquely identify your event.
        TraceLoggingValue(sampleValue, "TestMessage")); // Field for your event in the form of (value, field name).

    // Stop TraceLogging and unregister the provider
    TraceLoggingUnregister(g_hMyComponentProvider);
}

上面的示例包括 SimpleTraceLoggingExample.h,其中包含代码将用于记录事件的全局提供程序变量。

TRACELOGGING_DEFINE_PROVIDER宏分配存储并定义提供程序句柄变量。 提供给此宏的变量名称必须与头文件中 TRACELOGGING_DECLARE_PROVIDER 宏中使用的名称匹配。

注册提供程序句柄

在使用提供程序句柄记录事件之前,必须调用 TraceLoggingRegister 来注册提供程序句柄。 这通常在 main () 或 DLLMain () 中完成,但只要在尝试记录事件之前即可随时完成。 如果在注册提供程序句柄之前记录事件,则不会发生错误,但不会记录该事件。 上面的示例中的以下代码注册提供程序句柄。

// Define the GUID to use in TraceLoggingProviderRegister
TRACELOGGING_DEFINE_PROVIDER(
    g_hMyComponentProvider,
    "SimpleTraceLoggingProvider",
    // {0205c616-cf97-5c11-9756-56a2cee02ca7}
    (0x0205c616,0xcf97,0x5c11,0x97,0x56,0x56,0xa2,0xce,0xe0,0x2c,0xa7));

void main()
{
    char sampleValue[] = "Sample value";

    // Register the provider
    TraceLoggingRegister(g_hMyComponentProvider);

记录 Tracelogging 事件

注册提供程序后,以下代码会记录一个简单的事件。

    // Log an event
    TraceLoggingWrite(g_hMyComponentProvider, // handle to my provider
        "HelloWorldTestEvent",              // Event Name that should uniquely identify your event.
        TraceLoggingValue(sampleValue, "TestMessage")); // Field for your event in the form of (value, field name).

TraceLoggingWrite 宏最多接受 909 个参数。 事件名称以 UTF-8 格式存储。 不得在事件名称或字段名称中使用嵌入 '\0' 字符。 允许的字符没有其他限制,尽管某些事件解码器或事件处理程序可能有自己的限制。

事件名称后面的每个参数都必须包装在 TraceLogging 包装器宏中。 如果使用 C++,可以使用 TraceLoggingValue 包装宏自动推断参数的类型。 如果要在 C 中编写或想要对字段类型进行更多控制,则必须使用特定于类型的字段宏,例如 TraceLoggingInt32TraceLoggingUnicodeString等等 TraceLoggingString

除了记录单个事件之外,还可以使用 TraceLoggingActivityTraceLoggingWriteStart/TraceLoggingWriteStop 宏按活动对事件进行分组。 活动将事件关联起来,对于开始和结束的方案非常有用。 例如,可以使用活动来度量从启动应用程序开始的方案,包括初始屏幕可用所需的时间,并在应用程序的初始屏幕变为可见时结束。

活动捕获单个事件,并嵌套在该活动开始和结束之间发生的其他活动。 活动具有每个进程范围,必须从线程传递到线程,以正确嵌套多线程事件。

提供程序句柄的范围仅限于在其中定义它的模块 (DLL、EXE 或 SYS) 文件。 不应将句柄传递给其他 DLL。 如果使用B.DLL中定义的提供程序句柄在A.DLL中调用 TraceLoggingWrite 宏,则可能会导致问题。 满足此要求的最安全且最有效的方法是始终直接引用全局提供程序句柄,并且永远不会将提供程序句柄作为参数传递。

取消注册提供程序

在组件卸载之前,必须注销 TraceLogging 提供程序。 这对于 DLL 和驱动程序尤其重要。 如果 DLL 或驱动程序在未注册提供程序的情况下卸载,则可能会发生崩溃。

以下代码取消注册提供程序:

// Stop TraceLogging and unregister the provider
TraceLoggingUnregister(g_hMyComponentProvider);

兼容性

根据其配置,TraceLoggingProvider.h 可以向后兼容, (生成的程序将在Windows Vista 或更高版本) 上运行,也可以针对更高版本的 OS 版本进行优化。 TraceLoggingProvider.h 使用 WINVER (用户模式) 和NTDDI_VERSION (内核模式) 来确定它是否应与早期操作系统版本兼容,还是针对较新的 OS 版本进行优化。

对于用户模式,如果在设置 WINVER 之前包括 <windows.h><windows.h> 请将 WINVER 设置为 SDK 的默认目标 OS 版本。 如果 WINVER 设置为0x602或更高版本,请针对 Windows 8 或更高版本优化其行为, TraceLoggingProvider.h 并且你的应用不会在早期版本的 Windows 上运行。 如果需要程序在 Vista 或 Windows 7 上运行,请确保在包括 <windows.h>之前将 WINVER 设置为适当的值。

同样,如果在设置NTDDI_VERSION之前包括 <wdm.h><wdm.h> 请将NTDDI_VERSION设置为默认值。 如果NTDDI_VERSION设置为0x06040000或更高版本,TraceLoggingProvider.h 会优化 Windows 10 的行为,并且驱动程序不适用于早期版本的 Windows。

可以通过设置之前TraceLoggingProvider.h包括TLG_HAVE_EVENT_SET_INFORMATION此行为来控制此行为。 有关宏的详细信息TLG_HAVE_EVENT_SET_INFORMATION,请参阅标头中的TraceLoggingProvider.h注释。

总结和后续步骤

若要查看如何使用 Windows 性能工具 (WPT) 捕获 和查看 TraceLogging 数据,请参阅记录和显示 TraceLogging 事件

有关更多 C ++ TraceLogging 示例,请参阅 C/C++ Tracelogging 示例。