EnableTraceEx2 函数 (evntrace.h)

跟踪会话控制器调用 EnableTraceEx2 来配置 ETW 事件提供程序将事件记录到跟踪会话的方式。

此函数取代 EnableTraceEnableTraceEx 函数。

语法

ULONG WMIAPI EnableTraceEx2(
  [in]           TRACEHANDLE              TraceHandle,
  [in]           LPCGUID                  ProviderId,
  [in]           ULONG                    ControlCode,
  [in]           UCHAR                    Level,
  [in]           ULONGLONG                MatchAnyKeyword,
  [in]           ULONGLONG                MatchAllKeyword,
  [in]           ULONG                    Timeout,
  [in, optional] PENABLE_TRACE_PARAMETERS EnableParameters
);

参数

[in] TraceHandle

要为其配置提供程序的事件跟踪会话的句柄。 启动新的跟踪时 ,StartTrace 函数返回此句柄。 若要获取现有跟踪的句柄,请使用 ControlTrace 根据跟踪的名称查询跟踪属性,然后从返回EVENT_TRACE_PROPERTIES数据的 Wnode.HistoricalContext 字段中获取句柄。

[in] ProviderId

提供程序 ID (控制要配置的事件提供程序的 GUID) 。

[in] ControlCode

可以指定以下控制代码之一:

含义
EVENT_CONTROL_CODE_DISABLE_PROVIDER 更新会话配置,使会话不会从提供程序接收事件。
EVENT_CONTROL_CODE_ENABLE_PROVIDER 更新会话配置,以便会话从提供程序接收请求的事件。
EVENT_CONTROL_CODE_CAPTURE_STATE 请求提供程序记录其状态信息。

[in] Level

一个 值,该值指示你希望提供程序写入的事件的最大级别。 除了满足 MatchAnyKeywordMatchAllKeyword 条件外,如果事件的级别小于或等于此值,提供程序通常会写入事件。

Microsoft 定义级别 1-5 的语义,如下所示。 值越小,表示事件越严重。 Level 的每个值都启用指定的级别和所有更严重的级别。 例如,如果指定 TRACE_LEVEL_WARNING,则使用者将收到警告、错误和关键事件。

含义
TRACE_LEVEL_CRITICAL (1) 异常退出或终止事件
TRACE_LEVEL_ERROR (2) 严重错误事件
TRACE_LEVEL_WARNING (3) 警告事件,例如分配失败
TRACE_LEVEL_INFORMATION (4) 非错误信息事件
TRACE_LEVEL_VERBOSE (5) 详细诊断事件

TRACE_LEVEL 量在 evntrace.h 中定义。 等效 WINMETA_LEVEL 常量在 winmeta.h 中定义。

[in] MatchAnyKeyword

关键字的 64 位位掩码,用于确定你希望提供程序写入的事件类别。 如果事件的关键字 (keyword) 位与此值中设置的任何位匹配,或者事件没有设置关键字 (keyword) 位,除了满足 LevelMatchAllKeyword 条件外,提供程序通常会写入事件。

[in] MatchAllKeyword

关键字的 64 位位掩码,用于限制你希望提供程序写入的事件。 如果事件的关键字 (keyword) 位与此值中设置的所有位匹配,或者事件没有设置关键字 (keyword) 位,除了满足 LevelMatchAnyKeyword 条件外,提供程序通常会写入事件。

此值经常设置为 0。

[in] Timeout

如果 Timeout 为 0,则此函数将开始异步配置提供程序,并立即返回 (即,它将返回 ,而无需等待提供程序回调完成) 。

否则,此函数将开始配置提供程序,然后开始等待配置完成,包括等待所有提供程序回调完成。 如果在指定的超时之前完成配置,此函数将返回 ERROR_SUCCESS。 否则,此函数将返回 ERROR_TIMEOUT

若要永远等待,请将 设置为 INFINITE

[in, optional] EnableParameters

用于启用提供程序的跟踪参数。 有关详细信息,请参阅 ENABLE_TRACE_PARAMETERS

返回值

如果函数成功,则 返回值ERROR_SUCCESS

如果函数失败,则返回值为 系统错误代码之一。 下面是一些常见错误及其原因。

  • ERROR_INVALID_PARAMETER

    参数不正确。

    如果存在以下任一情况,则可能会发生这种情况:

    • ProviderIdNULL
    • TraceHandle0
  • ERROR_TIMEOUT

    超时值在启用回调完成之前过期。 有关详细信息,请参阅 Timeout 参数。

  • ERROR_INVALID_FUNCTION

    未注册提供程序时,无法更新级别。

  • ERROR_NO_SYSTEM_RESOURCES

    超出了可以启用提供程序的跟踪会话数。

  • ERROR_ACCESS_DENIED

    只有具有管理权限的用户、组中的用户Performance Log Users以及以 、 LocalServiceNetworkService 身份LocalSystem运行的服务才能启用跨进程会话的事件提供程序。 若要授予受限用户启用事件提供程序的能力,请将他们添加到 Performance Log Users 组或参阅 EventAccessControl

    Windows XP 和 Windows 2000: 任何人都可以启用事件提供程序。

备注

事件跟踪控制器调用此函数以配置将事件写入会话的事件提供程序。 例如,控制器可能调用此函数以开始从提供程序收集事件、调整从提供程序收集的事件的级别或关键字,或停止从提供程序收集事件。

提供程序的启用行为取决于提供程序使用的 API。

  • 使用 RegisterTraceGuids 的提供程序 (例如,使用基于 TMF 的 WPP 或 MOF) 的提供程序使用旧版启用系统, (有时称为“经典 ETW”) 。 为会话启用或重新配置旧提供程序时,ETW 运行时会通知提供程序,并提供对级别、MatchAnyKeyword 掩码的低 32 位和会话 ID 的访问权限。 然后,提供程序使用自己的逻辑来决定应启用哪些事件,并将这些事件直接发送到指定的会话。 在运行时发送到 ETW 的事件数据包括事件的解码 GUID 和消息 ID,但不包括事件的控制 GUID、级别或关键字。 ETW 验证提供程序是否具有必要的权限,然后将事件数据添加到指定的会话。
    • 由于事件直接发送到没有控制 GUID、级别或关键字 (keyword) 信息的特定会话,因此 ETW 无法对使用旧版启用系统的提供程序执行任何其他筛选或路由。 每个事件可以路由到不超过一个会话。
  • 使用 EventRegister (例如基于清单的提供程序或 TraceLogging 提供程序) 使用新式启用系统, (有时称为“crimson ETW”) 。 为会话启用或重新配置新式提供程序时,ETW 运行时会向提供程序通知级别、64 位 MatchAnyKeyword 掩码、64 位 MatchAllKeyword 掩码以及跟踪控制器指定的任何自定义提供程序端筛选数据。 然后,提供程序使用自己的逻辑来决定应启用哪些事件,尽管大多数提供程序只是复制 EventProviderEnabled 的逻辑。 提供程序将启用的事件发送到 ETW 进行路由。 发送到 ETW 的事件数据包括事件的控件 GUID、消息 ID、级别和关键字。 然后,ETW 会根据需要执行其他筛选,将事件路由到相应的会话 () 。
    • 由于事件会随描述性信息一起发送到 ETW,因此 ETW 可以在将事件添加到会话之前执行其他筛选和路由。 事件可以路由到多个会话(如果适用)。

对于使用新式启用系统的提供程序 (即使用 EventRegister) 的提供程序,ETW 支持跟踪会话控制器可通过 EnableTraceEx2EnableParameters 请求的多项功能。 (有关详细信息,请参阅 EVENT_FILTER_DESCRIPTOR 。)

  • 架构化筛选 - 这是传统的筛选设置,也称为提供程序端筛选。 控制器将一组自定义筛选器定义为传递给 EnableCallbackFilterData 中的提供程序的二进制对象。 控制器和提供程序有责任定义和解释这些筛选器。 然后,提供程序可以使用 EventWriteExFilter 参数来指示由于提供程序端筛选而不应将事件发送到的会话。 这需要控制器和提供程序的紧密耦合,因为未定义可筛选的二进制对象的类型和格式。 TdhEnumerateProviderFilters 函数可用于检索清单中定义的筛选器。
  • 范围筛选 - 根据某些提供程序是否满足范围筛选器指定的条件来启用或未启用会话。 有多种类型的范围筛选器允许基于进程 ID (PID) 、可执行文件文件名、应用 ID 和应用包名称进行筛选。 Windows 8.1、Windows Server 2012 R2 及更高版本支持此功能。
  • Stackwalk 筛选 - 这通知 ETW 仅对一组给定的事件 ID 执行堆栈访问,或者对 TraceLogging 事件执行 () 事件名称。 Windows 8.1、Windows Server 2012 R2 及更高版本支持此功能。
  • 属性筛选 - 对于清单提供程序,可以根据事件属性(如级别、关键字 (keyword) 、事件 ID 或事件名称)筛选事件。
  • 事件有效负载筛选 - 对于清单提供程序,可以根据事件是否满足基于一个或多个谓词的逻辑表达式进行动态筛选。

注意

尽管 ETW 支持强大的有效负载和属性筛选,但事件应主要基于范围筛选器或通过控制 GUID、级别和关键字 (keyword) 进行筛选。 提供程序通常在生成事件或将事件发送到 ETW 之前,直接在提供程序的代码中执行控制 GUID、级别和关键字 (keyword) 筛选。 在大多数提供程序中,按级别或关键字 (keyword) 禁用的事件对系统性能几乎没有影响。 同样,范围筛选器禁用的提供程序对系统性能几乎没有影响。 基于有效负载或除级别和关键字 (keyword) ) 以外的属性的其他类型的筛选 (通常在提供程序生成事件并将其发送到 ETW 运行时之后执行,这意味着事件会影响系统性能, (准备事件并将其发送到 ETW) 即使 ETW 筛选确定事件不应由任何会话记录。 这种筛选仅在减少跟踪数据量方面有效,对于减少跟踪 CPU 开销并不有效。

每次调用 EnableTraceEx2 时,该会话中提供程序的筛选器都会替换为传递给 EnableTraceEx2 函数的参数定义的新参数。 在单个 EnableTraceEx2 调用中传递的多个筛选器可与累加效果结合使用,但在后续调用中传递的筛选器将替换以前的一组筛选器。

若要禁用筛选,从而启用日志记录会话中的所有提供程序/事件,请调用 EnableTraceEx2,其 EnableParameters 参数指向 FilterDescCount 成员设置为 0 的 ENABLE_TRACE_PARAMETERS 结构。

传递给 EnableTraceEx2 函数的每个筛选器都由EVENT_FILTER_DESCRIPTOR中的 Type 成员指定。 EVENT_FILTER_DESCRIPTOR 结构的数组在 EnableParameters 参数中传递到 EnableTraceEx2 函数的 ENABLE_TRACE_PARAMETERS 结构中。

(特定 Type 成员) 的每种类型的筛选器在 对 EnableTraceEx2 函数的调用中只能出现一次。 某些筛选器类型允许在单个筛选器中包含多个条件。 对 EnableTraceEx2 的调用中可以包含的最大筛选器数由 evntprov.h 头文件中定义的MAX_EVENT_FILTERS_COUNT (设置;值在 Windows SDK) 的未来版本中可能会更改。

每个筛选器类型都有其自己的大小或实体限制,具体取决于EVENT_FILTER_DESCRIPTOR结构中的特定 Type 成员。 以下列表指示了这些限制。

  • EVENT_FILTER_TYPE_SCHEMATIZED

    • 筛选器大小限制: MAX_EVENT_FILTER_DATA_SIZE (1024)
    • 允许的元素数:由提供程序和控制器定义
  • EVENT_FILTER_TYPE_PID

    • 筛选器大小限制: MAX_EVENT_FILTER_DATA_SIZE (1024)
    • 允许的元素数: MAX_EVENT_FILTER_PID_COUNT (8)
  • EVENT_FILTER_TYPE_EXECUTABLE_NAME

    • 筛选器大小限制: MAX_EVENT_FILTER_DATA_SIZE (1024)
    • 允许的元素数:一个字符串,可以包含多个可执行文件名称(以分号分隔)。
  • EVENT_FILTER_TYPE_PACKAGE_ID

    • 筛选器大小限制: MAX_EVENT_FILTER_DATA_SIZE (1024)
    • 允许的元素数:一个字符串,可以包含多个用分号分隔的包 ID。
  • EVENT_FILTER_TYPE_PACKAGE_APP_ID

    • 筛选器大小限制: MAX_EVENT_FILTER_DATA_SIZE (1024)
    • 允许的元素数:单个字符串,可以包含多个包相对应用 ID (PRAID,) 用分号分隔。
  • EVENT_FILTER_TYPE_PAYLOAD

    • 筛选器大小限制: MAX_EVENT_FILTER_PAYLOAD_SIZE (4096)
    • 允许的元素数:1
  • EVENT_FILTER_TYPE_EVENT_ID

    • 筛选器大小限制:未定义
    • 允许的元素数: MAX_EVENT_FILTER_EVENT_ID_COUNT (64)
  • EVENT_FILTER_TYPE_STACKWALK

    • 筛选器大小限制:未定义
    • 允许的元素数: MAX_EVENT_FILTER_EVENT_ID_COUNT (64)

关键字定义事件类别。 例如,如果提供程序定义 InitializationKeyword = 0x1 (关键字 (keyword) 位 0) ,FileOperationKeyword = 0x2 (关键字 (keyword) 位 1) ,CalculationKeyword = 0x4 (关键字 (keyword) 位 2) ,则可以设置 MatchAnyKeywordto (InitializationKeyword |CalculationKeyword) = 5 接收初始化和计算事件,但不能接收文件事件。

基于清单 的新式 (或 TraceLogging) 提供程序一起使用时, MatchAnyKeyword0 被视为与 MatchAnyKeyword0xFFFFFFFFFFFFFFFF相同,即启用所有事件关键字。 但是,此行为不适用于基于 MOF 或 TMF 的旧 (WPP) 提供程序。 若要启用旧提供程序中的所有事件关键字,请将 MatchAnyKeyword 设置为 0xFFFFFFFF。 若要启用旧提供程序和新式提供程序中的所有事件关键字,请将 MatchAnyKeyword 设置为 0xFFFFFFFFFFFFFFFF

如果事件的关键字 (keyword) 为零,则提供程序会将事件写入会话,而不考虑 MatchAnyKeywordMatchAllKeyword 掩码。 (可以使用 EVENT_ENABLE_PROPERTY_IGNORE_KEYWORD_0 flag 禁用此行为。)

若要指示要启用提供程序组,请在 EVENT_ENABLE_PROPERTY_PROVIDER_GROUPEnableParametersEnableProperty 成员上使用 标志。

调用 EnableTraceEx2 时,提供程序可能已注册,也可能尚未注册。 如果提供程序已注册,ETW 会调用提供程序的回调函数 ((如果有任何) ),会话开始接收事件。 如果提供程序尚未注册,则 ETW 将调用提供程序的回调函数 (如果在提供程序注册后立即) ,然后会话将开始接收事件。 如果提供程序尚未注册,则提供程序的回调函数将不会收到源 ID。

如果提供程序已注册并已向会话启用,则可以再次调用 EnableTraceEx2 以更新 EnableParametersLevelMatchAnyKeywordMatchAllKeyword 参数以及 EnablePropertyEnableFilterDesc 成员。

在Windows 8.1、Windows Server 2012 R2 及更高版本上,事件有效负载、范围和堆栈演练筛选器可由 EnableTraceEx2 函数以及ENABLE_TRACE_PARAMETERSEVENT_FILTER_DESCRIPTOR结构用于筛选记录器会话中的特定条件。 有关事件有效负载筛选器的详细信息,请参阅 TdhCreatePayloadFilterTdhAggregatePayloadFilters 函数以及 ENABLE_TRACE_PARAMETERSEVENT_FILTER_DESCRIPTORPAYLOAD_FILTER_PREDICATE 结构。

EnableTraceEx2 无法启用或禁用特殊的系统跟踪提供程序事件。 只有在 StartTrace 首次启动跟踪时,才能通过 EVENT_TRACE_PROPERTIESEnableFlags 字段启用它们。

从 Windows 11 开始,可以使用 EnableTraceEx2 启用系统跟踪提供程序事件

最多八个跟踪会话可以启用和接收来自同一个 基于清单 的新式 (或 TraceLogging) 提供程序的事件。 但是,只有一个跟踪会话可以启用旧版 (MOF(基于 TMF 的 WPP) 提供程序)。 如果多个会话尝试启用旧提供程序,当第二个会话启用同一个提供程序时,第一个会话将停止接收事件。 例如,如果会话 A 启用了旧提供程序,然后会话 B 启用了同一提供程序,则只有会话 B 将从该提供程序接收事件。

在会话禁用提供程序之前,提供程序将一直为会话启用。 如果启动会话的应用程序在未禁用提供程序的情况下结束,则提供程序将保持启用状态。

若要确定用于启用基于清单的提供程序的级别和关键字,请使用以下命令之一:

  • logman 查询提供程序 provider-name
  • wevtutil gp provider-name

对于经典提供程序,由提供程序来记录和向潜在控制器提供严重性级别或启用它支持的标志。 如果提供程序希望由任何控制器启用,则提供程序应接受 0 作为严重性级别,并启用标志并将 0 解释为执行默认日志记录的请求, (任何可能) 。

如果使用 EnableTraceEx2 启用经典提供程序,将进行以下转换:

  • Level 参数与在 EnableTrace 中设置 EnableLevel 参数相同。
  • MatchAnyKeyword 与在 EnableTrace 中设置 EnableFlag 参数相同,只不过关键字 (keyword) 值从 64 位值截断为 32 位值。
  • ControlCallback 回调中,提供程序可以调用 GetTraceEnableLevel 来获取级别,并调用 GetTraceEnableFlags 以获取启用标志。
  • 不使用其他参数。

示例

以下示例演示了使用 TdhCreatePayloadFilterTdhAggregatePayloadFilters 函数对记录器会话中的特定条件进行筛选的 EnableTraceEx2 和有效负载筛选器。

#define INITGUID
#include <windows.h>
#include <stdlib.h>
#include <stdio.h>
#include <strsafe.h>
#include <evntrace.h>
#include <tdh.h>

#define MAXIMUM_SESSION_NAME 1024

#define PATH_TO_MANIFEST_FILE L"c:\\ExampleManifest.man"

//
// The following definitions would be found in the include file generated by
// message compiler from the manifest file.
//

// Provider Example-Provider Event Count 2
EXTERN_C __declspec(selectany) const GUID EXAMPLE_PROVIDER = {0x37a59b93, 0xbb25, 0x4cee, {0x97, 0xaa, 0x8b, 0x6a, 0xcd, 0xc, 0x4d, 0xf8}};

//
// Event Descriptors
//
EXTERN_C __declspec(selectany) const EVENT_DESCRIPTOR Example_Event_1 = { 0x1, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0 };
#define Example_Event_1_value 0x1
EXTERN_C __declspec(selectany) const EVENT_DESCRIPTOR Example_Event_2 = { 0x2, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0 };
#define Example_Event_2_value 0x2

//
// (End of snippet from include file)
//

// Allocate an EVENT_TRACE_PROPERTIES structure and set the needed logging session properties
PEVENT_TRACE_PROPERTIES AllocateTraceProperties(
    _In_opt_ PCWSTR LoggerName,
    _In_opt_ PCWSTR LogFileName
)
{
    PEVENT_TRACE_PROPERTIES TraceProperties = NULL;
    ULONG BufferSize;

    BufferSize = sizeof(EVENT_TRACE_PROPERTIES) +
        (MAXIMUM_SESSION_NAME + MAX_PATH) * sizeof(WCHAR);

    TraceProperties = (PEVENT_TRACE_PROPERTIES)malloc(BufferSize);
    if (TraceProperties == NULL) {
        printf("Unable to allocate %d bytes for properties structure.\n", BufferSize);
        goto Exit;
    }

    //
    // Set the session properties.
    //
    ZeroMemory(TraceProperties, BufferSize);
    TraceProperties->Wnode.BufferSize = BufferSize;
    TraceProperties->Wnode.Flags = WNODE_FLAG_TRACED_GUID;
    TraceProperties->LoggerNameOffset = sizeof(EVENT_TRACE_PROPERTIES);
    TraceProperties->LogFileNameOffset = sizeof(EVENT_TRACE_PROPERTIES) +
        (MAXIMUM_SESSION_NAME * sizeof(WCHAR));

    if (LoggerName != NULL) {
        StringCchCopyW((LPWSTR)((PCHAR)TraceProperties + TraceProperties->LoggerNameOffset),
            MAXIMUM_SESSION_NAME,
            LoggerName);
    }

    if (LogFileName != NULL) {
        StringCchCopyW((LPWSTR)((PCHAR)TraceProperties + TraceProperties->LogFileNameOffset),
            MAX_PATH,
            LogFileName);
    }

Exit:
    return TraceProperties;
}

// Free the EVENT_TRACE_PROPERTIES structure previously allocated
VOID FreeTraceProperties(
    _In_ PEVENT_TRACE_PROPERTIES TraceProperties
)
{
    free(TraceProperties);
    return;
}

// Set the values needed in a PAYLOAD_FILTER_PREDICATE for a single payload filter
FORCEINLINE VOID PayloadPredicateCreate(
    _Out_ PAYLOAD_FILTER_PREDICATE* Predicate,
    _In_ PCWSTR FieldName,
    USHORT CompareOp,
    PCWSTR Value
)
{
    Predicate->FieldName = (PWSTR)FieldName;
    Predicate->CompareOp = CompareOp;
    Predicate->Value = (PWSTR)Value;
    return;
}

int __cdecl wmain()
{
    UINT i;
    PVOID EventFilters[2];
    EVENT_FILTER_DESCRIPTOR FilterDescriptor;
    UINT PredicateCount;
    PAYLOAD_FILTER_PREDICATE Predicates[3];
    ULONG FilterCount;
    ULONG Status = ERROR_SUCCESS;
    TRACEHANDLE SessionHandle = 0;
    PEVENT_TRACE_PROPERTIES TraceProperties;
    BOOLEAN TraceStarted = FALSE;
    PCWSTR LoggerName = L"MyTrace";
    ENABLE_TRACE_PARAMETERS EnableParameters;

    ZeroMemory(EventFilters, sizeof(EventFilters));
    ZeroMemory(Predicates, sizeof(Predicates));
    TraceProperties = NULL;
    FilterCount = 0;

    //
    // Load the manifest for the provider
    //
    Status = TdhLoadManifest((PWSTR)PATH_TO_MANIFEST_FILE);
    if (Status != ERROR_SUCCESS) {
        printf("TdhCreatePayloadFilter() failed with %lu\n", Status);
        goto Exit;
    }

    //
    // Create predicates that match the following high-level expression:
    //
    // INCLUDE Example_Event_1 IF
    //     Example_Event_1.Initiator == "User" AND
    //     7 <= Example_Event_1.Level <= 16
    //
    PredicateCount = 0;

    PayloadPredicateCreate(
        &Predicates[PredicateCount++],
        (PWSTR)L"Initiator",
        PAYLOADFIELD_IS,
        (PWSTR)L"User");

    PayloadPredicateCreate(
        &Predicates[PredicateCount++],
        L"Level",
        PAYLOADFIELD_BETWEEN,
        L"7,16");

    Status = TdhCreatePayloadFilter(
        &EXAMPLE_PROVIDER,
        &Example_Event_1,
        FALSE,      // Match all predicates (AND)
        PredicateCount,
        Predicates,
        &EventFilters[FilterCount++]);
    if (Status != ERROR_SUCCESS) {
        printf("TdhCreatePayloadFilter() failed with %lu\n", Status);
        goto Exit;
    }

    //
    // Create predicates that match the following high-level expression:
    // INCLUDE Example_Event_2 IF
    //      Example_Event_2.Title CONTAINS "UNI" OR
    //      Example_Event_2.InstanceId == {0E95CFBC-58D4-44BA-BE40-E63A853536DF} OR
    //      Example_Event_2.ErrorCode != 0      //
    PredicateCount = 0;

    PayloadPredicateCreate(
        &Predicates[PredicateCount++],
        L"Title",
        PAYLOADFIELD_CONTAINS,
        L"UNI");

    PayloadPredicateCreate(
        &Predicates[PredicateCount++],
        L"InstanceId",
        PAYLOADFIELD_IS,
        L" {0E95CFBC-58D4-44BA-BE40-E63A853536DF}");

    PayloadPredicateCreate(
        &Predicates[PredicateCount++],
        L"ErrorCode",
        PAYLOADFIELD_NE,
        L"0");

    Status = TdhCreatePayloadFilter(
        &EXAMPLE_PROVIDER,
        &Example_Event_2,
        FALSE,      // Match any predicates (OR)
        PredicateCount,
        Predicates,
        &EventFilters[FilterCount++]);
    if (Status != ERROR_SUCCESS) {
        printf("TdhCreatePayloadFilter() failed with %lu\n", Status);
        goto Exit;
    }

    //
    // Combine the interim filters into a final filter descriptor.
    //
    Status = TdhAggregatePayloadFilters(
        FilterCount,
        EventFilters,
        NULL,
        &FilterDescriptor);
    if (Status != ERROR_SUCCESS) {
        printf("TdhAggregatePayloadFilters() failed with %lu\n", Status);
        goto Exit;
    }

    //
    // Clean up the interim filters
    //
    for (i = 0; i < FilterCount; i++) {

        Status = TdhDeletePayloadFilter(&EventFilters[i]);
        if (Status != ERROR_SUCCESS) {
            printf("TdhDeletePayloadFilter() failed with %lu\n", Status);
            goto Exit;
        }
    }

    //
    // Create a new trace session
    //
    //
    // Allocate EVENT_TRACE_PROPERTIES structure and perform some
    // basic initialization.
    //
    // N.B. LoggerName will be populated during StartTrace call.
    //
    TraceProperties = AllocateTraceProperties(NULL, L"SystemTrace.etl");
    if (TraceProperties == NULL) {
        Status = ERROR_OUTOFMEMORY;
        goto Exit;
    }

    TraceProperties->LogFileMode = EVENT_TRACE_FILE_MODE_SEQUENTIAL | EVENT_TRACE_SYSTEM_LOGGER_MODE;
    TraceProperties->MaximumFileSize = 100; // Limit file size to 100MB max
    TraceProperties->BufferSize = 512; // Use 512KB trace buffers
    TraceProperties->MinimumBuffers = 8;
    TraceProperties->MaximumBuffers = 64;

    Status = StartTraceW(&SessionHandle, LoggerName, TraceProperties);
    if (Status != ERROR_SUCCESS) {
        printf("StartTrace() failed with %lu\n", Status);
        goto Exit;
    }

    TraceStarted = TRUE;

    //
    // Enable the provider to a trace session with filtering enabled on the
    // provider
    //
    ZeroMemory(&EnableParameters, sizeof(EnableParameters));
    EnableParameters.Version = ENABLE_TRACE_PARAMETERS_VERSION_2;
    EnableParameters.EnableFilterDesc = &FilterDescriptor;
    EnableParameters.FilterDescCount = 1;

    Status = EnableTraceEx2(
        SessionHandle,
        &EXAMPLE_PROVIDER,
        EVENT_CONTROL_CODE_ENABLE_PROVIDER,
        TRACE_LEVEL_VERBOSE,
        0,
        0,
        0,
        &EnableParameters);
    if (Status != ERROR_SUCCESS) {
        printf("EnableTraceEx2() failed with %lu\n", Status);
        goto Exit;
    }

    //
    // Clean up the payload descriptor
    //
    Status = TdhCleanupPayloadEventFilterDescriptor(&FilterDescriptor);
    if (Status != ERROR_SUCCESS) {
        printf("TdhCleanupPayloadEventFilterDescriptor() failed with %lu\n", Status);
        goto Exit;
    }

    //
    // Collect trace for 30 seconds
    //
    Sleep(30 * 1000);

Exit:

    //
    // Stop tracing.
    //
    if (TraceStarted != FALSE) {
        Status = ControlTraceW(SessionHandle, NULL, TraceProperties, EVENT_TRACE_CONTROL_STOP);
        if (Status != ERROR_SUCCESS) {
            printf("StopTrace() failed with %lu\n", Status);
        }
    }

    if (TraceProperties != NULL) {
        FreeTraceProperties(TraceProperties);
    }

    TdhUnloadManifest((PWSTR)PATH_TO_MANIFEST_FILE);

    return Status;
}

要求

   
最低受支持的客户端 Windows 7 [桌面应用 |UWP 应用]
最低受支持的服务器 Windows Server 2008 R2 [桌面应用 |UWP 应用]
目标平台 Windows
标头 evntrace.h
Library Windows 8.1 和 Windows Server 2012 R2 上的 Sechost.lib;Windows 8、Windows Server 2012、Windows 7 和 Windows Server 2008 R2 上的 Advapi32.lib
DLL Windows 8.1 和 Windows Server 2012 R2 上的 Sechost.dll;Windows 8、Windows Server 2012、Windows 7 和 Windows Server 2008 R2 上的 Advapi32.dll

另请参阅

StartTrace

ControlTrace

EnableCallback

ENABLE_TRACE_PARAMETERS

EVENT_FILTER_DESCRIPTOR