简单做个摘录,持续更新。
一. 配置和启动Event tracing Session
要配置一个事件跟踪会话,使用EVENT_TRACE_PROPERTIES结构来指定会话的属性。
//待注释
typedef struct _EVENT_TRACE_PROPERTIES {
WNODE_HEADER Wnode;
ULONG BufferSize;
ULONG MinimumBuffers;
ULONG MaximumBuffers;
ULONG MaximumFileSize;
ULONG LogFileMode;
ULONG FlushTimer;
ULONG EnableFlags;
LONG AgeLimit;
ULONG NumberOfBuffers;
ULONG FreeBuffers;
ULONG EventsLost;
ULONG BuffersWritten;
ULONG LogBuffersLost;
ULONG RealTimeBuffersLost;
HANDLE LoggerThreadId;
ULONG LogFileNameOffset;
ULONG LoggerNameOffset;
} EVENT_TRACE_PROPERTIES, *PEVENT_TRACE_PROPERTIES;
所以所分配的内存必须足够大,包含会话日志的名称(etl文件名称),会话日志的路径,和结构体大小。
BufferSize = sizeof(EVENT_TRACE_PROPERTIES)+sizeof(LOGFILE_PATH)+sizeof(LOGSESSION_NAME);
设置完结构体内容后,调用StartTrace函数启动会话。函数成功,则通过参数返回SessionHandle,并将会话名称的偏移给LoggerNameOffset成员(有一些疑问待解决)。
//待注释
ULONG StartTrace(
_Out_ PTRACEHANDLE SessionHandle,
_In_ LPCTSTR SessionName,
_Inout_ PEVENT_TRACE_PROPERTIES Properties
);
使用EnableTrace/EX/EX2函数,打开你想要记录事件到Session的providers(事件提供者)。启用或禁用指定的经典事件跟踪提供程序。
在Windows Vista和更高版本,调用EnableTraceEx功能启用或禁用提供商。
//待注释
ULONG EnableTrace(
_In_ ULONG Enable,
_In_ ULONG EnableFlag,
_In_ ULONG EnableLevel,
_In_ LPCGUID ControlGuid,
_In_ TRACEHANDLE SessionHandle
);
使用EnableTraceEx函数,启用或禁用指定的事件跟踪提供程序。
//待注释
ULONG EnableTraceEx(
_In_ LPCGUID ProviderId,
_In_opt_ LPCGUID SourceId,
_In_ TRACEHANDLE TraceHandle,
_In_ ULONG IsEnabled,
_In_ UCHAR Level,
_In_ ULONGLONG MatchAnyKeyword,
_In_ ULONGLONG MatchAllKeyword,
_In_ ULONG EnableProperty,
_In_opt_ PEVENT_FILTER_DESCRIPTOR EnableFilterDesc
);
EnableTraceEx2功能取代了此函数。
//待注释
ULONG EnableTraceEx2(
_In_ TRACEHANDLE TraceHandle,
_In_ LPCGUID ProviderId,
_In_ ULONG ControlCode,
_In_ UCHAR Level,
_In_ ULONGLONG MatchAnyKeyword,
_In_ ULONGLONG MatchAllKeyword,
_In_ ULONG Timeout,
_In_opt_ PENABLE_TRACE_PARAMETERS EnableParameters
);
对于manifest-based provider可以有最多8个Session进行启用和接收,但是对于classic provider只允许同时存在一个Session进行启用和记录数据,即: SessionA enabled Provider1,then SessionB enabled provider1,only SessionB would recv events from provider1.
____________________________________
在Winodows 8.1之后
可以使用EnableTraceEx2函数和ENABLE_TRACE_PARAMETERS和EVENT_FILTER_DESCRIPTOR结构体在会话中对payload,scope,stack walk进行过滤。
ENABLE_TRACE_PARAMETERS结构定义信息用于启用提供者。
typedef struct _ENABLE_TRACE_PARAMETERS {
ULONG Version;
ULONG EnableProperty;
ULONG ControlFlags;
GUID SourceId;
PEVENT_FILTER_DESCRIPTOR EnableFilterDesc;
ULONG FilterDescCount;
} ENABLE_TRACE_PARAMETERS, *PENABLE_TRACE_PARAMETERS;
该EVENT_FILTER_DESCRIPTOR结构 定义一个过滤数据传递给会话的事件提供者的回调函数。
typedef struct _EVENT_FILTER_DESCRIPTOR {
ULONGLONG Ptr;
ULONG Size;
ULONG Type;
} EVENT_FILTER_DESCRIPTOR, *PEVENT_FILTER_DESCRIPTOR;
等等,一些函数 TdhCreatePayloadFilter, and TdhAggregatePayloadFilters functions(不理解)。
____________________________________
可以再事件供应者注册之前或之后启用事件供应者,ETW都会调用提供的回调函数,如果没有注册会自己注册(?)
可以使用EnableTrace或者EnableTraceEx2来关闭或者更新provider相关数据(开关标志)。每次调用这两个函数都会使得会话,ETW都会调用回调函数。provider保持开启状态,直到由会话将其关闭。
在停止跟踪会话的时候,使用ControlTrace函数,使用EVENT_TRACE_CONTROL_STOP。使用StartTrace函数获得的SessionHanle或者先前启动会话的名称。(要先关闭provider在关闭Session)
//待注释
ULONG ControlTrace(
_In_ TRACEHANDLE SessionHandle,
_In_ LPCTSTR SessionName,
_Inout_ PEVENT_TRACE_PROPERTIES Properties,
_In_ ULONG ControlCode
);
/*
eg:
status = ControlTrace(SessionHandle, LOGSESSION_NAME, pSessionProperties, EVENT_TRACE_CONTROL_STOP);
*/
下面的几个例子进行参考分析和研究代码逻辑。
//待注释
//Example that Creates a Session and Enables a Manifest-based or Classic Provider
//The following example shows how to start a trace session, enables a manifest-based or classic provider, disables the provider and then stops the session.
#include <windows.h>
#include <stdio.h>
#include <conio.h>
#include <strsafe.h>
#include <wmistr.h>
#include <evntrace.h>
#define LOGFILE_PATH L"<FULLPATHTOLOGFILE.etl>"
#define LOGSESSION_NAME L"My Event Trace Session"
// GUID that identifies your trace session.
// Remember to create your own session GUID.
// {AE44CB98-BD11-4069-8093-770EC9258A12}
static const GUID SessionGuid =
{ 0xae44cb98, 0xbd11, 0x4069, { 0x80, 0x93, 0x77, 0xe, 0xc9, 0x25, 0x8a, 0x12 } };
// GUID that identifies the provider that you want
// to enable to your session.
// {D8909C24-5BE9-4502-98CA-AB7BDC24899D}
static const GUID ProviderGuid =
{ 0xd8909c24, 0x5be9, 0x4502, {
0x98, 0xca, 0xab, 0x7b, 0xdc, 0x24, 0x89, 0x9d } };
void wmain(void)
{
ULONG status = ERROR_SUCCESS;
TRACEHANDLE SessionHandle = 0;
EVENT_TRACE_PROPERTIES* pSessionProperties = NULL;
ULONG BufferSize = 0;
BOOL TraceOn = TRUE;
// Allocate memory for the session properties. The memory must
// be large enough to include the log file name and session name,
// which get appended to the end of the session properties structure.
BufferSize = sizeof(EVENT_TRACE_PROPERTIES) + sizeof(LOGFILE_PATH) + sizeof(LOGSESSION_NAME);
pSessionProperties = (EVENT_TRACE_PROPERTIES*) malloc(BufferSize);
if (NULL == pSessionProperties)
{
wprintf(L"Unable to allocate %d bytes for properties structure.\n", BufferSize);
goto cleanup;
}
// Set the session properties. You only append the log file name
// to the properties structure; the StartTrace function appends
// the session name for you.
ZeroMemory(pSessionProperties, BufferSize);
pSessionProperties->Wnode.BufferSize = BufferSize;
pSessionProperties->Wnode.Flags = WNODE_FLAG_TRACED_GUID;
pSessionProperties->Wnode.ClientContext = 1; //QPC clock resolution
pSessionProperties->Wnode.Guid = SessionGuid;
pSessionProperties->LogFileMode = EVENT_TRACE_FILE_MODE_SEQUENTIAL;
pSessionProperties->MaximumFileSize = 1; // 1 MB
pSessionProperties->LoggerNameOffset = sizeof(EVENT_TRACE_PROPERTIES);
pSessionProperties->LogFileNameOffset = sizeof(EVENT_TRACE_PROPERTIES) + sizeof(LOGSESSION_NAME);
StringCbCopy((LPWSTR)((char*)pSessionProperties + pSessionProperties->LogFileNameOffset), sizeof(LOGFILE_PATH), LOGFILE_PATH);
// Create the trace session.
status = StartTrace((PTRACEHANDLE)&SessionHandle, LOGSESSION_NAME, pSessionProperties);
if (ERROR_SUCCESS != status)
{
wprintf(L"StartTrace() failed with %lu\n", status);
goto cleanup;
}
// Enable the providers that you want to log events to your session.
status = EnableTraceEx2(
SessionHandle,
(LPCGUID)&ProviderGuid,
EVENT_CONTROL_CODE_ENABLE_PROVIDER,
TRACE_LEVEL_INFORMATION,
0,
0,
0,
NULL
);
if (ERROR_SUCCESS != status)
{
wprintf(L"EnableTrace() failed with %lu\n", status);
TraceOn = FALSE;
goto cleanup;
}
wprintf(L"Run the provider application. Then hit any key to stop the session.\n");
_getch();
cleanup:
if (SessionHandle)
{
if (TraceOn)
{
status = EnableTraceEx2(
SessionHandle,
(LPCGUID)&ProviderGuid,
EVENT_CONTROL_CODE_DISABLE_PROVIDER,
TRACE_LEVEL_INFORMATION,
0,
0,
0,
NULL
);
}
status = ControlTrace(SessionHandle, LOGSESSION_NAME, pSessionProperties, EVENT_TRACE_CONTROL_STOP);
if (ERROR_SUCCESS != status)
{
wprintf(L"ControlTrace(stop) failed with %lu\n", status);
}
}
if (pSessionProperties)
{
free(pSessionProperties);
pSessionProperties = NULL;
}
}
下面的例子演示了如何配置和启动NT内核记录会议,收集网络中的TCP/ IP内核事件,并将其写入到一个5MB的循环文件。
//Configuring and Starting the NT Kernel Logger Session
//There is only one NT Kernel Logger session. If the session is already in use, the StartTrace function returns ERROR_ALREADY_EXISTS.
#define INITGUID
// Include this #define to use SystemTraceControlGuid in Evntrace.h.
#include <windows.h>
#include <stdio.h>
#include <conio.h>
#include <strsafe.h>
#include <wmistr.h>
#include <evntrace.h>
#define LOGFILE_PATH L"<FULLPATHTOTHELOGFILE.etl>"
void wmain(void)
{
ULONG status = ERROR_SUCCESS;
TRACEHANDLE SessionHandle = 0;
EVENT_TRACE_PROPERTIES* pSessionProperties = NULL;
ULONG BufferSize = 0;
// Allocate memory for the session properties. The memory must
// be large enough to include the log file name and session name,
// which get appended to the end of the session properties structure.
BufferSize = sizeof(EVENT_TRACE_PROPERTIES) + sizeof(LOGFILE_PATH) + sizeof(KERNEL_LOGGER_NAME);
pSessionProperties = (EVENT_TRACE_PROPERTIES*) malloc(BufferSize);
if (NULL == pSessionProperties)
{
wprintf(L"Unable to allocate %d bytes for properties structure.\n", BufferSize);
goto cleanup;
}
// Set the session properties. You only append the log file name
// to the properties structure; the StartTrace function appends
// the session name for you.
ZeroMemory(pSessionProperties, BufferSize);
pSessionProperties->Wnode.BufferSize = BufferSize;
pSessionProperties->Wnode.Flags = WNODE_FLAG_TRACED_GUID;
pSessionProperties->Wnode.ClientContext = 1; //QPC clock resolution
pSessionProperties->Wnode.Guid = SystemTraceControlGuid;
pSessionProperties->EnableFlags = EVENT_TRACE_FLAG_NETWORK_TCPIP;
pSessionProperties->LogFileMode = EVENT_TRACE_FILE_MODE_CIRCULAR;
pSessionProperties->MaximumFileSize = 5; // 5 MB
pSessionProperties->LoggerNameOffset = sizeof(EVENT_TRACE_PROPERTIES);
pSessionProperties->LogFileNameOffset = sizeof(EVENT_TRACE_PROPERTIES) + sizeof(KERNEL_LOGGER_NAME);
StringCbCopy((LPWSTR)((char*)pSessionProperties + pSessionProperties->LogFileNameOffset), sizeof(LOGFILE_PATH), LOGFILE_PATH);
// Create the trace session.
status = StartTrace((PTRACEHANDLE)&SessionHandle, KERNEL_LOGGER_NAME, pSessionProperties);
if (ERROR_SUCCESS != status)
{
if (ERROR_ALREADY_EXISTS == status)
{
wprintf(L"The NT Kernel Logger session is already in use.\n");
}
else
{
wprintf(L"EnableTrace() failed with %lu\n", status);
}
goto cleanup;
}
wprintf(L"Press any key to end trace session ");
_getch();
cleanup:
if (SessionHandle)
{
status = ControlTrace(SessionHandle, KERNEL_LOGGER_NAME, pSessionProperties, EVENT_TRACE_CONTROL_STOP);
if (ERROR_SUCCESS != status)
{
wprintf(L"ControlTrace(stop) failed with %lu\n", status);
}
}
if (pSessionProperties)
free(pSessionProperties);
}
用于分析etl文件的代码,参考和研究。
//Turns the DEFINE_GUID for EventTraceGuid into a const.
#define INITGUID
#include <windows.h>
#include <stdio.h>
#include <wbemidl.h>
#include <wmistr.h>
#include <evntrace.h>
#include <tdh.h>
#include <in6addr.h>
#pragma comment(lib, "tdh.lib")
#define LOGFILE_PATH L"C:\\Code\\etw\\V2EventTraceController\\mylogfile.etl"
// Used to calculate CPU usage
ULONG g_TimerResolution = 0;
// Used to determine if the session is a private session or kernel session.
// You need to know this when accessing some members of the EVENT_TRACE.Header
// member (for example, KernelTime or UserTime).
BOOL g_bUserMode = FALSE;
// Handle to the trace file that you opened.
TRACEHANDLE g_hTrace = 0;
// Prototypes
void WINAPI ProcessEvent(PEVENT_RECORD pEvent);
DWORD GetEventInformation(PEVENT_RECORD pEvent, PTRACE_EVENT_INFO & pInfo);
PBYTE PrintProperties(PEVENT_RECORD pEvent, PTRACE_EVENT_INFO pInfo, DWORD PointerSize, USHORT i, PBYTE pUserData, PBYTE pEndOfUserData);
DWORD GetPropertyLength(PEVENT_RECORD pEvent, PTRACE_EVENT_INFO pInfo, USHORT i, PUSHORT PropertyLength);
DWORD GetArraySize(PEVENT_RECORD pEvent, PTRACE_EVENT_INFO pInfo, USHORT i, PUSHORT ArraySize);
DWORD GetMapInfo(PEVENT_RECORD pEvent, LPWSTR pMapName, DWORD DecodingSource, PEVENT_MAP_INFO & pMapInfo);
void RemoveTrailingSpace(PEVENT_MAP_INFO pMapInfo);
void wmain(void)
{
TDHSTATUS status = ERROR_SUCCESS;
EVENT_TRACE_LOGFILE trace;
TRACE_LOGFILE_HEADER* pHeader = &trace.LogfileHeader;
// Identify the log file from which you want to consume events
// and the callbacks used to process the events and buffers.
ZeroMemory(&trace, sizeof(EVENT_TRACE_LOGFILE));
trace.LogFileName = (LPWSTR) LOGFILE_PATH;
trace.EventRecordCallback = (PEVENT_RECORD_CALLBACK) (ProcessEvent);
trace.ProcessTraceMode = PROCESS_TRACE_MODE_EVENT_RECORD;
g_hTrace = OpenTrace(&trace);
if (INVALID_PROCESSTRACE_HANDLE == g_hTrace)
{
wprintf(L"OpenTrace failed with %lu\n", GetLastError());
goto cleanup;
}
g_bUserMode = pHeader->LogFileMode & EVENT_TRACE_PRIVATE_LOGGER_MODE;
if (pHeader->TimerResolution > 0)
{
g_TimerResolution = pHeader->TimerResolution / 10000;
}
wprintf(L"Number of events lost: %lu\n", pHeader->EventsLost);
// Use pHeader to access all fields prior to LoggerName.
// Adjust pHeader based on the pointer size to access
// all fields after LogFileName. This is required only if
// you are consuming events on an architecture that is
// different from architecture used to write the events.
if (pHeader->PointerSize != sizeof(PVOID))
{
pHeader = (PTRACE_LOGFILE_HEADER)((PUCHAR)pHeader +
2 * (pHeader->PointerSize - sizeof(PVOID)));
}
wprintf(L"Number of buffers lost: %lu\n\n", pHeader->BuffersLost);
status = ProcessTrace(&g_hTrace, 1, 0, 0);
if (status != ERROR_SUCCESS && status != ERROR_CANCELLED)
{
wprintf(L"ProcessTrace failed with %lu\n", status);
goto cleanup;
}
cleanup:
if (INVALID_PROCESSTRACE_HANDLE != g_hTrace)
{
status = CloseTrace(g_hTrace);
}
}
// Callback that receives the events.
VOID WINAPI ProcessEvent(PEVENT_RECORD pEvent)
{
DWORD status = ERROR_SUCCESS;
PTRACE_EVENT_INFO pInfo = NULL;
LPWSTR pwsEventGuid = NULL;
PBYTE pUserData = NULL;
PBYTE pEndOfUserData = NULL;
DWORD PointerSize = 0;
ULONGLONG TimeStamp = 0;
ULONGLONG Nanoseconds = 0;
SYSTEMTIME st;
SYSTEMTIME stLocal;
FILETIME ft;