鷲ノ巣

C# とか PowerShell とか。当ブログの記事は(特に公開直後は)頻繁に改定される場合があることをご了承ください。

コンシューマーを作る

サボっていて申し訳ないです。
今回はコンシューマーを作ります。
コードは例によって GitHub に。

だいたいの流れ


  1. EVENT_TRACE_LOGFILE 構造体を初期化
  2. OpenTrace 関数でセッションを開く
  3. ProcessTrace 関数でイベントの処理を開始
  4. CloseTrace 関数でセッションを閉じる

EVENT_TRACE_LOGFILE 構造体の ProcessTraceMode メンバーには PROCESS_TRACE_MODE_EVENT_RECORD を指定します。
これは Windows Vista 以降の新しい方式(Manifest-based)を使うという意味です。
このフラグを含めないと、古い方式を使うことになります。

EventRecordCallback メンバーに指定したコールバック関数にイベント情報が渡されます。
プロバイダーが発行したイベント1つにつき、1回のコールバック関数が実行されます。
ProcessTrace 関数を呼ぶと、すべてのイベントの処理が終わるまで、呼び出し元には帰ってきません。

LogFileName には、コントローラーを作る時に指定した EVENT_TRACE_PROPERTIES 構造体の後ろの方にくっつけた(LogFileNameOffset でその位置を指し示した)ファイル名を指定します。
このサンプルでは、カレント ディレクトリに Controller1.etl ファイルがあることを前提にしていますので、実行する際はパスに注意してください。

訂正

当初、サンプルでは LogFileName と LoggerName を両方指定していましたが、これらは排他的でした。
本サンプルでは LogFileName のみ指定するように訂正しました。

肝心なのはコールバック

コードは一部抜粋しています。

コールバック関数には EVENT_RECORD 構造体が渡されます。
サンプルでは、このうち EVENT_HEADER 構造体に含まれるデータのみを表示しています。
さらにその中にある EVENT_DESCRIPTOR 構造体 が、マニフェストevent 要素で指定した属性を含みます。

EVENT_HEADER 構造体の TimeStamp メンバーは、イベントの発生時刻を FILETIME 構造体と同じ形式で含んでいます。
UTC なのでローカル時刻に直した後、わかりやすいように SYSTEMTIME 構造体に変換しています。
SYSTEMTIME 構造体はミリ秒単位までしか持たない一方、FILETIME 構造体は 100 ナノ秒単位で表されていますので、マイクロ秒以下の部分は自分で計算しています。

EVENT_RECORD はイベントのすべてのデータを含みますが、このうち、EventHeader(と、ExtendedData)に含まれる部分が、マニフェストの登録なしで取得できる、イベントの共通的なメタデータ(イベント ログで言うと System 要素にあたる部分)です。
言い換えれば、EVENT_RECORD 構造体の UserData メンバーは、マニフェストがないと内部を解析することができません。

そのあたりは後程やります。

次回予告

ここまでは、トレース データを一旦ファイルに溜めて、セッション終了後にコンシューマーがファイルから読み取るという方式を解説してきました。
次回は、ファイルを介さない、リアルタイムモードについて説明します。