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


Краткое руководство по 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/TraceLoggingWriteStop макросы 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++ Tracelogging Examples для дополнительных примеров трассировки C++.