다음을 통해 공유


이벤트 메타데이터 검색

다음 예제에서는 추적 데이터 도우미 함수를 사용하여 각 이벤트에 대한 메타데이터를 검색하는 방법을 보여 줍니다. TdhQueryProviderFieldInformationTdhEnumerateProviderFieldInformation 함수에 포함된 예제도 참조하세요.

//Turns the DEFINE_GUID for EventTraceGuid into a const.
#define INITGUID

#include <windows.h>
#include <stdio.h>
#include <comdef.h>
#include <guiddef.h>
#include <wbemidl.h>
#include <wmistr.h>
#include <evntrace.h>
#include <tdh.h>

#pragma comment(lib, "tdh.lib")

#define LOGFILE_PATH L"<FULLPATHTOTHELOGFILE.etl>"

static const GUID GUID_NULL = 
{ 0x00000000, 0x0000, 0x0000, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } };

// Strings that represent the source of the event metadata.

WCHAR* pSource[] = {L"XML instrumentation manifest", L"WMI MOF class", L"WPP TMF file"};

// Handle to the trace file that you opened.

TRACEHANDLE g_hTrace = 0;  


// Prototypes

void WINAPI ProcessEvent(PEVENT_RECORD pEvent);
DWORD GetEventInformation(PEVENT_RECORD pEvent, PTRACE_EVENT_INFO & pInfo);
DWORD PrintPropertyMetadata(TRACE_EVENT_INFO* pInfo, DWORD i, USHORT indent);


void wmain(void)
{
    ULONG status = ERROR_SUCCESS;
    EVENT_TRACE_LOGFILE trace;
    TRACE_LOGFILE_HEADER* pHeader = &trace.LogfileHeader;

    // Identify the log file from which you want to consume events
    // and the callbacks used to process the events and buffers.

    ZeroMemory(&trace, sizeof(EVENT_TRACE_LOGFILE));
    trace.LogFileName = (LPWSTR) LOGFILE_PATH;
    trace.EventRecordCallback = (PEVENT_RECORD_CALLBACK) (ProcessEvent);
    trace.ProcessTraceMode = PROCESS_TRACE_MODE_EVENT_RECORD;

    g_hTrace = OpenTrace(&trace);
    if (INVALID_PROCESSTRACE_HANDLE == g_hTrace)
    {
        wprintf(L"OpenTrace failed with %lu\n", GetLastError());
        goto cleanup;
    }

    status = ProcessTrace(&g_hTrace, 1, 0, 0);
    if (status != ERROR_SUCCESS && status != ERROR_CANCELLED)
    {
        wprintf(L"ProcessTrace failed with %lu\n", status);
        goto cleanup;
    }

cleanup:

    if (INVALID_PROCESSTRACE_HANDLE != g_hTrace)
    {
        status = CloseTrace(g_hTrace);
    }
}


VOID WINAPI ProcessEvent(PEVENT_RECORD pEvent)
{
    DWORD status = ERROR_SUCCESS;
    HRESULT hr = S_OK;
    PTRACE_EVENT_INFO pInfo = NULL;
    LPWSTR pStringGuid = NULL;


    // Skips the event if it is the event trace header. Log files contain this event
    // but real-time sessions do not. The event contains the same information as 
    // the EVENT_TRACE_LOGFILE.LogfileHeader member that you can access when you open 
    // the trace. 

    if (IsEqualGUID(pEvent->EventHeader.ProviderId, EventTraceGuid) &&
        pEvent->EventHeader.EventDescriptor.Opcode == EVENT_TRACE_TYPE_INFO)
    {
        ; // Skip this event.
    }
    else
    {
        // Process the event. This example does not process the event data but
        // instead prints the metadata that describes each event.

        status = GetEventInformation(pEvent, pInfo);

        if (ERROR_SUCCESS != status)
        {
            wprintf(L"GetEventInformation failed with %lu\n", status);
            goto cleanup;
        }

        wprintf(L"Decoding source: %s\n", pSource[pInfo->DecodingSource]);

        if (DecodingSourceWPP == pInfo->DecodingSource)
        {
            // This example is not rendering WPP metadata.
            goto cleanup;
        }

        if (pInfo->ProviderNameOffset > 0)
        {
            wprintf(L"Provider name: %s\n", (LPWSTR)((PBYTE)(pInfo) + pInfo->ProviderNameOffset));
        }

        hr = StringFromCLSID(pInfo->ProviderGuid, &pStringGuid);
        if (FAILED(hr))
        {
            wprintf(L"StringFromCLSID(ProviderGuid) failed with 0x%x\n", hr);
            status = hr;
            goto cleanup;
        }

        wprintf(L"\nProvider GUID: %s\n", pStringGuid);
        CoTaskMemFree(pStringGuid);
        pStringGuid = NULL;

        if (!IsEqualGUID(pInfo->EventGuid, GUID_NULL))
        {
            hr = StringFromCLSID(pInfo->EventGuid, &pStringGuid);
            if (FAILED(hr))
            {
                wprintf(L"StringFromCLSID(EventGuid) failed with 0x%x\n", hr);
                status = hr;
                goto cleanup;
            }

            wprintf(L"\nEvent GUID: %s\n", pStringGuid);
            CoTaskMemFree(pStringGuid);
            pStringGuid = NULL;
        }


        if (DecodingSourceXMLFile == pInfo->DecodingSource)
        {
            wprintf(L"Event ID: %hu\n", pInfo->EventDescriptor.Id);
        }

        wprintf(L"Version: %d\n", pInfo->EventDescriptor.Version);

        if (pInfo->ChannelNameOffset > 0)
        {
            wprintf(L"Channel name: %s\n", (LPWSTR)((PBYTE)(pInfo) + pInfo->ChannelNameOffset));
        }

        if (pInfo->LevelNameOffset > 0)
        {
            wprintf(L"Level name: %s\n", (LPWSTR)((PBYTE)(pInfo) + pInfo->LevelNameOffset));
        }
        else
        {
            wprintf(L"Level: %hu\n", pInfo->EventDescriptor.Level);
        }

        if (DecodingSourceXMLFile == pInfo->DecodingSource)
        {
            if (pInfo->OpcodeNameOffset > 0)
            {
                wprintf(L"Opcode name: %s\n", (LPWSTR)((PBYTE)(pInfo) + pInfo->OpcodeNameOffset));
            }
        }
        else
        {
            wprintf(L"Type: %hu\n", pInfo->EventDescriptor.Opcode);
        }

        if (DecodingSourceXMLFile == pInfo->DecodingSource)
        {
            if (pInfo->TaskNameOffset > 0)
            {
                wprintf(L"Task name: %s\n", (LPWSTR)((PBYTE)(pInfo) + pInfo->TaskNameOffset));
            }
        }
        else
        {
            wprintf(L"Task: %hu\n", pInfo->EventDescriptor.Task);
        }

        wprintf(L"Keyword mask: 0x%x\n", pInfo->EventDescriptor.Keyword);
        if (pInfo->KeywordsNameOffset)
        {
            LPWSTR pKeyword = (LPWSTR)((PBYTE)(pInfo) + pInfo->KeywordsNameOffset);

            for (; *pKeyword != 0; pKeyword += (wcslen(pKeyword) + 1))
                wprintf(L"  Keyword name: %s\n", pKeyword);
        }

        if (pInfo->EventMessageOffset > 0)
        {
            wprintf(L"Event message: %s\n", (LPWSTR)((PBYTE)(pInfo) + pInfo->EventMessageOffset));
        }

        if (pInfo->ActivityIDNameOffset > 0)
        {
            wprintf(L"Activity ID name: %s\n", (LPWSTR)((PBYTE)(pInfo) + pInfo->ActivityIDNameOffset));
        }

        if (pInfo->RelatedActivityIDNameOffset > 0)
        {
            wprintf(L"Related activity ID name: %s\n", (LPWSTR)((PBYTE)(pInfo) + pInfo->RelatedActivityIDNameOffset));
        }

        wprintf(L"Number of top-level properties: %lu\n", pInfo->TopLevelPropertyCount);

        wprintf(L"Total number of properties: %lu\n", pInfo->PropertyCount);

        // Print the metadata for all the top-level properties. Metadata for all the 
        // top-level properties come before structure member properties in the 
        // property information array.

        if (pInfo->TopLevelPropertyCount > 0)
        {
            wprintf(L"\nThe following are the user data properties defined for this event:\n");

            for (USHORT i = 0; i < pInfo->TopLevelPropertyCount; i++)
            {
                status = PrintPropertyMetadata(pInfo, i, 0);
                if (ERROR_SUCCESS != status)
                {
                    wprintf(L"Printing metadata for top-level properties failed.\n");
                    goto cleanup;
                }
            }
        }
        else
        {
            wprintf(L"\nThe event does not define any user data properties.\n");
        }

        wprintf(L"\n");
    }

cleanup:

    if (pInfo)
    {
        free(pInfo);
    }

    if (ERROR_SUCCESS != status)
    {
        CloseTrace(g_hTrace);
    }
}



DWORD GetEventInformation(PEVENT_RECORD pEvent, PTRACE_EVENT_INFO & pInfo)
{
    DWORD status = ERROR_SUCCESS;
    DWORD BufferSize = 0;

    // Retrieve the required buffer size for the event metadata.

    status = TdhGetEventInformation(pEvent, 0, NULL, pInfo, &BufferSize);

    if (ERROR_INSUFFICIENT_BUFFER == status)
    {
        pInfo = (TRACE_EVENT_INFO*) malloc(BufferSize);
        if (pInfo == NULL)
        {
            wprintf(L"Failed to allocate memory for event info (size=%lu).\n", BufferSize);
            status = ERROR_OUTOFMEMORY;
            goto cleanup;
        }

        // Retrieve the event metadata.

        status = TdhGetEventInformation(pEvent, 0, NULL, pInfo, &BufferSize);
    }

    if (ERROR_SUCCESS != status)
    {
        wprintf(L"TdhGetEventInformation failed with 0x%x.\n", status);
    }

cleanup:

    return status;
}


// Print the metadata for each property.

DWORD PrintPropertyMetadata(TRACE_EVENT_INFO* pinfo, DWORD i, USHORT indent)
{
    DWORD status = ERROR_SUCCESS;
    DWORD j = 0;
    DWORD lastMember = 0;  // Last member of a structure

    // Print property name.

    wprintf(L"%*s%s", indent, L"", (LPWSTR)((PBYTE)(pinfo) + pinfo->EventPropertyInfoArray[i].NameOffset));


    // If the property is an array, the property can define the array size or it can
    // point to another property whose value defines the array size. The PropertyParamCount
    // flag tells you where the array size is defined.

    if ((pinfo->EventPropertyInfoArray[i].Flags & PropertyParamCount) == PropertyParamCount)
    {
        j = pinfo->EventPropertyInfoArray[i].countPropertyIndex;
        wprintf(L" (array size is defined by %s)", (LPWSTR)((PBYTE)(pinfo) + pinfo->EventPropertyInfoArray[j].NameOffset));
    }
    else
    {
        if (pinfo->EventPropertyInfoArray[i].count > 1)
            wprintf(L" (array size is %lu)", pinfo->EventPropertyInfoArray[i].count);
    }


    // If the property is a buffer, the property can define the buffer size or it can
    // point to another property whose value defines the buffer size. The PropertyParamLength
    // flag tells you where the buffer size is defined.

    if ((pinfo->EventPropertyInfoArray[i].Flags & PropertyParamLength) == PropertyParamLength)
    {
        j = pinfo->EventPropertyInfoArray[i].lengthPropertyIndex;
        wprintf(L" (size is defined by %s)", (LPWSTR)((PBYTE)(pinfo) + pinfo->EventPropertyInfoArray[j].NameOffset));
    }
    else
    {
        // Variable length properties such as structures and some strings do not have
        // length definitions.

        if (pinfo->EventPropertyInfoArray[i].length > 0)
            wprintf(L" (size is %lu bytes)", pinfo->EventPropertyInfoArray[i].length);
        else
            wprintf(L" (size  is unknown)");
    }

    wprintf(L"\n");


    // If the property is a structure, print the members of the structure.

    if ((pinfo->EventPropertyInfoArray[i].Flags & PropertyStruct) == PropertyStruct)
    {
        wprintf(L"%*s(The property is a structure and has the following %hu members:)\n", 4, L"",
            pinfo->EventPropertyInfoArray[i].structType.NumOfStructMembers);

        lastMember = pinfo->EventPropertyInfoArray[i].structType.StructStartIndex + 
            pinfo->EventPropertyInfoArray[i].structType.NumOfStructMembers;

        for (j = pinfo->EventPropertyInfoArray[i].structType.StructStartIndex; j < lastMember; j++)
        {
            PrintPropertyMetadata(pinfo, j, 4);
        }
    }
    else
    {
        // You can use InType to determine the data type of the member and OutType
        // to determine the output format of the data.

        if (pinfo->EventPropertyInfoArray[i].nonStructType.MapNameOffset)
        {
            // You can pass the name to the TdhGetEventMapInformation function to 
            // retrieve metadata about the value map.

            wprintf(L"%*s(Map attribute name is %s)\n", indent, L"", 
                (PWCHAR)((PBYTE)(pinfo) + pinfo->EventPropertyInfoArray[i].nonStructType.MapNameOffset));
        }
    }

    return status;
}