Using advanced logging to log custom module data

Posted: Apr 18, 2009  2 comments  

Average Rating

Tags
Advanced Logging

Advanced logging module which media team released few days ago uses IIS tracing subsystem and allow module developers to log custom data in W3C compatible format using familiar IHttpTraceContext interface. If you are a module developer and want to generate W3C style logs for requests with custom data, doing it with advanced logging module is very easy. All you need to do is call IHttpTraceContext::RaiseTraceEvent passing data you want to publish. Your module installer can then configure advanced logging module to make it dump this data in a log file and you have complete logging solution without ever have to deal with log files yourself. Let’s see what it takes to make use of this functionality.

Generating trace information in your module

I have a simple class below which hides some of the complexity of IIS tracing subsystem. You can use most of the code below directly in your module. Just change area GUID and also code under RaiseEvent to dump your own custom data.

#include <httpserv.h>
#include <httptrace.h>

//
// Start of the new provider class AdvancedLoggingTraceProvider,
//
// GUID: {f41fdbf7-1b0a-45e9-9666-2918b0a9d144}
// NOTE:
// You must use this provider GUID for advanced logging to
// process events generated by your module
//
// Description: IIS: Advanced Logging
//
class AdvancedLoggingTraceProvider
{
public:
    static
    LPCGUID
    GetProviderGuid(
        VOID
    )
    {
        static const GUID AdvLoggingProviderGuid =
          {0xf41fdbf7,0x1b0a,0x45e9,{0x96,0x66,0x29,0x18,0xb0,0xa9,0xd1,0x44}};
        return &AdvLoggingProviderGuid;
    };

    enum enumAreaFlags
    {
        IISAdvancedLoggingGeneral = 0x0000
    };

    static
    LPCWSTR
    TranslateEnumAreaFlagsToString(
        enum enumAreaFlags EnumValue
    )
    {
        switch( (DWORD) EnumValue )
        {
            case 0x0000: return L"IISAdvancedLoggingGeneral";
        }
        return NULL;
    };

    static
    BOOL
    CheckTracingEnabled(
        IHttpTraceContext * pHttpTraceContext,
        enumAreaFlags       AreaFlags,
        DWORD               dwVerbosity
    )
    {
        HRESULT                  hr;
        HTTP_TRACE_CONFIGURATION TraceConfig;
        TraceConfig.pProviderGuid = GetProviderGuid();
        hr = pHttpTraceContext->GetTraceConfiguration( &TraceConfig );
        if ( FAILED( hr )  || !TraceConfig.fProviderEnabled )
        {
            return FALSE;
        }
        if ( TraceConfig.dwVerbosity >= dwVerbosity &&
             (  TraceConfig.dwAreas == (DWORD) AreaFlags || 
             ( TraceConfig.dwAreas & (DWORD)AreaFlags ) == (DWORD)AreaFlags ) )
        {
            return TRUE;
        }
        return FALSE;
    };
};

//
// Start of the new event class IISAdvancedLoggingGeneralEvents
// GUID: {ffa89186-ec59-42c1-988f-bbbd0ee48d4f}
// Use any random area GUID
// Description: Advanced Logging general events
//
class IISAdvancedLoggingGeneralEvents
{
public:
    static LPCGUID GetAreaGuid( VOID )
    {
        static const GUID AreaGuid =
          {0xffa89186,0xec59,0x42c1,{0x98,0x8f,0xbb,0xbd,0x0e,0xe4,0x8d,0x4f}};
        return &AreaGuid;
    };

    class SAMPLE_TRACE_EVENT
    {
    public:
        static
        HRESULT
        RaiseEvent(
            IHttpTraceContext * pHttpTraceContext,
            LPCGUID      pContextId,
            LPCWSTR      pSample_Data1,
            LPCWSTR      pSample_Data2
        )
        {
            HTTP_TRACE_EVENT Event;
            Event.pProviderGuid  = AdvancedLoggingTraceProvider::GetProviderGuid();
            Event.dwArea         =  AdvancedLoggingTraceProvider::IISAdvancedLoggingGeneral;
            Event.pAreaGuid      = IISAdvancedLoggingGeneralEvents::GetAreaGuid();
            Event.dwEvent        = 1;
            Event.pszEventName   = L"SAMPLE_TRACE_EVENT";
            Event.dwEventVersion = 1;
            Event.dwVerbosity    = 0;
            Event.cEventItems    = 6;
            Event.pActivityGuid  = NULL;
            Event.pRelatedActivityGuid = NULL;
            Event.dwTimeStamp    = 0;
            Event.dwFlags        = HTTP_TRACE_EVENT_FLAG_STATIC_DESCRIPTIVE_FIELDS;

            // pActivityGuid, pRelatedActivityGuid, Timestamp to be filled in by IIS

            HTTP_TRACE_EVENT_ITEM Items[ 3 ];
            Items[ 0 ].pszName = L"ContextId";
            Items[ 0 ].dwDataType = HTTP_TRACE_TYPE_LPCGUID; // mof type (object)
            Items[ 0 ].pbData = (PBYTE) pContextId;
            Items[ 0 ].cbData = 16;
            Items[ 0 ].pszDataDescription = NULL;
            Items[ 1 ].pszName = L"Sample_Data1";
            Items[ 1 ].dwDataType = HTTP_TRACE_TYPE_LPCWSTR; // mof type (string)
            Items[ 1 ].pbData = (PBYTE) pSample_Data1;
            Items[ 1 ].cbData  =
                 ( Items[ 1 ].pbData == NULL )? 0 : ( sizeof(WCHAR) * (1 + (DWORD) wcslen( (PWSTR) Items[ 1 ].pbData  ) ) );
            Items[ 1 ].pszDataDescription = NULL;
            Items[ 2 ].pszName = L"Sample_Data2";
            Items[ 2 ].dwDataType = HTTP_TRACE_TYPE_LPCWSTR; // mof type (string)
            Items[ 2 ].pbData = (PBYTE) pSample_Data2;
            Items[ 2 ].cbData  =
                 ( Items[ 2 ].pbData == NULL )? 0 : ( sizeof(WCHAR) * (1 + (DWORD) wcslen( (PWSTR) Items[ 2 ].pbData  ) ) );
            Items[ 2 ].pszDataDescription = NULL;

            Event.pEventItems = Items;
            pHttpTraceContext->RaiseTraceEvent( &Event );

            return S_OK;
        };

        static
        BOOL
        IsEnabled(
            IHttpTraceContext *  pHttpTraceContext
        )
        {
            return AdvancedLoggingTraceProvider::CheckTracingEnabled(
                                 pHttpTraceContext,
                                 AdvancedLoggingTraceProvider::IISAdvancedLoggingGeneral,
                                 0 );
        }
    };
};

Once you have class(es) similar to SAMPLE_TRACE_EVENT defined for the event(s) you want to generate, you can just call RaiseEvent in your module. Before generating the event you should call IsEnabled() to check if a relevant trace provider is present with tracing enabled. Here is what you will write in your module.

IHttpTraceContext* pTraceContext = pContext->GetTraceContext();

if( IISAdvancedLoggingGeneralEvents::SAMPLE_TRACE_EVENT::IsEnabled( pTraceContext ) == TRUE )
{
    IISAdvancedLoggingGeneralEvents::SAMPLE_TRACE_EVENT::RaiseEvent( pTraceContext,
                                                                     NULL,
                                                                     “Data1”,
                                                                     “Data2” );
}

Configuring advanced logging to generate logs 


Now to dump data generated by your module in advanced logging logs, you need to create log definition and specify event names as field names in advanced logging configuration. To do this, follow the steps as below in advanced logging UI.

1.       Go to advanced logging UI and create a new log definition.

2.       Specify details and then add additional fields which your module is generating. In the sample above these are Sample_Data1 and Sample_Data2. As advanced logging require a unique name to identify the event uniquely, we recommend people to use “<ModuleName>_” as prefix in the event names.

3.       Restart w3svc (this requirement will be removed in the next release of advanced logging).

That’s it. Log file produced will have single entry for each request received by the server. If a request gets short circuited and never reaches your module code where you generate the trace event, Sample_Data1 and Sample_Data2 field values will be blank strings. To log only requests which reached your module’s RaiseEvent call, make Sample_Data1 and Sample_Data2 fields “required” in advanced logging configuration. Note that ability to mark a field “required” is not there in the UI yet. You can edit the IIS configuration file manually or you other tools like appcmd, configuration editor to do it. More detailed steps to configure advanced logging are available here.

Hope this helps.
Kanwal

Comments

  1. Anonymous
    November 20, 2009

    This is the welcome page for the dentaldoctor.us Association web site.

  2. Anonymous
    November 21, 2009

    This is the welcome page for the dietguidance.us Association web site.

Submit a Comment

Microsoft Communities