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
17namespace base {
18namespace 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();
33template <class ImplClass>
34class EtwTraceConsumerBase {
35 public:
36  // Constructs a closed consumer.
37  EtwTraceConsumerBase() {
38  }
39
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.
65  static void ProcessEvent(EVENT_TRACE* event) {
66  }
67  // Override in subclasses to handle buffers.
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.
78  static void WINAPI ProcessEventCallback(EVENT_TRACE* event) {
79    ImplClass::ProcessEvent(event);
80  }
81  static ULONG WINAPI ProcessBufferCallback(PEVENT_TRACE_LOGFILE buffer) {
82    return ImplClass::ProcessBuffer(buffer);
83  }
84
85  DISALLOW_COPY_AND_ASSIGN(EtwTraceConsumerBase);
86};
87
88template <class ImplClass> inline
89HRESULT 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
105template <class ImplClass> inline
106HRESULT 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
121template <class ImplClass> inline
122HRESULT 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
130template <class ImplClass> inline
131HRESULT 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