c++ - ETW - 事件跟踪的实时消耗
问题描述
我不是 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 传递以使用内核事件。
推荐阅读
- dbt - 以与其他转换不同的用户身份运行 dbt 快照
- r - 循环遍历子集对象并将输出存储在 R 中
- dependency-injection - Redux-saga:无法访问 saga 中的类实例?
- ceph - centos7 上的 ceph-deploy install --release octopus 尝试加载不存在的 ceph-release-1-0 并且 ceph-deploy 不喜欢 centos8
- c# - 使用 EF Core 如何进行简单的连接以获得一个值
- loops - Lua 表 // 循环 // 哇插件 // 索引作为变量
- visual-studio - Visual Studio 2019 CS8032 无法从 C:\folder 创建 Microsoft.EntityFrameworkCore.InternalUsageDiagnosticAnalyzer 的实例
- python - 当我使用 PM2 时,我的 NodeJS 子进程没有运行我的 python 文件,但是当我在 nodemon 中执行它们时工作正常
- postgresql - 如果行的顺序在 posgres 中有聚集索引,是否按顺序锁定整个表?
- javascript - 如何在处理下一步之前等待 HTTP 请求在循环中获得响应