しばたテックブログ

PowerShellを中心に気分で書いている技術ブログです。

EventLog.WriteEvent メソッドを使ってイベントログを出力する

はじめに

C#でイベントログを出力するには通常 EventLog.WriteEntry メソッドを使うのが一般的だと思うのですが、本エントリはそうではなく EventLog.WriteEvent メソッドを使ってイベントログを出力する方法を紹介します。
仕事でとあるイベントログの監視ツールに対してイベントログを出力する必要があって、「簡単だろう」と高を括っていたら意外とはまってしまったのが今回の内容です。

作業環境はこんな感じです。

メッセージリソースDLLを作る

最初にイベントログに出力するメッセージを格納するメッセージリソースDLLを作成します。
メッセージリソースDLLは以下の手順で作成することができます。

  1. メッセージを記述したメッセージスクリプトを作成し、メッセージコンパイラ(mc.exe)でコンパイルしリソーススクリプトを作成する。
  2. 作成したリソーススクリプトを、リソースコンパイラ(rc.exe)でコンパイルしリソースファイルを作成する。
  3. リソースファイルをリンカ(link.exe)でリンクし、リソースDLLにする。

メッセージテキストファイルは以下の様な形式で記述します。
MessageId(これがイベントIDになります)を指定し、Severity(Success、Informational、Warning、Errorから選択します)を選び、言語毎のメッセージを記述します。
ここでは、 MyAppMessage.mc という名前でファイルを作成しておきます。

MessageIdTypedef=DWORD

LanguageNames=(English=0x0409:MSG0409)
LanguageNames=(Japanese=0x0411:MSG0411)

MessageId=1
Language=English
Category1
.
Language=Japanese
Category1
.
MessageId=2
Language=English
Category2
.
Language=Japanese
Category2
.

MessageId=1000
Severity=Informational
Language=English
Message %1
.
Language=Japanese
メッセージは「%1」です。
.
MessageId=1001
Severity=Warning
Language=English
Warning Message %1
.
Language=Japanese
警告メッセージは「%1」です。
.
MessageId=1002
Severity=Error
Language=English
Error Message %1
.
Language=Japanese
エラーメッセージは「%1」です。
.


メッセージテキストファイルの詳細はこちらをご覧ください http://msdn.microsoft.com/en-us/library/dd996906%28VS.85%29.aspx

メッセージテキストファイルを作成したら、メッセージコンパイラコンパイルします。

mc.exe MyAppMessage.mc

コンパイルに成功すると以下のヘッダファイルとリソーススクリプトファイルが作成されます。

  • MSG0409.bin
  • MSG0411.bin
  • MyAppMessage.h
  • MyAppMessage.rc


リソーススクリプトが出来たら、リソースコンパイラコンパイルします。

rc.exe MyAppMessage.rc

コンパイルに成功すると、以下のリソースファイルが作成されます。

  • MyAppMessage.res

最後に、リソースをリンカでリンクします。リソースのみのDLLですので /NOENTRY オプションを指定します。

link.exe /NOENTRY /MACHINE:X86 /DLL MyAppMessage.res

これで、メッセージリソースDLL MyAppMessage.dll が出来上がります。

イベントソースの作成

メッセージDLLを作成したらイベントソースを作成し、イベントログのメッセージにこのDLLを使用する登録をする必要があります。
EventLog.CreateEventSource メソッドを使って以下の様に記述するとイベントソースの作成ができます。*1

using System.Diagnostics;

EventSourceCreationData cd = new EventSourceCreationData("MyApp", "Application");
//イベントログのメッセージDLLの指定を行います
cd.MessageResourceFile = @"C:\MyApp\MyAppMessage.dll";
//カテゴリのメッセージDLLの指定を行います
cd.CategoryResourceFile = @"C:\MyApp\MyAppMessage.dll";
//カテゴリ数を指定します(今回の例では2になります)
cd.CategoryCount = 2;
//イベントソースの作成
EventLog.CreateEventSource(cd);


イベントソースの作成が成功すると、レジストリの HKLM\SYSTEM\CurrentControlSet\services\eventlog\Application\ にソース名の新しいキーが作成されます。


レジストリのキーが作成されていればイベントソースの作成は完了です。

イベントログの出力

ここまで来たらイベントログを出力する準備は完了ですので、EventLog.WriteEvent メソッドを使用して以下の様に記述することでメッセージDLLからメッセージを出力することが出来ます。

//カテゴリ指定なし、情報
EventLog.WriteEvent("MyApp",
                    new EventInstance(0x400003E8L, //EventId:1000
                                      0,           //カテゴリ未指定
                                      EventLogEntryType.Information),
                    "情報");
//カテゴリ1、警告
EventLog.WriteEvent("MyApp",
                    new EventInstance(0x800003E9L, //EventId:1001
                                      1,           //カテゴリ1
                                      EventLogEntryType.Warning),
                    "警告");
//カテゴリ2、エラー
EventLog.WriteEvent("MyApp",
                    new EventInstance(0xC00003EAL, //EventId:1002
                                      2,           //カテゴリ2
                                      EventLogEntryType.Error),
                    "エラー");

WriteEventメソッドの第一引数にはイベントソース名を指定します。
第二引数には EventInstanceクラスのインスタンスを指定するのですが、これがちょっと曲者で、コンストラクタの第一引数はInstanceIDとなっているのですが、ここにはリソーススクリプトを作成した時に出来た MyAppMessage.h に記述されているMessageIdを指定する必要あります。第二引数のCategoryIdも同様にMyAppMessage.hのMessageIdを指定します。第三引数にはEventLogEntryTypeを指定します。メッセージDLLのSeverityと違う区分にした場合はこの引数の値が優先される様です。*2
WriteEventの最後の引数にはメッセージパラメータを指定します。

イベントビューアで確認するとこんな感じで出力されます。



*1:イベントソースを作成するには管理者権限が必要です

*2:じゃあSeverityっていらなくね?って思うでんすがどうなんでしょう。