ja ja ja ja ja ja ja ja ja en ja ja ja ja ja ja ja ja ja ja ja nb ja ja ja ja ja en ja ja en en ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja en en en ja ja en ja ja ja ja ja ja ja ja ja ja ja zh ja ja ja ja ja ja ja en ja en ja ja ja en ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja en ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja en ja ja en ja ja vi ja sv eu ja en en hu ja ja en en pl ja ja jbo hbs_lat en ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja
Visual Studioなしでmingw-w64だけでWindowsのイベントログに出力する機能を実現する方法 - 2015-09-10 - ククログ
Windows Event Log APIとWindows Logging API
Event Logging APIはWindows Server 2003、Windows XP、Windows 2000用に開発されたAPIです。
Windows Event Log APIはWindows Server 2008、Windows Vista以降用に開発されたAPIで、Event Logging APIの上位互換になっています。
クラシックプロバイダー(classic provider)
マニフェストベースのプロバイダー(manifest-based provider)
それぞれログを出力するために使うAPIも違いますし、使うツールも違います。なお、ログを出力することを「イベントを書く」と呼んでいるので、以降ではそのように書いている箇所があります。
クラシックプロバイダーでイベントを書く場合はRegisterTraceGuids()とTraceEvent()というAPIとmofcomp(Managed Object Format compilerの略。Managed Object FormatはMOFと略される。)というツールが必要です。
マニフェストベースのプロバイダーでイベントを書く場合はEventRegister()とEventWrite()というAPIとMC.exe(Event Logging APIでキレイにログを表示するために使うツールと同じ)というツールを使います。
今はVisual Studioを使わずにmingw-w64だけでログを出力したいので選択肢はEvent Logging APIしかありません。ただし、そのままではログはキレイに表示されません。この回避策については後で触れます。
(なお、Visual Studioと書いていますが、MC.exeはWindows Kits(Windows SDKのこと?)に含まれるもので、mofcompはWMI Administrative Toolsに含まれていそうなものなので、本当はVisual Studioではありません。)
Event Logging APIを使ったログ出力の実装方法
それでは、Event Logging APIを使ったログ出力の実装方法を説明します。ログをキレイに表示するための回避策については次のセクションで説明します。
Event Logging APIでログを出力するために使うAPIは次の3つです。
RegisterEventSource()
ReportEvent()
DeregisterEventSource()
RegisterEventSource()でReportEvent()を実行するときに使うハンドルを取得して、ReportEvent()でログを出力します。ログは何回出力してもかまいません。ログを出力し終わったらDeregisterEventSource()でRegisterEventSource()で取得したハンドルを解放するという流れです。
コードでいうと次のような流れです。
HANDLE event_source; event_source = RegisterEventSource(/* ... */); ReportEvent(event_source/*, ... */); ReportEvent(event_source/*, ... */); ReportEvent(event_source/*, ... */); /* ... */ ReportEvent(event_source/*, ... */); DeregisterEventSource(event_source);
このコードを動くようにするために最低限決めなければいけないことは次のことです。
イベントソース名はアプリケーション名にするとよいでしょう。Groongaの場合は"Groonga"です。
ログの種類は次から選びます。
情報(知っておくといいよ、という情報。たとえば、どのポート番号で起動した、とか。)
多くの場合は「エラー」、「情報」、「警告」から選ぶことになるでしょう。Groongaではこの3つのどれかだけを使っています。
メッセージはログに出力するメッセージです。
次のように決めたとします。
イベントソース名:「"MyApp"」
ログの種類:「エラー」
メッセージ:「"File not found"」
このときのコードは次のようになります。ReportEvent()の引数が多いですが、ほとんどの引数は0やNULLといった値を使うことができます。
#include   int main(int argc, char **argv) { const char *event_source_name = "MyApp"; HANDLE event_source; WORD type = EVENTLOG_ERROR_TYPE; WORD category = 0; DWORD event_id = 0; SID *user_sid = NULL; WORD n_strings = 1; DWORD data_size = 0; const char *strings[] = {"File not found"}; void *data = NULL; event_source = RegisterEventSource(NULL, event_source_name); ReportEvent(event_source, type, category, event_id, user_sid, n_strings, data_size, strings, data); DeregisterEventSource(event_source); return 0; }
次のようにmingw-w64でクロスコンパイルします。
% x86_64-w64-mingw32-gcc -Wall -o log.exe log.c
このlog.exeをWindowsにコピーして動かすとWindowsのイベントログに出力できます。イベント ビューアーで確認すると次のようになります。
「File not found」というメッセージの前に「ソース"MyApp"からの…」という説明が書いています。これが「キレイにログが表示されない」ということです。これの回避方法は次のセクションで説明します。
なお、WevtUtil.exeというツールを使うとコマンドラインからでも確認できます。(XMLは見やすいように整形していますが実際は1行です。)
> wevtutil.exe query-events Application /c:1 /rd:true /f:xml        0   2   0   0x80000000000000     30162   Application   gatows         File not found
オプションの説明は省略します。「wevtutil.exe /?」で確認できるのでそちらを参照してください。
ポイントは「/f:xml」です。これはXMLで出力するという意味です。デフォルトではテキストで出力するのですが、そうするとメッセージ(今は「File not found」)を確認できません。これは「キレイにログが表示されない」と関係しているのですが、それの説明も次のセクションに回します。
ここで示したコードと引数で「イベントソース名」、「ログの種類」、「メッセージ」を出力できるコードをkou/windows-event-log-loggerに置いてあるので参考にしてください。
キレイにログを表示する方法
Windowsのイベントログはログを出力する側(たとえばアプリケーション)とログを読む側(たとえばイベントビューアー)で別になっています。ログを出力する側は必要な情報を出力します。ログを読む側は出力されたログをいい感じに表示します。いい感じとは、たとえば国際化して表示するということです。英語ユーザー向けには「File "logger.exe" doesn't exist.」と表示して、日本語ユーザー向けには「『logger.exe』というファイルがありません。」と表示するというようなことです。
イベントビューアーで見たときに「ソース"MyApp"からの…」という説明がでるのは、いい感じに表示できていないということを表しています。いい感じに表示するためには追加の情報が必要です。それがメッセージファイルです。
メッセージファイルには「このイベントのメッセージはこんな風に表示する」という情報が入っています。それが見つかるとイベントビューアーは「ソース"MyApp"からの…」という説明が消えます。
そのメッセージファイルを用意するにはMC.exeというツールを使いながらその情報が入ったDLLを作成する必要があります。
ただ、それだとクロスコンパイルできないので別の方法を2つ紹介します。
他のマルチプラットフォーム対応のフリーソフトウェアが提供しているDLLを利用する。
Windows組み込みのDLLを利用する。
他のマルチプラットフォーム対応のフリーソフトウェアが提供しているDLLを利用
最初の方法は他のマルチプラットフォーム対応のフリーソフトウェアが提供しているメッセージファイルの情報が入ったDLLを利用する方法です。
Windowsのイベントログの作法に従うなら、アプリケーションはメッセージを組み立てるために必要な情報だけを出力し、メッセージファイルの方でそれを組み立ててメッセージにします。たとえば、アプリケーションからはファイル名だけを出力し、メッセージファイルには「『ここにファイル名を入れる』というファイルが見つかりませんでした。」というテンプレートを用意しておくということです。
しかし、その方法に従うと他のプラットフォームでうまくログを出力できません。他のプラットフォームではアプリケーションがメッセージを組み立てることが多いからです。そのため、マルチプラットフォーム対応のフリーソフトウェアはメッセージの内容をアプリケーション側で組み立てて、メッセージファイルには「『ここにそのままメッセージを入れる』」というテンプレートを用意し、すべてのメッセージをアプリケーション側で組み立てています。
たとえば、PostgreSQLもそのような実装になっていて、そのようなメッセージファイルの情報が入ったDLLを提供しています。
PostgreSQLが提供しているDLL(PostgreSQLのバイナリーのzipをダウンロードして展開した中にあるpgsql\lib\pgevent.dll)を利用する場合は次のようにします。管理者権限で実行しないと失敗するので注意してください。
> regsvr32 /n /i:MyApp pgsql\lib\pgevent.dll
イベントビューアーを見てください。「ソース"MyApp"からの…」という説明が消えています。
注意点は一度登録したらDLL(この場合はpgevent.dll)の場所を変えてはいけないということです。レジストリーにこのDLLのパスが書き込まれているからです。
Windows組み込みのDLLを利用
他のマルチプラットフォーム対応のフリーソフトウェアのDLLを使えば自分のアプリケーションではDLLを作成する必要はありませんでした。しかし、いちいちDLLを登録するのは面倒です。ということで別の方法です。
別の方法も方針は前述の方法と一緒で、「『ここにそのままメッセージを入れる』」というテンプレートを利用するのですが、そのテンプレートを持ってくる方法が違います。Windowsに標準で入っているたくさんのテンプレートの中の、たまたまそのようなテンプレートになっているテンプレートを使います。
この方法を使うとメッセージ以外の情報(たとえばカテゴリーとか)がおかしなことになります。ただ、メッセージだけに興味があるのでその他は気にしないと割り切るならアリでしょう。
この方法を使っているのはApacheです。Apacheはnetmsg.dllを使っています。このDLLの中のイベントID3299のメッセージのテンプレートが「『ここにそのままメッセージを入れる1』『ここにそのままメッセージを入れる2』...『ここにそのままメッセージを入れる9』」というものなのです。
興味がある人はApacheのソースのserver/mpm/winnt/nt_eventlog.cをみてください。
Visual Studioを使わずにmingw-w64だけでクロスコンパイルできるWindowsのイベントログ出力機能の実装方法について説明しました。
同じようなことをしようとして調べているフリーソフトウェア開発者の役に立つ情報になることを期待します。
なお、Groongaはこの間リリースされた5.0.7からWindowsのイベントログ出力機能が実装されています。WindowsでもGroongaを使ってみてください。
現在クリアコードではソフトウェア開発者を募集しています! フリーソフトウェア開発での開発の仕方をベースに、成果や知識を公開し共有しながら業務に携われます。
Firefoxの独自ビルドの作成方法(2015年版)
クリアコードとフリーソフトウェアとビジネス
Apache Arrow
milter manager
ククログの記事はCC BY-SA 4.0とGFDLのデュアルライセンスで自由に利用できます。
クリアコードはプログラミングが楽しいソフトウェア開発者を1名募集しています。
クリアコードは「クリアコードをいい感じにする人」を1名募集しています。
クリアコードはフリーソフトウェア開発で培った技術力を提供しています。特にMozilla製品(Mozilla FirefoxとMozilla Thunderbird)とRubyとGroonga(全文検索)に関連した開発を得意としています。