#ifndef BASE_WIN_EVENT_TRACE_CONSUMER_H_
#define BASE_WIN_EVENT_TRACE_CONSUMER_H_
#include <windows.h>
#include <evntcons.h>
#include <evntrace.h>
#include <stddef.h>
#include <wmistr.h>
#include <vector>
#include "base/threading/scoped_blocking_call.h"
namespace base {
namespace win {
template <class ImplClass>
class EtwTraceConsumerBase {
public:
static constexpr bool kEnableRecordMode = false;
static constexpr bool kRawTimestamp = false;
EtwTraceConsumerBase() = default;
EtwTraceConsumerBase(const EtwTraceConsumerBase&) = delete;
EtwTraceConsumerBase& operator=(const EtwTraceConsumerBase&) = delete;
~EtwTraceConsumerBase() { Close(); }
HRESULT OpenRealtimeSession(const wchar_t* session_name);
HRESULT OpenFileSession(const wchar_t* file_name);
HRESULT Consume();
HRESULT Close();
protected:
static void ProcessEvent(EVENT_TRACE* event) {}
static void ProcessEventRecord(EVENT_RECORD* event_record) {}
static bool ProcessBuffer(EVENT_TRACE_LOGFILE* buffer) {
return true;
}
HRESULT OpenSessionImpl(EVENT_TRACE_LOGFILE& logfile);
protected:
std::vector<TRACEHANDLE> trace_handles_;
private:
static void WINAPI ProcessEventCallback(EVENT_TRACE* event) {
ImplClass::ProcessEvent(event);
}
static void WINAPI ProcessEventRecordCallback(EVENT_RECORD* event_record) {
ImplClass::ProcessEventRecord(event_record);
}
static ULONG WINAPI ProcessBufferCallback(PEVENT_TRACE_LOGFILE buffer) {
return ImplClass::ProcessBuffer(buffer);
}
};
template <class ImplClass>
inline HRESULT EtwTraceConsumerBase<ImplClass>::OpenRealtimeSession(
const wchar_t* session_name) {
EVENT_TRACE_LOGFILE logfile = {
.LoggerName = const_cast<wchar_t*>(session_name),
.ProcessTraceMode = PROCESS_TRACE_MODE_REAL_TIME,
};
return OpenSessionImpl(logfile);
}
template <class ImplClass>
inline HRESULT EtwTraceConsumerBase<ImplClass>::OpenFileSession(
const wchar_t* file_name) {
EVENT_TRACE_LOGFILE logfile = {.LogFileName =
const_cast<wchar_t*>(file_name)};
return OpenSessionImpl(logfile);
}
template <class ImplClass>
HRESULT EtwTraceConsumerBase<ImplClass>::OpenSessionImpl(
EVENT_TRACE_LOGFILE& logfile) {
if (ImplClass::kEnableRecordMode) {
logfile.ProcessTraceMode |= PROCESS_TRACE_MODE_EVENT_RECORD;
logfile.EventRecordCallback = &ProcessEventRecordCallback;
} else {
logfile.EventCallback = &ProcessEventCallback;
}
if (ImplClass::kRawTimestamp) {
logfile.ProcessTraceMode |= PROCESS_TRACE_MODE_RAW_TIMESTAMP;
}
logfile.BufferCallback = &ProcessBufferCallback;
logfile.Context = this;
TRACEHANDLE trace_handle = ::OpenTrace(&logfile);
if (reinterpret_cast<TRACEHANDLE>(INVALID_HANDLE_VALUE) == trace_handle) {
return HRESULT_FROM_WIN32(::GetLastError());
}
trace_handles_.push_back(trace_handle);
return S_OK;
}
template <class ImplClass>
inline HRESULT EtwTraceConsumerBase<ImplClass>::Consume() {
base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
base::BlockingType::MAY_BLOCK);
ULONG err = ::ProcessTrace(&trace_handles_[0],
static_cast<ULONG>(trace_handles_.size()), nullptr,
nullptr);
return HRESULT_FROM_WIN32(err);
}
template <class ImplClass>
inline HRESULT EtwTraceConsumerBase<ImplClass>::Close() {
HRESULT hr = S_OK;
for (size_t i = 0; i < trace_handles_.size(); ++i) {
if (NULL != trace_handles_[i]) {
ULONG ret = ::CloseTrace(trace_handles_[i]);
trace_handles_[i] = NULL;
if (FAILED(HRESULT_FROM_WIN32(ret))) {
hr = HRESULT_FROM_WIN32(ret);
}
}
}
trace_handles_.clear();
return hr;
}
}
}
#endif