Windows ETW: потребитель ядра не получает событий EventCallback или BufferCallback
Я пытаюсь слушать события ядра ETW.
Шаг 1: Позвоните
OpenTrace
, указавEventCallback
и необязательноBufferCallback
функции, которые будут вызываться во время моего звонкаProcessTrace
:var logFile: EVENT_TRACE_LOGFILE; currentTrace: TRACEHANDLE; begin ZeroMemory(@logFile, sizeof(logFile)); logFile.LoggerName := KERNEL_LOGGER_NAME; logFile.LogFileName := 'C:\Users\Ian\foo.etl'; logFile.ProcessTraceMode := 0; logFile.EventCallback := RealtimeEventCallback; logFile.BufferCallback := BufferCallback; //optional currentTrace := OpenTrace(@logFile); if (currentTrace = INVALID_PROCESSTRACE_HANDLE) or (currentTrace = -1) then RaiseLastWin32Error();
Шаг 2: Включить события ядра. Это делается по телефону
StartTrace
, В моем случае я хочу отслеживать прерывания ядра (EVENT_TRACE_FLAG_INTERRUPT
) и отложенные вызовы процедур (EVENT_TRACE_FLAG_DPC
):var sessionProperties: PEVENT_TRACE_PROPERTIES; bufferSize: Int64; th: TRACEHANDLE; loggerName: string; logFilePath: string; begin loggerName := KERNEL_LOGGER_NAME; logFilePath := 'C:\Users\Ian\foo.etl'; bufferSize := sizeof(EVENT_TRACE_PROPERTIES) + 1024 //maximum session name is 1024 characters + 1024; //maximum log file name is 1024 characters sessionProperties := AllocMem(bufferSize); ZeroMemory(sessionProperties, bufferSize); sessionProperties.Wnode.BufferSize := bufferSize; sessionProperties.Wnode.ClientContext := 1; //QPC clock resolution sessionProperties.Wnode.Flags := WNODE_FLAG_TRACED_GUID; sessionProperties.Wnode.Guid := SystemTraceControlGuid; sessionProperties.EnableFlags := EVENT_TRACE_FLAG_INTERRUPT or EVENT_TRACE_FLAG_DPC; sessionProperties.LogFileMode := EVENT_TRACE_FILE_MODE_CIRCULAR; sessionProperties.MaximumFileSize := 5; // 5 MB sessionProperties.LoggerNameOffset := sizeof(EVENT_TRACE_PROPERTIES); sessionProperties.LogFileNameOffset := sizeof(EVENT_TRACE_PROPERTIES)+1024; //Copy LoggerName to the offset address MoveMemory(Pointer(Cardinal(sessionProperties)+sessionProperties.LoggerNameOffset), PChar(loggerName), Length(loggerName)+1); //Copy LogFilePath to the offset address MoveMemory(Pointer(Cardinal(sessionProperties)+sessionProperties.LogFileNameOffset), PChar(logFilePath), Length(logFilePath)+1); hr := StartTrace({var}th, PChar(loggerName), sessionProperties); if (hr <> ERROR_SUCCESS) then raise EWin32Error.Create(SysErrorMessage(hr));
И журнал запущен успешно (я вижу
foo.etl
начать расти до своего 5 МБ циркулярного предела).Шаг 3: Звоните
ProcessTrace
, который блокирует, пока не доставит все ожидающие события вEventCallback
обработчик, указанный в шаге 1:var res: LongWord; begin res := EventTrace.ProcessTrace(@currentTrace, 1, nil, nil); if (res <> ERROR_SUCCESS) then raise EWin32Error.Create(SysErrorMessage(res));
Кроме этого ProcessTrace
многократно возвращается немедленно, и обратный вызов не вызывается - даже если файл etl присутствует и растет.
Если я изменю ведение журнала с файлов на основе ведения журнала в реальном времени:
Шаг 1 -
OpenTrace
изменения для поддержки в реальном времени:logFile.ProcessTraceMode := PROCESS_TRACE_MODE_REAL_TIME;
Шаг 2 -
StartTrace
изменения для поддержки в реальном времени:sessionProperties.LogFileMode := EVENT_TRACE_REAL_TIME_MODE;
В этом случае ProcessTrace
никогда не возвращается, но ни EventCallback
или же BufferCallback
когда-либо называются.
Что я делаю неправильно?
Обновление: Мои функции обратного вызова:
function BufferCallback(Logfile: PEVENT_TRACE_LOGFILE): LongWord; stdcall;
begin
ShowMessage('BufferCallback');
Result := 1; //return true to keep processing rows
end;
procedure RealtimeEventCallback(pEvent: PEVENT_TRACE); stdcall;
begin
ShowMessage('EventCallback');
nEvents := nEvents+1;
end;
2 ответа
Я нашел проблему.
Заголовки, которые я использовал, не были выровнены по четырем словам.
На языке Delphi ключевое слово packed
использовался.
Вы не можете предоставить и LoggerName, и LogFileName. Если вы указываете LoggerName, LogFileName должно быть нулевым. Смотрите эту ссылку.