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