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 传递以使用内核事件。