ETW - 事件跟踪的实时消费
ETW - Realtime consuming of event trace
我不是 C++ 开发人员,对于任何不精确的语言,我深表歉意。
我配置了一个 ETW 内核记录器(基本上是 Microsoft 示例的调整版本)。它将事件写入日志,我可以从 etl 文件中查看数据。我想将 LogFileMode
切换为 EVENT_TRACE_REAL_TIME_MODE
并在数据通过跟踪时与其进行交互。
一个具体的例子是这样的
foreach ($event in $trace) {
if ($string in $event) {
print $event
}
}
我读过的文档建议我需要一个消费者,它会 运行 OpenTrace
函数,使用回调处理事件,然后关闭跟踪?不幸的是,我还没有看到这样一个我能理解的消费者的例子。是否可以采用下面的 msft 示例代码并对其进行修改以执行我正在描述的操作,或者这不是一种可行的方法吗?
#define INITGUID
#define UNICODE 1
#include <windows.h>
#include <stdio.h>
#include <conio.h>
#include <strsafe.h>
#include <wmistr.h>
#include <evntrace.h>
#define LOGFILE_PATH L"C:\Users\userplace\testtrace.etl"
int main(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;
}
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_FILE_IO_INIT | EVENT_TRACE_FLAG_PROCESS;
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);
}
这是基于 MSDN 的简约示例:
void create_realtime_consumer(const wchar_t * session_name, EVENT_RECORD_CALLBACK * event_callback, EVENT_TRACE_BUFFER_CALLBACKW * buffer_callback)
{
EVENT_TRACE_LOGFILE trace{};
TRACE_LOGFILE_HEADER * pHeader = &trace.LogfileHeader;
TDHSTATUS status = ERROR_SUCCESS;
trace.LoggerName = (LPWSTR)session_name; // use KERNEL_LOGGER_NAMEW to consume Kernel events
trace.ProcessTraceMode = PROCESS_TRACE_MODE_REAL_TIME | PROCESS_TRACE_MODE_RAW_TIMESTAMP | PROCESS_TRACE_MODE_EVENT_RECORD; // create real time sesion + event should be represented as EVENT_RECORD structure
trace.EventRecordCallback = event_callback; // called on each event
trace.BufferCallback = buffer_callback; // called on each ETWbuffer flush
auto h_trace = OpenTrace(&trace);
if(h_trace == INVALID_PROCESSTRACE_HANDLE)
throw std::runtime_error("Unable to open trace");
if(pHeader->PointerSize != sizeof(PVOID))
pHeader = (PTRACE_LOGFILE_HEADER)((PUCHAR)pHeader + 2 * (pHeader->PointerSize - sizeof(PVOID)));
try {
status = ProcessTrace(&h_trace, 1, 0, 0); // this call blocks until either the session is stopped or an exception is occurred in event_callback
}
catch(...) {
// catch exceptions occurred in event_callback
}
CloseTrace(h_trace);
}
此代码 运行 是实时处理内核事件的消费者。
要使其工作,您应该首先创建 ETW 会话(就像您在上面提到的示例中一样,但您需要在 LogFileMode 中指定 EVENT_TRACE_REAL_TIME_MODE),然后 运行 消费者。
您应该将 KERNEL_LOGGER_NAMEW 作为 session_name 传递以使用内核事件。
我不是 C++ 开发人员,对于任何不精确的语言,我深表歉意。
我配置了一个 ETW 内核记录器(基本上是 Microsoft 示例的调整版本)。它将事件写入日志,我可以从 etl 文件中查看数据。我想将 LogFileMode
切换为 EVENT_TRACE_REAL_TIME_MODE
并在数据通过跟踪时与其进行交互。
一个具体的例子是这样的
foreach ($event in $trace) {
if ($string in $event) {
print $event
}
}
我读过的文档建议我需要一个消费者,它会 运行 OpenTrace
函数,使用回调处理事件,然后关闭跟踪?不幸的是,我还没有看到这样一个我能理解的消费者的例子。是否可以采用下面的 msft 示例代码并对其进行修改以执行我正在描述的操作,或者这不是一种可行的方法吗?
#define INITGUID
#define UNICODE 1
#include <windows.h>
#include <stdio.h>
#include <conio.h>
#include <strsafe.h>
#include <wmistr.h>
#include <evntrace.h>
#define LOGFILE_PATH L"C:\Users\userplace\testtrace.etl"
int main(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;
}
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_FILE_IO_INIT | EVENT_TRACE_FLAG_PROCESS;
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);
}
这是基于 MSDN 的简约示例:
void create_realtime_consumer(const wchar_t * session_name, EVENT_RECORD_CALLBACK * event_callback, EVENT_TRACE_BUFFER_CALLBACKW * buffer_callback)
{
EVENT_TRACE_LOGFILE trace{};
TRACE_LOGFILE_HEADER * pHeader = &trace.LogfileHeader;
TDHSTATUS status = ERROR_SUCCESS;
trace.LoggerName = (LPWSTR)session_name; // use KERNEL_LOGGER_NAMEW to consume Kernel events
trace.ProcessTraceMode = PROCESS_TRACE_MODE_REAL_TIME | PROCESS_TRACE_MODE_RAW_TIMESTAMP | PROCESS_TRACE_MODE_EVENT_RECORD; // create real time sesion + event should be represented as EVENT_RECORD structure
trace.EventRecordCallback = event_callback; // called on each event
trace.BufferCallback = buffer_callback; // called on each ETWbuffer flush
auto h_trace = OpenTrace(&trace);
if(h_trace == INVALID_PROCESSTRACE_HANDLE)
throw std::runtime_error("Unable to open trace");
if(pHeader->PointerSize != sizeof(PVOID))
pHeader = (PTRACE_LOGFILE_HEADER)((PUCHAR)pHeader + 2 * (pHeader->PointerSize - sizeof(PVOID)));
try {
status = ProcessTrace(&h_trace, 1, 0, 0); // this call blocks until either the session is stopped or an exception is occurred in event_callback
}
catch(...) {
// catch exceptions occurred in event_callback
}
CloseTrace(h_trace);
}
此代码 运行 是实时处理内核事件的消费者。 要使其工作,您应该首先创建 ETW 会话(就像您在上面提到的示例中一样,但您需要在 LogFileMode 中指定 EVENT_TRACE_REAL_TIME_MODE),然后 运行 消费者。 您应该将 KERNEL_LOGGER_NAMEW 作为 session_name 传递以使用内核事件。