Event Tracing Provider Framework  

Setting up an application to be a provider

All event tracing providers must register themselves with the Operating System’s event tracer. This allows the provider to trace events and is controlled by the event tracer with a control callback function. This is implemented in the framework class CTraceController. An event tracing controller can control the provider (through the event tracer) by using the event tracing APIs.

Placing a CTraceController object at a global level in your project is a good choice as the control callback function will always be available when your application gets registered as a provider. Do something similar to this:

#include <WMIEVENTTRACING.H>
CTraceController g_Controller;

All event tracing providers must identify themselves using a GUID. Your next task is to generate a GUID using guidgen.exe. The sample event tracing provider that accompanies this article defines it’s GUID as:

// {14CA03A4-F36E-443e-8D03-9D1BE2DCD5CA}
GUID MY_EVENTTRACER = 
    {0x14ca03a4, 0xf36e, 0x443e, {0x8d, 0x3, 0x9d, 0x1b, 0xe2, 0xdc, 0xd5, 0xca}};

In addition to the provider’s GUID, a good event tracing provider should also register all of its event classes which are identified using a GUID. The sample event tracing provider defines its two event classes as:

// {D905720E-CE71-481a-BD10-14C71DACF283}
GUID MY_EVENTCLASS = 
    {0xd905720e, 0xce71, 0x481a, {0xbd, 0x10, 0x14, 0xc7, 0x1d, 0xac, 0xf2, 0x83}};

// {41D2379B-526A-466d-8748-C54546F74470}
GUID MY_VARIABLE_LEN_EVENTCLASS = 
    {0x41d2379b, 0x526a, 0x466d, {0x87, 0x48, 0xc5, 0x45, 0x46, 0xf7, 0x44, 0x70}};

We will discuss later what the above two event class’s look like (in terms of their data structure), but for now, the only requirement is the knowledge of what the event class GUIDs are so we can register them.

The simplest approach to understand how to use the CTraceController class is to look at a small sample. The following demonstrates the application’s event class GUIDs being added with AddEventType before Register is called. The Register method registers the application as an event tracing provider. The function, SomeFunction, is intended to represent the application performing some useful duties. When its time for the application to terminate, it un-registers itself by calling Unregister.

extern "C" int _tmain()
{
    // The supported event classes that this provider will trace
    g_Controller.AddEventType(&MY_EVENTCLASS);
    g_Controller.AddEventType(&MY_VARIABLE_LEN_EVENTCLASS);
    
    // Register this as an event tracing provider
    ULONG ulReg = g_Controller.Register(MY_EVENTTRACER);
    
    // Let the process do its stuff!
    SomeFunction();
    
    // Must un-register the provider!
    ULONG ulUnReg = g_Controller.Unregister();
    return 0;
}

Let’s look at how a function using the event tracing framework should proceed in firing events to the event tracer. One of the design goals for the framework was to make it easy to add a single statement to the code which fires an event. The function, SomeFunction, shows this using the macro ET_EVENT. Let’s have a look:

void SomeFunction()
{
    ETFunc(); // This function will trace events
    // Trace the fixed length structure event.
    ET_EVENT(CEventFixedLen(12345));

    // Trace the variable length structure event.
    ET_EVENT(CEventVariableLen(L"this string", L"that string", 
    L"other string"));
}

The macro, ETFunc, sets up a CTraceEvent object which initializes itself with details of the current event tracing session. This is then used by subsequent calls to ET_EVENT which fires the event. The function SomeFunction above fires two events, a fixed length event and a variable length event. The ETFunc macro looks like this:

#define ETFunc() \
    CTraceEvent event

You should have noticed that the macro, ET_EVENT, takes a single parameter. The framework works by encapsulating the generation of an event in a class derived from either CBaseEvent or CVariableLengthBaseEvent. The details of these two classes will be discussed later. For now, all you need to know is that the class provided to ET_EVENT will be used in firing the event; the class initializes the event structure together with its custom data which is ultimately passed to the event tracing API, TraceEvent. The ET_EVENT macro looks like this:

#define ET_EVENT(EventTraceClass) \
    try { event.Trace(EventTraceClass); } \
    catch(...) { OutputDebugString(_T("Caught event trace exception\n")); }

Contact Me   |  Developing WMI Solutions    |   Gwyn Cole's Developer Blog    |   Legal
 © 2003 Content by Gwyn Cole. All rights reserved.