前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >ETW - 事件提供者(Event Provider)

ETW - 事件提供者(Event Provider)

原创
作者头像
lealc
修改2024-01-12 17:27:14
2390
修改2024-01-12 17:27:14

介绍

Event Tracing for Windows (ETW) - Windows drivers | Microsoft Learn

官方示例:Eventdrv - Code Samples | Microsoft Learn

Windows ETW(Event Tracing for Windows 简称ETW)是 Windows 操作系统中的一种高性能、可扩展的事件跟踪框架。它允许开发人员在应用程序、设备驱动程序和内核组件中插入事件,以便在运行时收集有关系统行为的详细信息。这些事件可以用于诊断性能问题、调试应用程序、监视系统活动等。

事件提供者(Event Provider)

事件提供者(Event Provider): 事件提供者是生成事件并将其发送到 ETW 的可执行模块,例如应用程序、设备驱动程序或内核组件。事件提供者在系统中注册,并指定事件的类型和结构。

为了实现事件提供者,开发者需要完成以下任务:

  • 定义事件:事件提供者需要定义要生成的事件,包括事件类型、级别、关键字和有效负载(即事件数据)等信息。
  • 注册事件提供者:事件提供者需要在系统中注册,以便 ETW 能够识别它。注册过程通常包括提供一个 GUID(全局唯一标识符)和事件元数据的文件(通常是一个 XML 文件)。
  • 生成事件:事件提供者需要在适当的代码位置生成事件。生成事件时,需要指定事件的级别、关键字和有效负载等信息。
  • 注销事件提供者:在不再需要生成事件时,事件提供者需要从系统中注销。 针对Provider,如果我们想自定义事件以及后续分析的话,这是首先需要创建的。

针对Provider,如果我们想自定义事件以及后续分析的话,这是首先需要创建的。

工具准备

需要安装Windows SDK:Windows相关资源汇总

比如mc,安装10.0.22621.0版本的SDK成功后可以在C:\Program Files (x86)\Windows Kits\10\bin\10.0.22621.0\x86\mc.exe找到

打开下载的微软VS命令行,或者配置mc.exe这类工具到系统环境变量,以便可以使用mc.exe等工具

wevtutil

官网说明:wevtutil | Microsoft Learn

wevtutil.exe是一个 Windows 命令行实用程序,用于管理事件日志和事件跟踪会话。它允许您查看、导出、清除和归档事件日志,以及查询和配置事件提供者和事件跟踪会话。

wevtutil.exe是 Windows Event Log 服务的一部分,它在 Windows Vista 及更高版本的操作系统中可用。

  • 功能: - 管理事件日志:wevtutil.exe 可以用于查看、导出、清除和归档事件日志。您可以使用它来查找特定类型的事件,或者在出现问题时导出事件日志以供进一步分析。 - 管理事件提供者:wevtutil.exe 可以用于查询和配置事件提供者。您可以使用它来查看已注册的事件提供者,或者更改事件提供者的配置,以便收集不同类型的事件。 - 管理事件跟踪会话:wevtutil.exe 可以用于查询和配置事件跟踪会话。您可以使用它来查看活动的事件跟踪会话,或者启用和禁用事件跟踪。
  • 常用命令参数: - wevtutil el:列出所有事件日志。 - wevtutil qe <LogName>:查询指定事件日志中的事件(例如,wevtutil qe System)。 - wevtutil epl <LogName> <FileName>:将指定事件日志导出到文件(例如,wevtutil epl System system_log.evtx)。 - wevtutil cl <LogName>:清除指定事件日志中的事件(例如,wevtutil cl System)。 - wevtutil ep <ProviderName>:查询指定事件提供者的配置(例如,wevtutil ep Microsoft-Windows-Kernel-Power)。 - wevtutil sl <ProviderName> <Options>:设置指定事件提供者的配置(例如,wevtutil sl Microsoft-Windows-Kernel-Power /e:true)。

示例: 假设我们有一个名为 MyProvider.mc 的 XML 消息定义文件,内容如下:

代码语言:xml
复制
<?xml version="1.0" encoding="utf-8"?>
<instrumentationManifest
   xmlns="http://schemas.microsoft.com/win/2004/08/events"
   xmlns:win="http://manifests.microsoft.com/win/2004/08/windows/events"
   xmlns:xs="http://www.w3.org/2001/XMLSchema">
   <instrumentation>
	   <events>
		   <provider name="MyProvider"
					 guid="{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}"
					 resourceFileName="MyProvider.dll"
					 messageFileName="MyProvider.dll">
			   <events>
				   <event value="1" version="1" level="win:Informational"
						  channel="win:Application" task="0" opcode="0">
					   <template>
						   <data name="Message" inType="win:UnicodeString" />
					   </template>
				   </event>
			   </events>
		   </provider>
	   </events>
   </instrumentation>
   <localization>
	   <resources culture="en-US">
		   <stringTable>
			   <string id="1" value="MyProvider: %1" />
		   </stringTable>
	   </resources>
   </localization>
</instrumentationManifest>

运行以下命令,使用 mc.exe生成事件资源、头文件、清单文件和消息文件:mc.exe MyProvider.mc,这将生成以下文件:

  • MyProvider.h:包含事件 ID、级别、关键字、通道、任务和操作码的常量定义的头文件。
  • MyProvider.rc:包含事件资源的资源文件。
  • MyProvider.xml:包含事件提供者和事件的元数据的清单文件。
  • MyProvider.dll:包含事件的文本描述的消息文件。

mc.exe 是一个用于生成事件资源的实用程序,它可以帮助开发者创建和维护事件提供者。通过使用 mc.exe,开发者可以更轻松地记录和处理事件,以便进行性能分析、调试和系统监控。

wpaexporter.exe

wpaexporter.exe(Windows Performance Analyzer Exporter)是一个 Windows 命令行实用程序,用于将 Windows Performance Recorder(WPR)生成的事件跟踪日志(ETL)文件转换为可读的报告。它是 Windows Performance Toolkit(WPT)的一部分,主要用于性能分析和调试。

以下是关于 wpaexporter.exe 的详细介绍:

功能:

  • 转换事件跟踪日志:wpaexporter.exe 可以将 WPR 生成的 ETL 文件转换为 CSV、XML 或 TSV 格式的报告,以便进行进一步分析。
  • 自定义报告:wpaexporter.exe 支持使用预定义的分析配置文件(WPA Profile)来自定义报告的内容和格式。分析配置文件定义了报告中要包含的表格、图形和摘要信息。
  • 批量处理:wpaexporter.exe 可以在命令行中批量处理多个 ETL 文件,从而提高分析效率。

使用方法: 要使用 wpaexporter.exe,首先需要一个由 WPR 生成的 ETL 文件。然后,运行 wpaexporter.exe,将 ETL 文件作为输入,指定输出文件的格式和名称。您还可以选择一个分析配置文件来自定义报告的内容和格式。

示例: 假设我们有一个名为 trace.etl 的事件跟踪日志文件,我们希望将其转换为 CSV 格式的报告。运行以下命令:

代码语言:shell
复制
wpaexporter.exe -i trace.etl -o report.csv -profile CPU

在这个示例中,-i 参数指定输入的 ETL 文件,-o 参数指定输出的 CSV 文件,-profile 参数指定预定义的分析配置文件(在这里,我们使用了名为 "CPU" 的配置文件)。

生成过程

准备事件清单,xml内容,按照指定格式填下,格式说明如下或者官方Demo:Windows-driver-samples/general/tracing/evntdrv/Eventdrv/evntdrv.xml at main · microsoft/Windows-driver-samples (github.com)

provider字段说明 :

  • guid:此Guid用于后续Consumer和Controller使用
  • name:Provider名称,使用命令行:wevtutil ep > providers.txt 可以导出所有注册的Provider
  • symbol:可选 - messageFileName:参数指定了包含事件消息的文件的路径。当事件被触发时,事件跟踪会使用该文件中的消息来记录事件的详细信息
  • resourceFileName:参数指定了包含本地化资源的文件的路径。这些资源文件包含了事件消息的本地化字符串,以便根据不同的语言环境显示适当的文本。

通过指定正确的 messageFileName 和 resourceFileName,事件跟踪可以根据提供程序的设置,将事件消息和参数信息转换为易于理解的文本,并在日志中进行记录。这使得事件的分析和诊断更加方便和可读性更强。 运行命令行:mc.exe etwproviders.man

生成以下文件:

  • etwprovidersTEMP.BIN
  • etwproviders.h
  • etwproviders.rc

生成后就可以使用这些文件编写属于自己的Provider,应用层的话编写dll即可 先上Demo源码:(头文件独立出来,方便后面Controllor使用)

源码

头文件

头文件用于导出一系列接口,供应用程序生产事件,以及后续Controllor和Consumer进行使用。

代码语言:C++
复制
// etwprof.h
PLATFORM_INTERFACE void __cdecl ETWMarkPrintf(_Printf_format_string_ _In_z_ PCSTR pMessage, ...);

PLATFORM_INTERFACE void __cdecl ETWRenderFrameMark();
实现

分为三个步骤:注册、生成、注销

代码语言:C++
复制
// Typedefs for use with GetProcAddress
typedef ULONG (__stdcall *tEventRegister)( _In_ LPCGUID ProviderId, _In_opt_ PENABLECALLBACK EnableCallback, _In_opt_ PVOID CallbackContext, _Out_ PREGHANDLE RegHandle);
typedef ULONG (__stdcall *tEventWrite)( _In_ REGHANDLE RegHandle, _In_ PCEVENT_DESCRIPTOR EventDescriptor, _In_ ULONG UserDataCount, _In_reads_opt_(UserDataCount) PEVENT_DATA_DESCRIPTOR UserData);
typedef ULONG (__stdcall *tEventUnregister)( _In_ REGHANDLE RegHandle );

ULONG EVNTAPI EventRegister( _In_ LPCGUID ProviderId, _In_opt_ PENABLECALLBACK EnableCallback, _In_opt_ PVOID CallbackContext, _Out_ PREGHANDLE RegHandle )
{
       if ( g_ETWRegister.m_pEventRegister )
              return g_ETWRegister.m_pEventRegister( ProviderId, EnableCallback, CallbackContext, RegHandle );

       *RegHandle = 0;
       return ERROR_INVALID_FUNCTION;
}

ULONG EVNTAPI EventWrite( _In_ REGHANDLE RegHandle, _In_ PCEVENT_DESCRIPTOR EventDescriptor, _In_ ULONG UserDataCount, _In_reads_opt_(UserDataCount) PEVENT_DATA_DESCRIPTOR UserData )
{
       if ( g_ETWRegister.m_pEventWrite )
              return g_ETWRegister.m_pEventWrite( RegHandle, EventDescriptor, UserDataCount, UserData );
       return ERROR_INVALID_FUNCTION;
}

ULONG EVNTAPI EventUnregister( _In_ REGHANDLE RegHandle )
{
       if ( g_ETWRegister.m_pEventUnregister )
              return g_ETWRegister.m_pEventUnregister( RegHandle );
       return ERROR_INVALID_FUNCTION;
}
注册
代码语言:C++
复制
class CETWRegister
{
public:
       CETWRegister()
       {

          QueryPerformanceFrequency(&m_frequency);

          // 查找 Advapi32.dll,这应该总是成功的。
          HMODULE pAdvapiDLL = LoadLibraryW(L"Advapi32.dll");
          if (pAdvapiDLL) {
              // 尝试查找 ETW 函数。这在 Windows XP 上会失败。
              m_pEventRegister = (tEventRegister)GetProcAddress(pAdvapiDLL, "EventRegister");
              m_pEventWrite = (tEventWrite)GetProcAddress(pAdvapiDLL, "EventWrite");
              m_pEventUnregister = (tEventUnregister)GetProcAddress(pAdvapiDLL, "EventUnregister");

              // 注册我们的 ETW 提供程序。如果注册失败,则事件日志调用将失败。
              // 在 Windows XP 上,这些调用将不起作用。
              // 在 Vista 及更高版本中,如果这些提供程序已由 xperf 或 logman 启用,
              // 则 *Context 全局变量将被修改如下:
              //     MatchAnyKeyword: 0xffffffffffffffff
              //     IsEnabled: 1
              //     Level: 255
              // 换句话说,完全启用。

              EventRegisterMulti_FrameRate();
              EventRegisterMulti_Main();
              EventRegisterMulti_Worker();
              EventRegisterMulti_Input();

              // 发出主线程的线程 ID。这也表示主提供程序已初始化。
              EventWriteThread_ID(GetCurrentThreadId(), "Main thread");
          }
       }
         ~CETWRegister()
       {
              // Unregister our providers.
              EventUnregisterMulti_Input();
              EventUnregisterMulti_Worker();
              EventUnregisterMulti_Main();
              EventUnregisterMulti_FrameRate();
       }

       tEventRegister m_pEventRegister;
       tEventWrite m_pEventWrite;
       tEventUnregister m_pEventUnregister;

       // QPC frequency
       LARGE_INTEGER m_frequency;

} g_ETWRegister;

事件生成

具体使用Provider生成事件的步骤如下:

  1. 引入Provider的头文件
  2. 注意事件清单messageFileName字段定义的目录,比如:messageFileName="%temp%\ETWProviders.dll",需要将Provider对应的dll拷贝到%temp%目录下
  3. 引入Provider对应Dll导入库
  4. 利用宏生成事件即可

源码展示如下:

代码语言:C++
复制
#include "stdafx.h"
#include <Windows.h>
#include "ETWProviders\etwprof.h"
#include <future>
#include <string>

__declspec(noinline) void IdleDelay()
{
       Sleep(10);
}

__declspec(noinline) void BusyDelay()
{
       DWORD startTick = GetTickCount();

       for (;;)
       {
              DWORD elapsed = GetTickCount() - startTick;
              if (elapsed > 10)
                      break;
       }
}

int _tmain(int argc, _TCHAR* argv[])
{
  printf("Emitting custom ETW events that can be recorded with etwrecord.bat\n");
	CETWScope timer("main");
	for (int i = 0; i < 40; ++i) {
		ETWMarkPrintf("This is loop %d", i);
		ETWRenderFrameMark();
		// Simulating code that does something.

		IdleDelay();
		BusyDelay();
	}
	return 0;
}

效果展示

录制etl,然后用wpa打开就可以看到我们定义的事件展示

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 介绍
  • 事件提供者(Event Provider)
  • 工具准备
    • wevtutil
      • wpaexporter.exe
      • 生成过程
        • 源码
          • 头文件
          • 实现
      • 事件生成
        • 效果展示
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档