Поделиться через


Краткое руководство по traceLogging C/C++

В следующем разделе описаны основные действия, необходимые для добавления TraceLogging в код пользовательского режима C/C++.

Предварительные требования

  • Microsoft Visual Studio 2013 или более поздняя версия.
  • Windows 10 пакет sdk требуется для написания поставщика пользовательского режима.
  • Комплект драйверов Windows (WDK) для Windows 10 требуется для написания поставщика режима ядра.

Важно!

Чтобы избежать ошибок компоновщика для неразрешенных EventRegisterфункций , EventWriteTransferили EventUnregister , свяжите с advapi32.lib при компиляции этих примеров.

Чтобы собирать и декодировать события из этих примеров, необходимо запустить трассировку с помощью такого средства, как tracelog или traceview, запустить пример, остановить трассировку с помощью такого средства, как tracelog или traceview, и декодировать трассировку с помощью средства декодирования, такого как tracefmt или traceview. Например, если поставщик был определен с помощью GUID {0205c616-cf97-5c11-9756-56a2cee02ca7}, события из этих примеров можно просмотреть с помощью журнала трассировки средств Windows SDK и tracefmt следующим образом:

  • tracelog -start MyTraceSession -f MyTraceFile.etl -guid #0205c616-cf97-5c11-9756-56a2cee02ca7
  • Запустите пример.
  • tracelog -stop MyTraceSession
  • tracefmt -o MyTraceFile.txt MyTraceFile.etl
  • notepad MyTraceFile.txt

SimpleTraceLoggingExample.h

Этот пример заголовка включает API TraceLogging, а переадресация объявляет дескриптор поставщика, который будет использоваться для регистрации событий. Любой класс, который хочет использовать TraceLogging, будет включать этот заголовок, а затем может начать ведение журнала.

#pragma once

#include <windows.h> // Definitions required by TraceLoggingProvider.h
#include <TraceLoggingProvider.h> // The C/C++ TraceLogging API

// Forward-declare the g_hMyComponentProvider variable that you will use for tracing in this component
TRACELOGGING_DECLARE_PROVIDER(g_hMyComponentProvider);

Файл заголовка содержит TraceLoggingProvider.h , который определяет API TraceLogging C/C++. Сначала необходимо включить, windows.h так как он определяет константы, используемые TraceLoggingProvider.h.

В переадресации файла заголовка объявляется дескриптор g_hMyComponentProvider поставщика, который вы будете передавать в API TraceLogging для регистрации событий. Этот дескриптор должен быть доступен для любого кода, который хочет использовать TraceLogging.

TRACELOGGING_DECLARE_PROVIDER — это макрос, который создает extern const TraceLoggingHProvider дескриптор, используя указанное имя, которое в приведенном выше примере — g_hMyComponentProvider. Вы выделяете фактическую переменную дескриптора поставщика в файле кода.

SimpleTraceLoggingExample.cpp

В следующем примере регистрируется поставщик, регистрируется событие и отмена регистрации поставщика.

#include "SimpleTraceLoggingExample.h"

// Define a handle to a TraceLogging provider
TRACELOGGING_DEFINE_PROVIDER(
    g_hMyComponentProvider,
    "SimpleTraceLoggingProvider",
    // {0205c616-cf97-5c11-9756-56a2cee02ca7}
    (0x0205c616,0xcf97,0x5c11,0x97,0x56,0x56,0xa2,0xce,0xe0,0x2c,0xa7));

void main()
{

    char sampleValue[] = "Sample value";

    // Register the provider
    TraceLoggingRegister(g_hMyComponentProvider);

    // Log an event
    TraceLoggingWrite(g_hMyComponentProvider, // handle to my provider
        "HelloWorldTestEvent",              // Event Name that should uniquely identify your event.
        TraceLoggingValue(sampleValue, "TestMessage")); // Field for your event in the form of (value, field name).

    // Stop TraceLogging and unregister the provider
    TraceLoggingUnregister(g_hMyComponentProvider);
}

Приведенный выше пример включает SimpleTraceLoggingExample.h, который содержит переменную глобального поставщика, которую код будет использовать для регистрации событий.

Макрос TRACELOGGING_DEFINE_PROVIDER выделяет хранилище и определяет переменную дескриптора поставщика. Имя переменной, указываемое для этого макроса, должно совпадать с именем, которое вы использовали в макросе TRACELOGGING_DECLARE_PROVIDER в файле заголовка.

Регистрация дескриптора поставщика

Прежде чем использовать дескриптор поставщика для регистрации событий, необходимо вызвать TraceLoggingRegister , чтобы зарегистрировать дескриптор поставщика. Обычно это делается в main() или DLLMain(), но это можно сделать в любое время, если это предшествует любой попытке записать событие в журнал. Если вы зарегистрируете событие перед регистрацией дескриптора поставщика, ошибка не возникнет, но событие не будет зарегистрировано. Следующий код из приведенного выше примера регистрирует дескриптор поставщика.

// Define the GUID to use in TraceLoggingProviderRegister
TRACELOGGING_DEFINE_PROVIDER(
    g_hMyComponentProvider,
    "SimpleTraceLoggingProvider",
    // {0205c616-cf97-5c11-9756-56a2cee02ca7}
    (0x0205c616,0xcf97,0x5c11,0x97,0x56,0x56,0xa2,0xce,0xe0,0x2c,0xa7));

void main()
{
    char sampleValue[] = "Sample value";

    // Register the provider
    TraceLoggingRegister(g_hMyComponentProvider);

Регистрация события tracelogging

После регистрации поставщика следующий код регистрирует простое событие.

    // Log an event
    TraceLoggingWrite(g_hMyComponentProvider, // handle to my provider
        "HelloWorldTestEvent",              // Event Name that should uniquely identify your event.
        TraceLoggingValue(sampleValue, "TestMessage")); // Field for your event in the form of (value, field name).

Макрос TraceLoggingWrite принимает до девяносто девяти аргументов. Имя события хранится в формате UTF-8. Не следует использовать внедренные '\0' символы в имени события или именах полей. Другие ограничения на разрешенные символы отсутствуют, хотя некоторые декодеры событий или обработчики событий могут иметь свои собственные ограничения.

Каждый аргумент, следующий за именем события, должен быть заключен в макрос-оболочку TraceLogging. Если вы используете C++, можно использовать TraceLoggingValue макрос-оболочку для автоматического определения типа аргумента. Если вы пишете на языке C или вам нужен дополнительный контроль над типом поля, необходимо использовать макросы полей для конкретного типа, такие как TraceLoggingInt32, TraceLoggingUnicodeString, TraceLoggingStringи т. д.

Помимо ведения журнала отдельных событий, вы также можете группировать события по действию с помощью макросов TraceLoggingWriteActivity или TraceLoggingWriteStart/TraceLoggingWriteSriteStop в TraceLoggingActivity.h. Действия коррелируют события и полезны для сценариев, имеющих начало и конец. Например, можно использовать действие для измерения сценария, который начинается с запуска приложения, включает время, необходимое для того, чтобы экран-заставка стал доступен, и заканчивается, когда начальный экран приложения становится видимым.

Действия фиксируют отдельные события и вкладывают другие действия, которые происходят между началом и окончанием этого действия. Действия имеют область для каждого процесса и должны передаваться из потока в поток, чтобы правильно вложить многопотоковые события.

Область дескриптора поставщика ограничивается модулем (DLL, EXE или SYS-файлом), в котором он определен. Дескриптор не должен передаваться другим библиотекам DLL. Если макрос TraceLoggingWrite вызывается в A.DLL с помощью дескриптора поставщика, определенного в B.DLL, это может привести к проблемам. Самый безопасный и эффективный способ выполнить это требование — всегда напрямую ссылаться на дескриптор глобального поставщика и никогда не передавать дескриптор поставщика в качестве параметра.

Отмена регистрации поставщика

Прежде чем выгрузить компонент, необходимо отменить регистрацию поставщика TraceLogging. Это особенно важно для библиотек DLL и драйверов. Сбой, скорее всего, если библиотека DLL или драйвер выгружаются без отмены регистрации поставщика.

Следующий код отменяет регистрацию поставщика:

// Stop TraceLogging and unregister the provider
TraceLoggingUnregister(g_hMyComponentProvider);

Совместимость

В зависимости от конфигурации traceLoggingProvider.h может быть обратно совместим (итоговая программа будет работать в Windows Vista или более поздней версии) или может быть оптимизирована для более поздних версий ОС. TraceLoggingProvider.h использует WINVER (пользовательский режим) и NTDDI_VERSION (режим ядра), чтобы определить, должна ли она быть совместима с более ранними версиями ОС или оптимизирована для более новых версий ОС.

В пользовательском режиме, если вы включили <windows.h> перед заданием WINVER, <windows.h> установите для WINVER целевую версию ОС пакета SDK по умолчанию. Если winver имеет значение 0x602 или выше, TraceLoggingProvider.h оптимизирует его поведение для Windows 8 или более поздней версии, и ваше приложение не будет работать в более ранних версиях Windows. Если вам нужно, чтобы программа запускала в Vista или Windows 7, обязательно установите для WINVER соответствующее значение, прежде чем включать <windows.h>.

Аналогичным образом, если вы включили <wdm.h> параметр перед установкой NTDDI_VERSION, <wdm.h> задается NTDDI_VERSION значение по умолчанию. Если для NTDDI_VERSION задано значение 0x06040000 или выше, TraceLoggingProvider.h оптимизирует свое поведение для Windows 10 и драйвер не будет работать в более ранних версиях Windows.

Это поведение можно контролировать, задав перед TLG_HAVE_EVENT_SET_INFORMATION включением TraceLoggingProvider.h. Дополнительные сведения о макросе см. в комментариях в TraceLoggingProvider.h заголовке TLG_HAVE_EVENT_SET_INFORMATION .

Сводка и дальнейшие действия

Сведения о том, как записывать и просматривать данные TraceLogging с помощью средств производительности Windows (WPT), см. в статье Запись и отображение событий traceLogging.

Дополнительные примеры трассировки C++ см. в разделе Примеры трассировки C/C++ .