IIS 7 C++ Module API Sample: Consuming Trace Events

 

Introduction

The attached sample IIS 7 module converts all tracing events into OutputDebugString calls. This is not something you'd want to do on a production box, because OutputDebugString can slow machines substantially. It is however very useful when you're performing functional debugging. This post assumes you've already got the hello world module working, so it jumps straight into API discussion. (There are many types of tracing from Microsoft, here is a diagram which attempts to show the relationships)

Registration

The module registers to receive trace events. There are many trace events available, so which events you'd like to receive is configured is HTTP_TRACE_CONFIGURATION. The hierarchy is identical to ETW's (provider, area, verbosity). When you configure these settings in the UI for "Failed Request Tracing", iisfreb.dll is converting that configuration into a couple of HTTP_TRACE_CONFIGURATION structures. Providers are identified by a GUID. For simplicity/convenience a special GUID, called GUID_IIS_ALL_TRACE_PROVIDERS is available. It is the equivalent to asking for all registerer trace providers. (Creating a custom provider is not covered in this post) For consistency's sake, the module also has to register for the GL_TRACE_EVENT notification.
    HTTP_TRACE_CONFIGURATION TraceConfiguration = {0}; 
    TraceConfiguration.pProviderGuid    = &GUID_IIS_ALL_TRACE_PROVIDERS;
    TraceConfiguration.dwAreas          = 0xFFFF;
    TraceConfiguration.dwVerbosity      = 5;
    TraceConfiguration.fProviderEnabled = TRUE;

    ...

    hr = pModuleInfo->SetGlobalNotifications( pGlobalModule, GL_TRACE_EVENT );

    ...

    hr = pGlobalInfo->GetTraceContext( )->
        SetTraceConfiguration( g_pModuleContext, &TraceConfiguration, 1 );

Consumption

Since the module registered for GL_TRACE_EVENT, it must implement GLOBAL_MODULE::OnGlobalTraceEvent. This function is called every time an event is raised. Now it's simply a matter of extracting interesting information from the event and OutputDebugString'ing it:
    hr = pProvider->GetTraceEvent( &pEvent );

    ...

    cItems = pEvent->cEventItems;

    hr = StringCchPrintf(
        pszBuffer,
        sizeof( pszBuffer ) / sizeof( pszBuffer[0] ),
        L"Event: %s (%s,%s,%s,%s)\n",
        pEvent->pszEventName,
        ...

    OutputDebugString( pszBuffer );
Since this module only subscribes to global events, it only needs to be in the <globalModules> list. Once working you should see output like this in your debugger/dbmon:
Event: GENERAL_REQUEST_START (,,DefaultAppPool,)
Event: PRE_BEGIN_REQUEST_START (,FailedRequestsTracingModule,,)
Event: PRE_BEGIN_REQUEST_END (,FailedRequestsTracingModule,,)
Event: PRE_BEGIN_REQUEST_START (,RequestMonitorModule,,)
Event: PRE_BEGIN_REQUEST_END (,RequestMonitorModule,,)
Event: PRE_BEGIN_REQUEST_START (,IsapiFilterModule,,)
Event: FILTER_START (,D:\Windows\Microsoft.NET\Framework\v2.0.
50727\aspnet_filter.dll,,)
Event: FILTER_PREPROC_HEADERS_START (,,,)
Event: GENERAL_SET_REQUEST_HEADER (,,,)
Event: FILTER_SET_REQ_HEADER (,,,)
Event: FILTER_PREPROC_HEADERS_END (,,,)
Event: FILTER_END (,,,)
Event: PRE_BEGIN_REQUEST_END (,IsapiFilterModule,,)
Event: GENERAL_REQUEST_HEADERS (,,,)
Event: URL_CACHE_ACCESS_START (,/d,,)
Event: URL_CACHE_ACCESS_END (,,,)
Event: HANDLER_PRECONDITION_NOT_MATCH (,AXD-ISAPI-2.0,class
icMode,runtimeVersion

No Comments