1 // Copyright 2012 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 //
5 // Declaration of a Windows event trace consumer base class.
6 #ifndef BASE_WIN_EVENT_TRACE_CONSUMER_H_
7 #define BASE_WIN_EVENT_TRACE_CONSUMER_H_
8
9 #include <windows.h>
10
11 #include <evntcons.h>
12 #include <evntrace.h>
13 #include <stddef.h>
14 #include <wmistr.h>
15
16 #include <vector>
17
18 #include "base/threading/scoped_blocking_call.h"
19
20 namespace base {
21 namespace win {
22
23 // This class is a base class that makes it easier to consume events
24 // from realtime or file sessions. Concrete consumers need to subclass a
25 // specialization of this class and override the ProcessEvent, the
26 // ProcessEventRecord and/or the ProcessBuffer methods to implement the
27 // event consumption logic.
28 // Usage might look like:
29 // class MyConsumer: public EtwTraceConsumerBase<MyConsumer, 1> {
30 // protected:
31 // static VOID WINAPI ProcessEvent(PEVENT_TRACE event);
32 // };
33 //
34 // MyConsumer consumer;
35 // consumer.OpenFileSession(file_path);
36 // consumer.Consume();
37 template <class ImplClass>
38 class EtwTraceConsumerBase {
39 public:
40 // If true, receive events in the new EVENT_RECORD format. To receive
41 // events in the new format, ProcessEventRecord() must be overridden.
42 // See PROCESS_TRACE_MODE_EVENT_RECORD from
43 // https://learn.microsoft.com/en-us/windows/win32/api/evntrace/ns-evntrace-event_trace_logfilea
44 static constexpr bool kEnableRecordMode = false;
45 // If true, TimeStamps in EVENT_HEADER and EVENT_TRACE_HEADER are not
46 // converted to system time. See PROCESS_TRACE_MODE_RAW_TIMESTAMP from
47 // https://learn.microsoft.com/en-us/windows/win32/api/evntrace/ns-evntrace-event_trace_logfilea
48 static constexpr bool kRawTimestamp = false;
49
50 // Constructs a closed consumer.
51 EtwTraceConsumerBase() = default;
52
53 EtwTraceConsumerBase(const EtwTraceConsumerBase&) = delete;
54 EtwTraceConsumerBase& operator=(const EtwTraceConsumerBase&) = delete;
55
~EtwTraceConsumerBase()56 ~EtwTraceConsumerBase() { Close(); }
57
58 // Opens the named realtime session, which must be existent.
59 // Note: You can use OpenRealtimeSession or OpenFileSession
60 // to open as many as MAXIMUM_WAIT_OBJECTS (63) sessions at
61 // any one time, though only one of them may be a realtime
62 // session.
63 HRESULT OpenRealtimeSession(const wchar_t* session_name);
64
65 // Opens the event trace log in "file_name", which must be a full or
66 // relative path to an existing event trace log file.
67 // Note: You can use OpenRealtimeSession or OpenFileSession
68 // to open as many as kNumSessions at any one time.
69 HRESULT OpenFileSession(const wchar_t* file_name);
70
71 // Consume all open sessions from beginning to end.
72 HRESULT Consume();
73
74 // Close all open sessions.
75 HRESULT Close();
76
77 protected:
78 // Override in subclasses to handle events.
ProcessEvent(EVENT_TRACE * event)79 static void ProcessEvent(EVENT_TRACE* event) {}
80 // Override in subclasses to handle events.
ProcessEventRecord(EVENT_RECORD * event_record)81 static void ProcessEventRecord(EVENT_RECORD* event_record) {}
82 // Override in subclasses to handle buffers.
ProcessBuffer(EVENT_TRACE_LOGFILE * buffer)83 static bool ProcessBuffer(EVENT_TRACE_LOGFILE* buffer) {
84 return true; // keep going
85 }
86
87 HRESULT OpenSessionImpl(EVENT_TRACE_LOGFILE& logfile);
88
89 protected:
90 // Currently open sessions.
91 std::vector<TRACEHANDLE> trace_handles_;
92
93 private:
94 // These delegate to ImplClass callbacks with saner signatures.
ProcessEventCallback(EVENT_TRACE * event)95 static void WINAPI ProcessEventCallback(EVENT_TRACE* event) {
96 ImplClass::ProcessEvent(event);
97 }
ProcessEventRecordCallback(EVENT_RECORD * event_record)98 static void WINAPI ProcessEventRecordCallback(EVENT_RECORD* event_record) {
99 ImplClass::ProcessEventRecord(event_record);
100 }
ProcessBufferCallback(PEVENT_TRACE_LOGFILE buffer)101 static ULONG WINAPI ProcessBufferCallback(PEVENT_TRACE_LOGFILE buffer) {
102 return ImplClass::ProcessBuffer(buffer);
103 }
104 };
105
106 template <class ImplClass>
OpenRealtimeSession(const wchar_t * session_name)107 inline HRESULT EtwTraceConsumerBase<ImplClass>::OpenRealtimeSession(
108 const wchar_t* session_name) {
109 EVENT_TRACE_LOGFILE logfile = {
110 .LoggerName = const_cast<wchar_t*>(session_name),
111 .ProcessTraceMode = PROCESS_TRACE_MODE_REAL_TIME,
112 };
113 return OpenSessionImpl(logfile);
114 }
115
116 template <class ImplClass>
OpenFileSession(const wchar_t * file_name)117 inline HRESULT EtwTraceConsumerBase<ImplClass>::OpenFileSession(
118 const wchar_t* file_name) {
119 EVENT_TRACE_LOGFILE logfile = {.LogFileName =
120 const_cast<wchar_t*>(file_name)};
121 return OpenSessionImpl(logfile);
122 }
123
124 template <class ImplClass>
OpenSessionImpl(EVENT_TRACE_LOGFILE & logfile)125 HRESULT EtwTraceConsumerBase<ImplClass>::OpenSessionImpl(
126 EVENT_TRACE_LOGFILE& logfile) {
127 if (ImplClass::kEnableRecordMode) {
128 logfile.ProcessTraceMode |= PROCESS_TRACE_MODE_EVENT_RECORD;
129 logfile.EventRecordCallback = &ProcessEventRecordCallback;
130 } else {
131 logfile.EventCallback = &ProcessEventCallback;
132 }
133 if (ImplClass::kRawTimestamp) {
134 logfile.ProcessTraceMode |= PROCESS_TRACE_MODE_RAW_TIMESTAMP;
135 }
136 logfile.BufferCallback = &ProcessBufferCallback;
137 logfile.Context = this;
138 TRACEHANDLE trace_handle = ::OpenTrace(&logfile);
139 if (reinterpret_cast<TRACEHANDLE>(INVALID_HANDLE_VALUE) == trace_handle)
140 return HRESULT_FROM_WIN32(::GetLastError());
141
142 trace_handles_.push_back(trace_handle);
143 return S_OK;
144 }
145
146 template <class ImplClass>
Consume()147 inline HRESULT EtwTraceConsumerBase<ImplClass>::Consume() {
148 base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
149 base::BlockingType::MAY_BLOCK);
150 ULONG err = ::ProcessTrace(&trace_handles_[0],
151 static_cast<ULONG>(trace_handles_.size()), nullptr,
152 nullptr);
153 return HRESULT_FROM_WIN32(err);
154 }
155
156 template <class ImplClass>
Close()157 inline HRESULT EtwTraceConsumerBase<ImplClass>::Close() {
158 HRESULT hr = S_OK;
159 for (size_t i = 0; i < trace_handles_.size(); ++i) {
160 if (NULL != trace_handles_[i]) {
161 ULONG ret = ::CloseTrace(trace_handles_[i]);
162 trace_handles_[i] = NULL;
163
164 if (FAILED(HRESULT_FROM_WIN32(ret)))
165 hr = HRESULT_FROM_WIN32(ret);
166 }
167 }
168 trace_handles_.clear();
169
170 return hr;
171 }
172
173 } // namespace win
174 } // namespace base
175
176 #endif // BASE_WIN_EVENT_TRACE_CONSUMER_H_
177