15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2011 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Declaration of a Windows event trace provider class, to allow using
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Windows Event Tracing for logging transport and control.
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifndef BASE_WIN_EVENT_TRACE_PROVIDER_H_
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define BASE_WIN_EVENT_TRACE_PROVIDER_H_
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <windows.h>
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <wmistr.h>
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <evntrace.h>
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/base_export.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/basictypes.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace base {
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace win {
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef GUID EtwEventClass;
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef UCHAR EtwEventType;
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef UCHAR EtwEventLevel;
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef USHORT EtwEventVersion;
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef ULONG EtwEventFlags;
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Base class is a POD for correctness.
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)template <size_t N> struct EtwMofEventBase {
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EVENT_TRACE_HEADER header;
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MOF_FIELD fields[N];
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Utility class to auto-initialize event trace header structures.
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)template <size_t N> class EtwMofEvent: public EtwMofEventBase<N> {
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  typedef EtwMofEventBase<N> Super;
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // Clang and the C++ standard don't allow unqualified lookup into dependent
3890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // bases, hence these using decls to explicitly pull the names out.
3990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  using EtwMofEventBase<N>::header;
4090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  using EtwMofEventBase<N>::fields;
4190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EtwMofEvent() {
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    memset(static_cast<Super*>(this), 0, sizeof(Super));
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EtwMofEvent(const EtwEventClass& event_class, EtwEventType type,
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              EtwEventLevel level) {
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    memset(static_cast<Super*>(this), 0, sizeof(Super));
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    header.Size = sizeof(Super);
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    header.Guid = event_class;
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    header.Class.Type = type;
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    header.Class.Level = level;
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    header.Flags = WNODE_FLAG_TRACED_GUID | WNODE_FLAG_USE_MOF_PTR;
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EtwMofEvent(const EtwEventClass& event_class, EtwEventType type,
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              EtwEventVersion version, EtwEventLevel level) {
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    memset(static_cast<Super*>(this), 0, sizeof(Super));
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    header.Size = sizeof(Super);
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    header.Guid = event_class;
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    header.Class.Type = type;
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    header.Class.Version = version;
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    header.Class.Level = level;
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    header.Flags = WNODE_FLAG_TRACED_GUID | WNODE_FLAG_USE_MOF_PTR;
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void SetField(int field, size_t size, const void *data) {
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // DCHECK(field < N);
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if ((field < N) && (size <= kuint32max)) {
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      fields[field].DataPtr = reinterpret_cast<ULONG64>(data);
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      fields[field].Length = static_cast<ULONG>(size);
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EVENT_TRACE_HEADER* get() { return& header; }
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(EtwMofEvent);
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Trace provider with Event Tracing for Windows. The trace provider
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// registers with ETW by its name which is a GUID. ETW calls back to
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// the object whenever the trace level or enable flags for this provider
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// name changes.
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Users of this class can test whether logging is currently enabled at
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// a particular trace level, and whether particular enable flags are set,
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// before other resources are consumed to generate and issue the log
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// messages themselves.
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class BASE_EXPORT EtwTraceProvider {
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Creates an event trace provider identified by provider_name, which
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // will be the name registered with Event Tracing for Windows (ETW).
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  explicit EtwTraceProvider(const GUID& provider_name);
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Creates an unnamed event trace provider, the provider must be given
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // a name before registration.
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EtwTraceProvider();
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual ~EtwTraceProvider();
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Registers the trace provider with Event Tracing for Windows.
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Note: from this point forward ETW may call the provider's control
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //    callback. If the provider's name is enabled in some trace session
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //    already, the callback may occur recursively from this call, so
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //    call this only when you're ready to handle callbacks.
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ULONG Register();
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Unregisters the trace provider with ETW.
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ULONG Unregister();
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Accessors.
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void set_provider_name(const GUID& provider_name) {
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    provider_name_ = provider_name;
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const GUID& provider_name() const { return provider_name_; }
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  TRACEHANDLE registration_handle() const { return registration_handle_; }
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  TRACEHANDLE session_handle() const { return session_handle_; }
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EtwEventFlags enable_flags() const { return enable_flags_; }
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EtwEventLevel enable_level() const { return enable_level_; }
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Returns true iff logging should be performed for "level" and "flags".
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Note: flags is treated as a bitmask, and should normally have a single
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //      bit set, to test whether to log for a particular sub "facility".
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool ShouldLog(EtwEventLevel level, EtwEventFlags flags) {
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return NULL != session_handle_ && level >= enable_level_ &&
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        (0 != (flags & enable_flags_));
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Simple wrappers to log Unicode and ANSI strings.
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Do nothing if !ShouldLog(level, 0xFFFFFFFF).
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ULONG Log(const EtwEventClass& event_class, EtwEventType type,
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            EtwEventLevel level, const char *message);
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ULONG Log(const EtwEventClass& event_class, EtwEventType type,
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            EtwEventLevel level, const wchar_t *message);
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Log the provided event.
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ULONG Log(EVENT_TRACE_HEADER* event);
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) protected:
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Called after events have been enabled, override in subclasses
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // to set up state or log at the start of a session.
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Note: This function may be called ETW's thread and may be racy,
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //    bring your own locking if needed.
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void OnEventsEnabled() {}
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Called just before events are disabled, override in subclasses
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // to tear down state or log at the end of a session.
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Note: This function may be called ETW's thread and may be racy,
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //    bring your own locking if needed.
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void OnEventsDisabled() {}
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Called just after events have been disabled, override in subclasses
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // to tear down state at the end of a session. At this point it's
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // to late to log anything to the session.
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Note: This function may be called ETW's thread and may be racy,
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //    bring your own locking if needed.
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void PostEventsDisabled() {}
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ULONG EnableEvents(PVOID buffer);
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ULONG DisableEvents();
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ULONG Callback(WMIDPREQUESTCODE request, PVOID buffer);
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static ULONG WINAPI ControlCallback(WMIDPREQUESTCODE request, PVOID context,
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      ULONG *reserved, PVOID buffer);
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GUID provider_name_;
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  TRACEHANDLE registration_handle_;
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  TRACEHANDLE session_handle_;
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EtwEventFlags enable_flags_;
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EtwEventLevel enable_level_;
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We don't use this, but on XP we're obliged to pass one in to
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // RegisterTraceGuids. Non-const, because that's how the API needs it.
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static TRACE_GUID_REGISTRATION obligatory_guid_registration_;
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(EtwTraceProvider);
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace win
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace base
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif  // BASE_WIN_EVENT_TRACE_PROVIDER_H_
181