Я пытаюсь прослушать события ядра 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;