xref: /aosp_15_r20/external/cronet/base/win/event_trace_consumer.h (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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