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