読者です 読者をやめる 読者になる 読者になる

プロバイダーに関する補足事項

Win32 ETW

前回の投稿に入れようと思って書いていたら脱線しすぎ&長くなり過ぎたのでカットした補足事項でございます。

XML 名前空間と QName

ご存知の方は読み飛ばしちゃってください。

今回、プロバイダー マニフェストに様々な要素を定義しました。
それぞれの要素には name 属性がありますが、いずれも my:ほげほげという形式になっています。

この my というのは XML 名前空間の接頭辞(プリフィックス)でして、マニフェストの先頭で定義しています。

サンプルでは "http://aerie.jp/schemas/etw/samples/my" としているのは名前空間 URI と言いまして、XML 名前空間の識別子です。
名前空間 URI はあくまで識別子でしかないので、この URI にアクセスしても何も得られません(URI ですが URL ではありません)。

XML 名前空間というのは、C# 等の言語の名前空間と同じで、同名の他人を区別するためのものです。
何らかの名前(C# ならばクラス名など)が同じであっても、名前空間が異なれば、それは異なる名前になります。

このように、名前空間で修飾された名前を修飾名(Qualified Name、略して QName)と言います。
ETW の構成要素の名前は、その多くが QName です。

これは、winmeta.xml のような、異なるマニフェストで定義されたものを取り込む時に、名前が衝突しないようにするためであると考えられます。
例えば、標準の「情報」レベルは win:Informational という名前ですが、my:Informatonal というのを定義したとすると、これらは(同じ Informational という名前でも、名前空間が異なるので)別ものになるわけです。

Admin チャンネルの制約

文字列テーブルと message 要素は、一番最初のプロバイダーのサンプルでチラっと出てきていました。
どうやら、Admin チャンネルに出力するイベントには、必ず message を指定しなければいけないらしいのです。
他のチャンネルに出力するイベントには、message は必須ではありません。

Admin チャンネルには(今のところ知っている限りでは)もう一つの制約があります。
それは、Admin チャンネルに出力するイベントのレベルは、あらかじめ定義されている以下のいずれかでなければならないということです。

名称 メッセージ
win:Critical 致命的 1
win:Error エラー 2
win:Warning 警告 3
win:Informatonal 情報 4

これらの値は winmeta.xml に書かれています。winmeta.xmlWindows SDK の Include ディレクトリ(プロバイダー マニフェストスキーマと同じ場所)にあります。

で、それだと自分で level 要素に message が定義できないので、今回は Operational チャンネルも用意しました。*1
なお、独自定義のレベルは 16 ~ 255 の範囲になります。

Admin チャンネルに、このような、一見不便とも思える制約があるのは、Admin チャンネルが最も一般的なユーザーの目に触れるものであるため、わかりやすくするためではないかと思います。

チャンネルの分け方

今回、安直に Admin チャンネルの名前を Admin、Operational チャンネルの名前を Operational としたのは、いい名前が思いつかなかったからWindows の標準イベント ログでもそのような名前になっているケースが多いからですが、名前は任意で、複数作ることができます(名前がユニークであれば、Admin が 2 つとか、Operational が 3 つとかあっても構いません)。

チャンネルの種類は以前にも触れたように、以下の 4 つがあります。

  • Admin
  • Operational
  • Analytic
  • Debug

これらは、一般に下へ行くほど情報が詳細になります。
また、各チャンネルは、その情報を必要とする人が異なります。

さて、一般的なロギング フレームワークの仕組みであれば(当然、ETW でも)ログ レベルという概念があります。
で、このログ レベルでも Verbose とか Debug といったものがあるのが一般的です。

これは個人的な考えですが、チャンネルとログ レベルを混同すべきではないと思います。
つまり、一般的なレベルのログは Admin に出して、詳細なレベルのログは Analytic や Debug に出して…というのは、良くないやり方だということです。
何故なら、チャンネルが分かれてしまうと、イベント ビューアーで見たときに、時系列でまとめて見ることができないからです。*2

イメージとしては、こんな感じにすべきだと思います(上から時系列だと思ってください)。

Admin Debug
詳細なログ
一般的なログ ←と同じ内容を、より詳細に表記したログ
詳細なログ
一般的なログ ←と同じ内容を、より詳細に表記したログ
詳細なログ

つまり、詳細なチャンネルにだけ出す情報というのはあっても構いませんが、一般的なチャンネルに出した情報は、必ず、(より詳細な形式で)詳細なチャンネルにも同じ情報を出すべきだと思うわけです。
こうすることで、それぞれのチャンネルを見る人は、一般ユーザーなら Admin チャンネルだけを、開発者なら Debug チャンネルだけを見れば済むようになります。

繰り返しますが、チャンネルの種別が異なるということは、その情報を必要とする人が異なるということです。

ちなみに、チャンネルとログ レベルを混同している例は、こんなイメージです。

Admin Debug
詳細なログ
一般的なログ
詳細なログ
一般的なログ
詳細なログ

これだと、Admin チャンネルと Debug チャンネルをマージしないと、完全な情報を追うことができません。

チャンネルを分けるというのは、従来の、テキスト ファイルに出力するロガーであれば、ファイルを分けることに相当するものだと考えるとよいと思います。

*1:ただ、レベルを自分で定義する必要ってほとんどない気がします

*2:コンシューマーを自作すれば見ることはできますが