Home | History | Annotate | Download | only in win
      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.
     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 
     88 template <class ImplClass> inline
     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
    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
    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
    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