event_trace_consumer.h revision 513209b27ff55e2841eac0e4120199c23acce758
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
16namespace base {
17namespace 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();
32template <class ImplClass>
33class EtwTraceConsumerBase {
34 public:
35  // Constructs a closed consumer.
36  EtwTraceConsumerBase() {
37  }
38
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.
64  static void ProcessEvent(EVENT_TRACE* event) {
65  }
66  // Override in subclasses to handle buffers.
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.
77  static void WINAPI ProcessEventCallback(EVENT_TRACE* event) {
78    ImplClass::ProcessEvent(event);
79  }
80  static ULONG WINAPI ProcessBufferCallback(PEVENT_TRACE_LOGFILE buffer) {
81    return ImplClass::ProcessBuffer(buffer);
82  }
83
84  DISALLOW_COPY_AND_ASSIGN(EtwTraceConsumerBase);
85};
86
87template <class ImplClass> inline
88HRESULT 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
104template <class ImplClass> inline
105HRESULT 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
120template <class ImplClass> inline
121HRESULT 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
129template <class ImplClass> inline
130HRESULT 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