winevt_c gemを開発をした話 - 2019-07-25 - ククログ

ククログ

株式会社クリアコード > ククログ > winevt_c gemを開発をした話

winevt_c gemを開発をした話

はじめに

Windows EventLogをRubyで取得するには元々win32-eventlog gemがありました。 このgemはWindows EventLogへ読み込みと書き込みができるものです。 ただし、文字コードに関してはCP_ACP(Windowsの初期コードページ)を使っていたため、日本語版WindowsではCP932(Windows-31J)の範囲内の文字列しか読み込むことができませんでした。

エンコーディングをより正確に扱うには?

Windows APIではchar *wchar *を相互に変換するAPIを提供しています。

どの関数も先ず変換先の文字列を長さを取得してから再度取得した変換先の文字列の長さを用いてchar *wchar *の変換を行います。

winevt_c gemでは、wchar *からRubyのUTF8の文字列を作成する関数を多用しました。

VALUE
wstr_to_rb_str(UINT cp, const WCHAR *wstr, int clen)
{
    VALUE vstr;
    CHAR *ptr;
    int len = WideCharToMultiByte(cp, 0, wstr, clen, nullptr, 0, nullptr, nullptr);
    ptr = ALLOCV_N(CHAR, vstr, len);
    WideCharToMultiByte(cp, 0, wstr, clen, ptr, len, nullptr, nullptr);
    VALUE str = rb_utf8_str_new_cstr(ptr);
    ALLOCV_END(vstr);

    return str;
}

この関数は任意のコードページを指定できるようにしていますが、winevt_cでは基本的にCP_UTF8(UTF8のコードページ)を指定して呼び出しています。

VALUE utf8str;
// some stuff.
utf8str = wstr_to_rb_str(CP_UTF8, <Wide Char Result>, -1);

Windows EventLogの新しいAPI

Windows Vistaより、Windows EventLogを読み取る新しいAPIが提供されています。 winevt_c gemではこのAPIを用いてRubyからWindows EventLogを読み込めるように実装しました。

EvtFormatMessageを用いたEventLogのメッセージの取得方法

EvtFormatMessageを用いると、EventLogのメッセージがWindowsの組み込みの管理ツールであるイベントビューアで取得できるメッセージと同じものが取得できます。winevt_cでは、get_message関数内でEvtFormatMessageを使用しています。このEvtFormatMessage関数の引数のFlagsEvtFormatMessageEventを指定しているところがポイントです。

winevt_cの現状

winevt_cはfluent-plugin-windows-eventlogに新しく実装したin_windows_eventlog2のWindows EventLogを取得するメソッドを中心に実装しています。そのため、現状では以下の機能は実装されていません。

  • リモートにあるWindowsの認証情報を作成し、リモートのWindowsにあるWindows EventLogを取得する

  • 指定したWindows EventLogのチャンネルからevtxファイルとしてエクスポートする

  • チャンネルのメタデータや設定をRubyから取得する関数

まとめ

fluent-plugin-windows-eventlogのin_windows_eventlog2を実装するにあたって作成したwinevt_c gemについて簡単に解説しました。この記事はFluentd meetup 2019でWindows EventLogに関するプラグイン回りの発表した話では軽くしか触れられていないwinevt_cの役割と、現状を解説する目的で執筆しました。winevt_c gem単体ではWindows EventLogはXMLで取得され、中身を見るためにはXMLのパースが現状では必要になってしまいますが、RubyでWindows EventLogを扱う方法の一つとして検討してみてください。