思い出した頃に更新することで定評のある ETW ブログのお時間です。
前々回までで、プロバイダー、コントローラー、コンシューマーと、ETW のコンポーネントを一通り作ってみました。
が、今までのプロバイダーは、イベントに付随するデータが何もありませんでした。
そのため、「何かが起きた」ことはわかっても、「何が起きたか」はわかりません。
それでは実用になりませんので、今回から、イベントに様々なデータを付随させて、実用的なサンプルにして行きたいと思います。
ま、今回はその準備段階のようなものですが。
例によってコードは GitHub に。
今回はプロバイダーとコンシューマーをいじっています。
コントローラーはこれまで作ったものでも logman でも構いませんが、.etl ファイルの名前には注意してください(trace3.cmd を使うとファイルを生成できます)。
メッセージとは
今回のテーマは「メッセージを表示する」です。
メッセージとは何かと言いますと、プロバイダー マニフェストであらゆる要素に定義されている message 属性のことです。
provider 要素にも、channel 要素にも、task 要素にも、opcode にも level にも event にも、様々な要素に message という属性があります。
この message 要素には、表示するメッセージをそのまま書くのではなく、(多言語対応のために)文字列テーブルへの参照を書きます。
まず、文字列テーブルを見てみましょう。
一つの言語につき一つの resources 要素を用意します。
string 要素の ID は、今回は種別.識別子のような形式にしましたが、別にこうするという決まりはありません。
続いて、これを参照するマニフェストの方ですが、
このように、$(string.文字列テーブルのID)という形式で指定します。
イベント データへのアクセス
コードは抜粋です。
TdhGetEventInformation 関数でイベント情報を取得します。
この関数を呼び出すためには、プロバイダー マニフェストが登録されている必要があります(RegisterProvider3.cmd を使ってください)。
最初に必要なバッファのサイズを取得し、バッファを確保してから再度呼び出しています。*1
イベント情報は TRACE_EVENT_INFO 構造体の形式で得られます。
この構造体には多数の、なんとかOffset という名前のメンバーがありますが、これらがそれぞれ、メッセージの場所を指し示しています。
このオフセット値は、この構造体の先頭の場所から何バイト先にメッセージがあるかということを表していますので、構造体のアドレスにオフセット値を足してやる必要があります。
構造体のイメージはこんな感じです(値は例です)。
メンバー | オフセット | 値 |
---|---|---|
ProviderGuid | +0 | {824E8551-... |
... | ||
ProviderNameOffset | 136 | |
LevelNameOffset | 168 | |
ChannelNameOffset | 176 | |
... | ||
+136 | "SampleProvider3\0" | |
+168 | "やばい\0" | |
+176 | "おぺれーしょなる\0" |
オフセット値が 0 ということは、そのメッセージは存在しないということですので、0 でないかどうかはチェックする必要があります。
ところで、Admin チャンネルの方に出している win:Informational のレベル名として「情報」という文字列が取得できません。
うーむ。レベル 0 ~ 15 はシステム規定だから決め打ちで何とかしろってことなのかなあ…。でもそれでは多言語化できないし…。どうするんだろう。
イベント ビューアーで見てみる
スクリーンショットは載せませんが、サンプルを動かしてみたら、是非、ご自分の環境でイベント ビューアーを開いてみてください。
いろいろなところが日本語化されていますよ。
次回予告
今回、マニフェストがぐっと複雑になりましたので、次回はそれに関してちょっと補足説明の回を設けます。
その次で、イベントにプロパティを付与してみます。