MOF (クラシック) イベントの書き込み
トレース セッションにイベントを書き込む前に、プロバイダーを登録する必要があります。 プロバイダーを登録すると、プロバイダーがトレース セッションにイベントを書き込む準備ができていることが ETW に通知されます。 プロセスでは、最大 1,024 個のプロバイダー GUID を登録できます。ただし、プロセスで登録するプロバイダーの数を 1 つまたは 2 つに制限する必要があります。
Windows Vista より前: プロセスで登録できるプロバイダーの数に制限はありません。
クラシック プロバイダーを登録するには、 RegisterTraceGuids 関数を 呼び出します。 この関数は、プロバイダーの GUID、イベント トレース クラス GUID を登録し、コントローラーがプロバイダーを有効または無効にしたときに ETW が呼び出すコールバックを識別します。
プロバイダーが TraceEvent 関数を呼び出してイベントをログに記録する場合、RegisterTraceGuids 関数を呼び出すときに、クラス GUID の配列を含める必要はありません (NULL にすることができます)。 配列を含める必要があるのは、プロバイダーが TraceEventInstance 関数を呼び出してイベントをログに記録する場合のみです。
Windows XP と Windows 2000: クラス GUID の配列を常に含める必要があります ( NULL にすることはできません)。
プロバイダー自体が登録され、コントローラーによって有効になった後、プロバイダーはコントローラーのトレース セッションにイベントをログに記録できます。
プロバイダーが終了する前に、 UnregisterTraceGuids 関数を呼び出して、プロバイダーの登録を ETW から削除します。 RegisterTraceGuids 関数は、UnregisterTraceGuids 関数に渡す登録ハンドルを返します。
プロバイダーがイベントをグローバル ロガー セッションのみに記録する場合、グローバル ロガー コントローラーはプロバイダーを有効または無効にしないため、プロバイダーを ETW に登録する必要はありません。 詳細については、「 グローバル ロガー セッションの構成と開始」を参照してください。
すべての クラシック プロバイダー (グローバル ロガー セッションにイベントをトレースするものを除く) は 、ControlCallback 関数を実装する必要があります。 プロバイダーは、コールバックの情報を使用して、それが有効か無効か、および書き込む必要があるイベントを決定します。
プロバイダーは、 RegisterTraceGuids 関数を呼び出して自身を登録するときに、コールバック関数の名前を指定します。 コントローラーが EnableTrace 関数を呼び出してプロバイダーを有効または無効にすると、ETW はコールバック関数を呼び出します。
ControlCallback 実装では、GetTraceLoggerHandle 関数を呼び出してセッション ハンドルを取得する必要があります。TraceEvent 関数を呼び出すときは、セッション ハンドルを使用します。 ControlCallback 実装で GetTraceEnableFlags 関数または GetTraceEnableLevel 関数を呼び出す必要があるのは、プロバイダーが有効化レベルまたは有効化フラグを使用している場合のみです。
プロバイダーはトレース イベントを 1 つのセッションにのみログに記録できますが、複数のコントローラーが 1 つのプロバイダーを有効にできないようにするものはありません。 別のコントローラーがトレース イベントをセッションにリダイレクトしないようにするには、 ControlCallback 実装にロジックを追加して、セッション ハンドルを比較し、他のコントローラーからの有効化要求を無視することができます。
イベントをログに記録するために、 クラシック プロバイダーは TraceEvent 関数を呼び出します。 イベントは 、EVENT_TRACE_HEADER 構造体と、ヘッダーに追加されるイベント固有のデータで構成されます。
ヘッダーには、次の情報が含まれている必要があります。
Size メンバーには、イベントに記録される合計バイト数 (EVENT_TRACE_HEADER構造体のサイズと、ヘッダーに追加されるイベント固有のデータを含む) が含まれている必要があります。
Guid メンバーには、イベントのクラス GUID が含まれている必要があります (または GuidPtr メンバーには、クラス GUID へのポインターが含まれている必要があります)。
Windows XP と Windows 2000: クラス GUID は、 RegisterTraceGuids 関数を使用して以前に登録されている必要があります。
Flags メンバーには、WNODE_FLAG_TRACED_GUID フラグが含まれている必要があります。 GuidPtr メンバーを使用してクラス GUID を指定する場合は、WNODE_FLAG_USE_GUID_PTR フラグも追加します。
MOF を使用してイベント データのレイアウトを公開する場合は、 Class.Type メンバーにイベントの種類を含める必要があります。
MOF を使用してイベント データのレイアウトを発行する場合は、 Class.Version メンバーにイベント バージョンが含まれている必要があります。 バージョンは、イベント データのリビジョンを区別するために使用されます。 初期バージョン番号を 0 に設定します。
プロバイダーとコンシューマーの両方を記述する場合は、 構造体を使用して、ヘッダーに追加されるイベント固有のデータを設定できます。 ただし、MOF を使用してイベント固有のデータを公開して、コンシューマーがイベントを処理できるようにする場合は、構造体を使用してイベント固有のデータをヘッダーに追加しないでください。 これは、コンパイラがバイトアラインメントのためにイベント固有のデータに余分なバイトを追加する可能性があるためです。 MOF 定義では余分なバイトが考慮されないため、コンシューマーは無効なデータを取得する可能性があります。
イベントのメモリ ブロックを割り当て、各イベント データ項目をメモリにコピーするか、 MOF_FIELD構造体の 配列を含む構造体を作成する必要があります。ほとんどのアプリケーションでは、 MOF_FIELD 構造体の配列を含む構造体が作成されます。 Header.Size に、イベントをログに記録する前に実際に設定されたMOF_FIELD構造体の実際の数が反映されていることを確認します。 たとえば、イベントに 3 つのデータ フィールドが含まれている場合は、 Header.Size を sizeof(EVENT_TRACE_HEADER) + (sizeof(MOF_FIELD) * 3) に設定します。
関連イベントのトレースについては、「 エンドツーエンド シナリオでの関連イベントの書き込み」を参照してください。
次の例は、 TraceEvent 関数を呼び出してイベントをログに記録する方法を示しています。 この例では、「 クラシック プロバイダーのイベント スキーマの発行」で定義されているイベントを参照しています。
#include <windows.h>
#include <stdio.h>
#include <wmistr.h>
#include <evntrace.h>
// GUID that identifies the category of events that the provider can log.
// The GUID is also used in the event MOF class.
// Remember to change this GUID if you copy and paste this example.
// {B49D5931-AD85-4070-B1B1-3F81F1532875}
static const GUID MyCategoryGuid =
{ 0xb49d5931, 0xad85, 0x4070, { 0xb1, 0xb1, 0x3f, 0x81, 0xf1, 0x53, 0x28, 0x75 } };
// GUID that identifies the provider that you are registering.
// The GUID is also used in the provider MOF class.
// Remember to change this GUID if you copy and paste this example.
// {7C214FB1-9CAC-4b8d-BAED-7BF48BF63BB3}
static const GUID ProviderGuid =
{ 0x7c214fb1, 0x9cac, 0x4b8d, { 0xba, 0xed, 0x7b, 0xf4, 0x8b, 0xf6, 0x3b, 0xb3 } };
// Identifies the event type within the MyCategoryGuid category
// of events to be logged. This is the same value as the EventType
// qualifier that is defined in the event type MOF class for one of
// the MyCategoryGuid category of events.
#define MY_EVENT_TYPE 1
// Event passed to TraceEvent
typedef struct _event
{
EVENT_TRACE_HEADER Header;
MOF_FIELD Data[MAX_MOF_FIELDS]; // Event-specific data
} MY_EVENT, *PMY_EVENT;
#define MAX_INDICES 3
#define MAX_SIGNATURE_LEN 32
#define EVENT_DATA_FIELDS_CNT 6
// Application data to be traced for Version 1 of the MOF class.
typedef struct _evtdata
{
LONG Cost;
DWORD Indices[MAX_INDICES];
WCHAR Signature[MAX_SIGNATURE_LEN];
BOOL IsComplete;
GUID ID;
DWORD Size;
}EVENT_DATA, *PEVENT_DATA;
// GUID used as the value for EVENT_DATA.ID.
// {25BAEDA9-C81A-4889-8764-184FE56750F2}
static const GUID tempID =
{ 0x25baeda9, 0xc81a, 0x4889, { 0x87, 0x64, 0x18, 0x4f, 0xe5, 0x67, 0x50, 0xf2 } };
// Global variables to store tracing state information.
TRACEHANDLE g_SessionHandle = 0; // The handle to the session that enabled the provider.
ULONG g_EnableFlags = 0; // Determines which class of events to log.
UCHAR g_EnableLevel = 0; // Determines the severity of events to log.
BOOL g_TraceOn = FALSE; // Used by the provider to determine whether it should log events.
ULONG WINAPI ControlCallback(WMIDPREQUESTCODE RequestCode, PVOID Context, ULONG* Reserved, PVOID Header);
// For this example to log the event, run the session example
// to enable the provider before running this example.
void wmain(void)
{
ULONG status = ERROR_SUCCESS;
EVENT_DATA EventData;
MY_EVENT MyEvent;
TRACEHANDLE RegistrationHandle = 0;
TRACE_GUID_REGISTRATION EventClassGuids[] = {
(LPGUID)&MyCategoryGuid, NULL
};
// Register the provider and specify the control callback function
// that receives the enable/disable notifications.
status = RegisterTraceGuids(
(WMIDPREQUEST)ControlCallback,
NULL,
(LPGUID)&ProviderGuid,
sizeof(EventClassGuids)/sizeof(TRACE_GUID_REGISTRATION),
EventClassGuids,
NULL,
NULL,
&RegistrationHandle
);
if (ERROR_SUCCESS != status)
{
wprintf(L"RegisterTraceGuids failed with %lu\n", status);
goto cleanup;
}
// Set the event-specific data.
EventData.Cost = 32;
EventData.ID = tempID;
EventData.Indices[0] = 4;
EventData.Indices[1] = 5;
EventData.Indices[2] = 6;
EventData.IsComplete = TRUE;
wcscpy_s(EventData.Signature, MAX_SIGNATURE_LEN, L"Signature");
EventData.Size = 1024;
// Log the event if the provider is enabled and the session
// passed a severity level value >= TRACE_LEVEL_ERROR (or zero).
// If your provider generates more than one class of events, you
// would also need to check g_EnableFlags.
if (g_TraceOn && (0 == g_EnableLevel || TRACE_LEVEL_ERROR <= g_EnableLevel))
{
// Initialize the event data structure.
ZeroMemory(&MyEvent, sizeof(MY_EVENT));
MyEvent.Header.Size = sizeof(EVENT_TRACE_HEADER) + (sizeof(MOF_FIELD) * EVENT_DATA_FIELDS_CNT);
MyEvent.Header.Flags = WNODE_FLAG_TRACED_GUID | WNODE_FLAG_USE_MOF_PTR;
MyEvent.Header.Guid = MyCategoryGuid;
MyEvent.Header.Class.Type = MY_EVENT_TYPE;
MyEvent.Header.Class.Version = 1;
MyEvent.Header.Class.Level = g_EnableLevel;
// Load the event data. You can also use the DEFINE_TRACE_MOF_FIELD
// macro defined in evntrace.h to set the MOF_FIELD members. For example,
// DEFINE_TRACE_MOF_FIELD(&EventData.Data[0], &EventData.Cost, sizeof(EventData.Cost), 0);
MyEvent.Data[0].DataPtr = (ULONG64) &(EventData.Cost);
MyEvent.Data[0].Length = sizeof(EventData.Cost);
MyEvent.Data[1].DataPtr = (ULONG64) &(EventData.Indices);
MyEvent.Data[1].Length = sizeof(EventData.Indices);
MyEvent.Data[2].DataPtr = (ULONG64) &(EventData.Signature);
MyEvent.Data[2].Length = (ULONG)(wcslen(EventData.Signature) + 1) * sizeof(WCHAR);
MyEvent.Data[3].DataPtr = (ULONG64) &(EventData.IsComplete);
MyEvent.Data[3].Length = sizeof(EventData.IsComplete);
MyEvent.Data[4].DataPtr = (ULONG64) &(EventData.ID);
MyEvent.Data[4].Length = sizeof(EventData.ID);
MyEvent.Data[5].DataPtr = (ULONG64) &(EventData.Size);
MyEvent.Data[5].Length = sizeof(EventData.Size);
// Write the event.
status = TraceEvent(g_SessionHandle, &(MyEvent.Header));
if (ERROR_SUCCESS != status)
{
// Decide how you want to handle failures. Typically, you do not
// want to terminate the application because you failed to
// log an event. If the error is a memory failure, you may
// may want to log a message to the system event log or turn
// off logging.
wprintf(L"TraceEvent() event failed with %lu\n", status);
g_TraceOn = FALSE;
}
}
cleanup:
if (RegistrationHandle)
{
UnregisterTraceGuids(RegistrationHandle);
}
}
// The callback function that receives enable/disable notifications
// from one or more ETW sessions. Because more than one session
// can enable the provider, this example ignores requests from other
// sessions if it is already enabled.
ULONG WINAPI ControlCallback(
WMIDPREQUESTCODE RequestCode,
PVOID Context,
ULONG* Reserved,
PVOID Header
)
{
UNREFERENCED_PARAMETER(Context);
UNREFERENCED_PARAMETER(Reserved);
ULONG status = ERROR_SUCCESS;
TRACEHANDLE TempSessionHandle = 0;
switch (RequestCode)
{
case WMI_ENABLE_EVENTS: // Enable the provider.
{
SetLastError(0);
// If the provider is already enabled to a provider, ignore
// the request. Get the session handle of the enabling session.
// You need the session handle to call the TraceEvent function.
// The session could be enabling the provider or it could be
// updating the level and enable flags.
TempSessionHandle = GetTraceLoggerHandle(Header);
if (INVALID_HANDLE_VALUE == (HANDLE)TempSessionHandle)
{
wprintf(L"GetTraceLoggerHandle failed. Error code is %lu.\n", status = GetLastError());
break;
}
if (0 == g_SessionHandle)
{
g_SessionHandle = TempSessionHandle;
}
else if (g_SessionHandle != TempSessionHandle)
{
break;
}
// Get the severity level of the events that the
// session wants you to log.
g_EnableLevel = GetTraceEnableLevel(g_SessionHandle);
if (0 == g_EnableLevel)
{
// If zero, determine whether the session passed zero
// or an error occurred.
if (ERROR_SUCCESS == (status = GetLastError()))
{
// Decide what a zero enable level means to your provider.
// For this example, it means log all events.
;
}
else
{
wprintf(L"GetTraceEnableLevel failed with, %lu.\n", status);
break;
}
}
// Get the enable flags that indicate the events that the
// session wants you to log. The provider determines the
// flags values. How it articulates the flag values and
// meanings to perspective sessions is up to it.
g_EnableFlags = GetTraceEnableFlags(g_SessionHandle);
if (0 == g_EnableFlags)
{
// If zero, determine whether the session passed zero
// or an error occurred.
if (ERROR_SUCCESS == (status = GetLastError()))
{
// Decide what a zero enable flags value means to your provider.
;
}
else
{
wprintf(L"GetTraceEnableFlags failed with, %lu.\n", status);
break;
}
}
g_TraceOn = TRUE;
break;
}
case WMI_DISABLE_EVENTS: // Disable the provider.
{
// Disable the provider only if the request is coming from the
// session that enabled the provider.
TempSessionHandle = GetTraceLoggerHandle(Header);
if (INVALID_HANDLE_VALUE == (HANDLE)TempSessionHandle)
{
wprintf(L"GetTraceLoggerHandle failed. Error code is %lu.\n", status = GetLastError());
break;
}
if (g_SessionHandle == TempSessionHandle)
{
g_TraceOn = FALSE;
g_SessionHandle = 0;
}
break;
}
default:
{
status = ERROR_INVALID_PARAMETER;
break;
}
}
return status;
}