#ifndef BASE_WIN_EVENT_TRACE_PROVIDER_H_
#define BASE_WIN_EVENT_TRACE_PROVIDER_H_
#include <windows.h>
#include <cguid.h>
#include <evntrace.h>
#include <stddef.h>
#include <stdint.h>
#include <wmistr.h>
#include <array>
#include <limits>
#include <type_traits>
#include "base/base_export.h"
#include "base/compiler_specific.h"
namespace base {
namespace win {
using EtwEventClass = GUID;
using EtwEventType = UCHAR;
using EtwEventLevel = UCHAR;
using EtwEventVersion = USHORT;
using EtwEventFlags = ULONG;
template <size_t N>
struct EtwMofEventBase {
EVENT_TRACE_HEADER header;
std::array<MOF_FIELD, N> fields;
};
template <size_t N>
class EtwMofEvent : public EtwMofEventBase<N> {
public:
using Super = EtwMofEventBase<N>;
static_assert(std::is_trivial_v<Super> && std::is_standard_layout_v<Super>,
"EtwMofEventBase must be a POD type.");
using EtwMofEventBase<N>::header;
using EtwMofEventBase<N>::fields;
EtwMofEvent() : Super{} {}
EtwMofEvent(const EtwEventClass& event_class,
EtwEventType type,
EtwEventLevel level)
: Super{} {
header.Size = sizeof(Super);
header.Guid = event_class;
header.Class.Type = type;
header.Class.Level = level;
header.Flags = WNODE_FLAG_TRACED_GUID | WNODE_FLAG_USE_MOF_PTR;
}
EtwMofEvent(const EtwEventClass& event_class,
EtwEventType type,
EtwEventVersion version,
EtwEventLevel level)
: Super{} {
header.Size = sizeof(Super);
header.Guid = event_class;
header.Class.Type = type;
header.Class.Version = version;
header.Class.Level = level;
header.Flags = WNODE_FLAG_TRACED_GUID | WNODE_FLAG_USE_MOF_PTR;
}
EtwMofEvent(const EtwMofEvent&) = delete;
EtwMofEvent& operator=(const EtwMofEvent&) = delete;
void SetField(size_t field, size_t size, const void* data) {
if ((field < N) && (size <= std::numeric_limits<uint32_t>::max())) {
fields[field].DataPtr = reinterpret_cast<ULONG64>(data);
fields[field].Length = static_cast<ULONG>(size);
}
}
EVENT_TRACE_HEADER* get() { return &header; }
};
class BASE_EXPORT EtwTraceProvider {
public:
explicit EtwTraceProvider(const GUID& provider_name);
EtwTraceProvider();
EtwTraceProvider(const EtwTraceProvider&) = delete;
EtwTraceProvider& operator=(const EtwTraceProvider&) = delete;
virtual ~EtwTraceProvider();
ULONG Register();
ULONG Unregister();
void set_provider_name(const GUID& provider_name) {
provider_name_ = provider_name;
}
const GUID& provider_name() const LIFETIME_BOUND { return provider_name_; }
TRACEHANDLE registration_handle() const { return registration_handle_; }
TRACEHANDLE session_handle() const { return session_handle_; }
EtwEventFlags enable_flags() const { return enable_flags_; }
EtwEventLevel enable_level() const { return enable_level_; }
bool ShouldLog(EtwEventLevel level, EtwEventFlags flags) {
return NULL != session_handle_ && level >= enable_level_ &&
(0 != (flags & enable_flags_));
}
ULONG Log(const EtwEventClass& event_class,
EtwEventType type,
EtwEventLevel level,
const char* message);
ULONG Log(const EtwEventClass& event_class,
EtwEventType type,
EtwEventLevel level,
const wchar_t* message);
ULONG Log(EVENT_TRACE_HEADER* event);
protected:
virtual void OnEventsEnabled() {}
virtual void OnEventsDisabled() {}
virtual void PostEventsDisabled() {}
private:
ULONG EnableEvents(PVOID buffer);
ULONG DisableEvents();
ULONG Callback(WMIDPREQUESTCODE request, PVOID buffer);
static ULONG WINAPI ControlCallback(WMIDPREQUESTCODE request,
PVOID context,
ULONG* reserved,
PVOID buffer);
GUID provider_name_ = GUID_NULL;
TRACEHANDLE registration_handle_ = NULL;
TRACEHANDLE session_handle_ = NULL;
EtwEventFlags enable_flags_ = 0;
EtwEventLevel enable_level_ = 0;
static TRACE_GUID_REGISTRATION obligatory_guid_registration_;
};
}
}
#endif