• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
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 #include <wmistr.h>
11 #include <evntrace.h>
12 #include <stddef.h>
13 #include <vector>
14 
15 #include "base/macros.h"
16 
17 namespace base {
18 namespace win {
19 
20 // This class is a base class that makes it easier to consume events
21 // from realtime or file sessions. Concrete consumers need to subclass
22 // a specialization of this class and override the ProcessEvent and/or
23 // the ProcessBuffer methods to implement the event consumption logic.
24 // Usage might look like:
25 // class MyConsumer: public EtwTraceConsumerBase<MyConsumer, 1> {
26 //  protected:
27 //    static VOID WINAPI ProcessEvent(PEVENT_TRACE event);
28 // };
29 //
30 // MyConsumer consumer;
31 // consumer.OpenFileSession(file_path);
32 // consumer.Consume();
33 template <class ImplClass>
34 class EtwTraceConsumerBase {
35  public:
36   // Constructs a closed consumer.
EtwTraceConsumerBase()37   EtwTraceConsumerBase() {
38   }
39 
~EtwTraceConsumerBase()40   ~EtwTraceConsumerBase() {
41     Close();
42   }
43 
44   // Opens the named realtime session, which must be existent.
45   // Note: You can use OpenRealtimeSession or OpenFileSession
46   //    to open as many as MAXIMUM_WAIT_OBJECTS (63) sessions at
47   //    any one time, though only one of them may be a realtime
48   //    session.
49   HRESULT OpenRealtimeSession(const wchar_t* session_name);
50 
51   // Opens the event trace log in "file_name", which must be a full or
52   // relative path to an existing event trace log file.
53   // Note: You can use OpenRealtimeSession or OpenFileSession
54   //    to open as many as kNumSessions at any one time.
55   HRESULT OpenFileSession(const wchar_t* file_name);
56 
57   // Consume all open sessions from beginning to end.
58   HRESULT Consume();
59 
60   // Close all open sessions.
61   HRESULT Close();
62 
63  protected:
64   // Override in subclasses to handle events.
ProcessEvent(EVENT_TRACE * event)65   static void ProcessEvent(EVENT_TRACE* event) {
66   }
67   // Override in subclasses to handle buffers.
ProcessBuffer(EVENT_TRACE_LOGFILE * buffer)68   static bool ProcessBuffer(EVENT_TRACE_LOGFILE* buffer) {
69     return true;  // keep going
70   }
71 
72  protected:
73   // Currently open sessions.
74   std::vector<TRACEHANDLE> trace_handles_;
75 
76  private:
77   // These delegate to ImplClass callbacks with saner signatures.
ProcessEventCallback(EVENT_TRACE * event)78   static void WINAPI ProcessEventCallback(EVENT_TRACE* event) {
79     ImplClass::ProcessEvent(event);
80   }
ProcessBufferCallback(PEVENT_TRACE_LOGFILE buffer)81   static ULONG WINAPI ProcessBufferCallback(PEVENT_TRACE_LOGFILE buffer) {
82     return ImplClass::ProcessBuffer(buffer);
83   }
84 
85   DISALLOW_COPY_AND_ASSIGN(EtwTraceConsumerBase);
86 };
87 
88 template <class ImplClass> inline
OpenRealtimeSession(const wchar_t * session_name)89 HRESULT EtwTraceConsumerBase<ImplClass>::OpenRealtimeSession(
90     const wchar_t* session_name) {
91   EVENT_TRACE_LOGFILE logfile = {};
92   logfile.LoggerName = const_cast<wchar_t*>(session_name);
93   logfile.LogFileMode = EVENT_TRACE_REAL_TIME_MODE;
94   logfile.BufferCallback = &ProcessBufferCallback;
95   logfile.EventCallback = &ProcessEventCallback;
96   logfile.Context = this;
97   TRACEHANDLE trace_handle = ::OpenTrace(&logfile);
98   if (reinterpret_cast<TRACEHANDLE>(INVALID_HANDLE_VALUE) == trace_handle)
99     return HRESULT_FROM_WIN32(::GetLastError());
100 
101   trace_handles_.push_back(trace_handle);
102   return S_OK;
103 }
104 
105 template <class ImplClass> inline
OpenFileSession(const wchar_t * file_name)106 HRESULT EtwTraceConsumerBase<ImplClass>::OpenFileSession(
107     const wchar_t* file_name) {
108   EVENT_TRACE_LOGFILE logfile = {};
109   logfile.LogFileName = const_cast<wchar_t*>(file_name);
110   logfile.BufferCallback = &ProcessBufferCallback;
111   logfile.EventCallback = &ProcessEventCallback;
112   logfile.Context = this;
113   TRACEHANDLE trace_handle = ::OpenTrace(&logfile);
114   if (reinterpret_cast<TRACEHANDLE>(INVALID_HANDLE_VALUE) == trace_handle)
115     return HRESULT_FROM_WIN32(::GetLastError());
116 
117   trace_handles_.push_back(trace_handle);
118   return S_OK;
119 }
120 
121 template <class ImplClass> inline
Consume()122 HRESULT EtwTraceConsumerBase<ImplClass>::Consume() {
123   ULONG err = ::ProcessTrace(&trace_handles_[0],
124                              static_cast<ULONG>(trace_handles_.size()),
125                              NULL,
126                              NULL);
127   return HRESULT_FROM_WIN32(err);
128 }
129 
130 template <class ImplClass> inline
Close()131 HRESULT EtwTraceConsumerBase<ImplClass>::Close() {
132   HRESULT hr = S_OK;
133   for (size_t i = 0; i < trace_handles_.size(); ++i) {
134     if (NULL != trace_handles_[i]) {
135       ULONG ret = ::CloseTrace(trace_handles_[i]);
136       trace_handles_[i] = NULL;
137 
138       if (FAILED(HRESULT_FROM_WIN32(ret)))
139         hr = HRESULT_FROM_WIN32(ret);
140     }
141   }
142   trace_handles_.clear();
143 
144   return hr;
145 }
146 
147 }  // namespace win
148 }  // namespace base
149 
150 #endif  // BASE_WIN_EVENT_TRACE_CONSUMER_H_
151