Home | History | Annotate | Download | only in win
      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 
     16 namespace base {
     17 namespace 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();
     32 template <class ImplClass>
     33 class 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 
     87 template <class ImplClass> inline
     88 HRESULT 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 
    104 template <class ImplClass> inline
    105 HRESULT 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 
    120 template <class ImplClass> inline
    121 HRESULT 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 
    129 template <class ImplClass> inline
    130 HRESULT 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