◆イベントログ − VC++ 2005 その1

[ ホーム ] [ 上へ ] [ イベントログ - VC++ 2005 その2 ]

・概要

イベントログとはウィンドウズシステム全体や個々のアプリケーションの重要な 情報やエラー情報を統一的に管理するシステムかと思います。今回はその仕組みとイベントログで 何ができるか書いてみたいと思います。イベントログは上記の情報をログと呼ばれるファイル (拡張子がevt)に統一的な形式で書き込んでいき、いつでも閲覧して ハードウェア・ウィンドウズシステム・アプリケーションを解析できるツールです。

ログとして記録するデータがどんな形式かというと、 スタート→ファイル名を指定して実行(R)でeventvwrを実行して現れたダイアログで、 アプリケーションログを選択して表示される各レコードの1つを右クリックして プロパティ(R)を選択して表示される下記のようなデータです。

  1. 日付・時刻
  2. イベントソース
  3. カテゴリ(分類)
  4. イベントタイプ(種類)
  5. イベントID
  6. ユーザ
  7. 説明(イベントIDに対応する内容)
  8. データ

このような情報/エラーデータなどを適切なタイミングで任意のログに書き込んでいき、 後で解析・利用するのがイベントログの機能です。

イベントログシステムが機能するための重要な要素のひとつがレジストリ にあるのでまずはそちらから解説します。

<レジストリデータ>

(イベントキー)

イベントログシステムはレジストリデータの値に設定されている イベントログに情報を書き込もうとします。具体的な位置は HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\EventLog 以下にすべての情報が収められています。このキーをイベントキーと言います。 レジストリエディタで見ると

こんな感じになっているはずです。左ペインの「Eventlog」が イベントキーで、その下にある「Application」「Security」「System」にイベントログ と呼ばれるデータを記録していく器に関する情報が収められています。

(イベントログキー)

ここに挙げられた3つのイベントログキーは デフォルトで登録されていると思いますが、例えば「Application」ログではさまざまな アプリケーションのイベントが日付順にランダムに記録されています。これがいやだという場合には 「Eventlog」キーの配下に専用のイベントログキーを作って、上記のスナップショットの 右ペインのような各エントリを設定してあげれば自分専用のログに記録できます。これが何の メリットがあるかというと、イベントログをバックアップしたいときにごった煮のApplicationログから 選んで抽出しなくても、専用のログから一発でバックアップできます。今回は、カスタムイベントログ 作成に関しては書きません。既定である「Application」ログを使って以降の説明をしていきます。

Applicationログをはじめ、各イベントログ キーには上記右ペインのような各エントリがありますが、各エントリの意味は以下のとおりです。

エントリ名 意味
CustomSD 上記レジストリエディタではありませんが、このイベントログへの アクセス制限を設定しています。Clear(0x0004)、Read(0x0001)、Write(0x0002)の1つ以上の 組合せを設定でき、例えば、Clearが設定されていなければこのイベントログを消去できません。
DisplayNameFile イベントビューワで表示されるイベントログ名が収められているファイルへのパス。
DisplayNameID DisplayNameFile内にあるイベント名のID。このIDを元にDisplayNameFile内を 検索してイベントビューワの左ペインにイベントログ名を表示します。
File イベントログ実体のパス。(拡張子はevt)
MaxSize ログファイルの最大値。64KB単位で64KB〜4096MBの範囲で設定可能。 規定値は512KB
PrimaryModule このイベントログキーの名前。
Retention 記録したイベントログがMaxサイズに達したときの 動作の設定。イベントが記録されてからこの値分だけ秒数が経過した場合上書きしていきます。 既定値は7日。0の場合はログが最大値に達するまで上書きされません (最大値に達すると古い順に消去されます)。0xFFFFFFFFの場合は上書きされません。
Sources このイベントログに記録される アプリケーション・サービス名の配列(MULTI_SZ形式)。このイベントログキー配下に登録されている サブキーの名前の配列(MULTI_SZ形式)で、この後に書くイベントソースと呼ばれています。

これらの設定はイベントビューワでも確認/設定できるので、例えば、スタート→ファイル名を 指定して実行(R)でeventvwrを起動して、アプリケーションログのプロパティをご覧になってみてください。

(イベントソースキー)

各アプリケーション・サービスなどが 最初の方で書いた内容をイベントログに書き込む際に、 イベントタイプやカテゴリ、イベントIDを指定しますが、指定できるイベントタイプやイベントIDに 対応するイベント内容はイベントログキー配下のイベントソースと呼ばれるサブキーの 各エントリで設定することになります。

実際にイベントログを書き込む際には、このイベントソース名を APIのRegisterEventSourceの引数に渡してハンドルを取得し、ReportEventを実行します。 次のレジストリエディタのスナップショットには「Application」ログに書き込まれるアプリケーション (イベントソース)が左ペインに表示され、右ペインには各アプリケーション(イベントソース) に設定されるエントリ例が表示されています。ここに設定された値に基づいてデータを上部のキーである イベントログキーのFileエントリに設定されたログに記録していくことになります。

上記の右ペインに表示されている、イベントソースの 各エントリの意味は以下のとおりです。

エントリ名 意味
CategoryCount イベントログのカテゴリ(分類)の数。CategoryMessageFileに登録されている イベントの分類数の数を設定。
CategoryMessageFile カテゴリのIDとそれに対応するカテゴリ名が収められてるファイル(DLL)へのパス。
EventMessageFile イベントIDに対応する説明が収められたファイル(DLL)へのパス
ParameterMessageFile イベントIDに対応する説明に埋め込むパラメータ文字列が収められた ファイルへのパス。後で書きますが、メッセージコンパイラでイベントIDとその説明を関連付ける際に、 説明の文字列内にパラメータを設定することができます。そのパラメータをここに設定した ファイルに収めます。
TypesSupported 記録するイベントタイプ(種類)をここの設定によって制限できる。 「情報(4)」「警告(2)」「エラー(1)」「成功の監査(8)」「失敗の監査(16)」の5種類で、 ビットマスクとして1つ以上を設定するとそのイベントタイプを記録できる。

イベントログキーはカスタムなログを作らなければデフォルトで存在していますが、 イベントソースに関するレジストリエントリは事実上、「Application」キー配下に自分で作成する ことになります。イベントソースキーを作らなくてもイベントログに記録できますが、システムは自動的に 「Application」ログを選択します。しかし、イベント内容 のうちイベントIDやそれに対応する説明、カテゴリは使用できないのでMSはイベントソースを作成する ことを推奨しています。

イベントソースでメッセージIDに対応するメッセージファイルやカテゴリIDに 対応するカテゴリメッセージファイルを指定しなければなりませんが、どんなイベントを記録し、 利用するかをユーザの好み?で自身で決めて作成することになります。通常、このファイルはDLLとして 作成しますが、次のセクションでこの点について触れます。

<メッセージコンパイラ & メッセージファイル>

イベントソースを作るにはメッセージIDに対応するメッセージファイル、 カテゴリIDに対応するカテゴリメッセージファイルをDLLとして作成しなければなりまんが、 VC++などプログラミング言語で作成する部分は実はほとんどありません。 メッセージコンパイラ(mc.exe)がコンパイルできるようなテキストファイル (メッセージファイル)を作成することが作業の中心になります。

メッセージIDとそれに対応したメッセージ内容が記載されたメッセージファイルを mc.exeでコンパイルすると、

  1. 32ビットのメッセージIDが定義されたヘッダファイル(.hファイル)
  2. メッセージIDとそれに対応付けられた説明が収められているバイナリファイル(.binファイル)
  3. binファイルをリソースに組み込むための記述がされたリソースファイル(.rcファイル)

の3つが作成されます。後は、ソリューションに加えてビルドするとメッセージIDに 対応した説明が含まれるDLLファイルが出来上がるので、レジストリのイベントソースのEventMessageFile、 CategoryMessageFileエントリに値をセットすればイベントビューワで説明が表示されるようになります。

ということでメッセージファイルを作成することに集中すればいいわけですが、 メッセージコンパイラが解釈できるような形式は次のようなテキストファイル(拡張子は.mc)です。

(メッセージファイルの形式)

;#ifndef _MSGFILE_H_
;#define _MSGFILE_H_

;//-------------ヘッダ部-----------------------
MessageIdTypedef=DWORD

SeverityNames=(Success=0x0
               Informational=0x1
               Warning=0x2
               Error=0x3
              )

FacilityNames=(System=0x0FF
               Application=0xFFF
              )

LanguageNames=(English=0x1:MSG000001)
LanguageNames=(Japanese=0x2:MSG000002)
;//
;//-----------メッセージ定義-------------------
;//
MessageId=0x1
Severity=Error
Facility=Application
SymbolicName=MSG_FILE_OPEN
Language=English
The AppFile has been Opened
.
Language=Japanese
ファイルが開かれました
.

;//
;#endif

メッセージファイルは以下のように大きく3つの部分から成り立っています。

項目 記述内容
コメント 行の先頭行がセミコロン「;」で始まるとメッセージコンパイラ (以降mcと称します)はその行をコメント行として解釈します。mcとしては何もしませんが、 mcによって出力されるC++ヘッダファイル(.h)には、この部分は出力されるので、 上図の例のようにC++のコメント行として出力するかなど 注意を払う必要があります。
メッセージ定義用ヘッダ部 メッセージ定義に使われる各設定項目に関する情報を定義します。
メッセージ定義部 メッセージIDなど、ヘッダ部で定義した情報を元に、実際にメッセージを 定義することによって、mcがメッセージID、説明情報が含まれたバイナリファイル(.bin)を 生成できるようにします。

次にヘッダ部・メッセージ定義部に何を記述するかは次のようになります。

ヘッダ部の定義内容
設定形式 説明
MessageIdTypedef=データ型 生成される32ビットのメッセージIDのデータ型を設定します。ここに設定した データ型がC++ヘッダファイルに
    #define  ((データ型)0xnnnnnnnn)
という形で出力されることになります。
SeverityNames=(名前=) メッセージIDに含める、設定可能なエラーの度合いを定義します。 既定の設定値は上記メッセージファイル のサンプルで定義されている値です。
FacilityNames=(名前=値) メッセージIDに含める、設定可能なファシリティ(どの分野のイベント) を定義します。既定の設定値は上記メッセージファイル のサンプルで定義されている値です。
LanguageNames=(名前=値:ファイル名) メッセージIDに対応する説明文がどの言語かを設定します(複数の言語設定可)。 既定の設定値は(Language=English:MSG000001)
メッセージ部の定義内容
設定形式 説明
MessageId= 生成される32ビットのメッセージIDのデータの内、下位16ビット分の任意の メッセージIDを定義します。この項目でを設定しない場合、直前に定義した MessageID+1がメッセージIDとなります。また、MessageId=+2などとすると、直前に定置した MessageID+2が設定値となります。
Severity=シンボル名 ヘッダ部のSeverityNamesで設定した シンボル名の1つを設定します。シンボル名を指定しない場合、メッセージ定義で直前に 設定されたSeverity値が使われます。最初のデフォルト値は Severity=Successです。
Facility=シンボル名 ヘッダ部のFacilityNamesで設定した シンボル名の1つを設定します。シンボル名を指定しない場合、メッセージ定義で直前に設定された Facility値が使われます。最初のデフォルト値は Facility=Applicationです。
Language=言語名 メッセージIDに対応する説明文がどの言語かを ヘッダ部で定義した中から設定します。 言語名を設定しなかった場合は、最後に設定した言語名になり、 最初の既定値はLanguage=Englishです。
説明文 .binファイルに収められる、メッセージIDに対応した説明文を定義します。
. メッセージ定義の終了を表します。

上記のようなメッセージファイルを作成・保存後、 コマンドプロンプトを起動して、

C:\> mc.exe msgfile.mc [リターン]

を実行すると先に書いた3つのファイル が作られます。mc.exeでコンパイルする際にいろいろオプションスイッチを指定できますが、 ここでは説明しないので、必要ならmc.exe /?を実行してオプションの内容を確認してください。

生成された3つのファイルの内、 メッセージIDが定義されたC++のhファイルが後のコーディングで使用するので一番注目しなければ なりません。ここでどのように32ビットのメッセージIDが生成されるかを書いておきます。

メッセージIDの内容
ビット位置 内容
1〜16    (16ビット)
MessageIdで設定した値
17〜28   (12ビット)
Facilityで設定した値
29       (1ビット)
予約ビット。(未使用)
30       (1ビット)
0 - システムコード、 1 - ユーザーコード
31〜32   (2ビット)
Severityで設定した値

このようになっているのでmcでコンパイルしてできた hファイルとmcファイルを比べてみてください。

<イベントログでの作業>

レジストリに適切な書込みをして、メッセージファイルをコンパイル後、DLLファイルを 作成するとイベントログを使って作業ができるようになります。どんなことができるかというと

  1. イベントログの書込み
  2. イベントログの検索 & 読込み
  3. イベントログのクリア & バックアップ
  4. イベントログのモニタリング

4.以外は分かるかと思いますが、4はイベントログを監視してイベントログに 書込みがあると通知してくれるようにすることができます。次項からこれらを実際にやってみます。