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