ISAPI フィルタによるログの書き換え
この資料では ISAPI フィルターを使って、ログファイルのエントリを書き換える方法を説明します。
ISAPI フィルタは、IIS の初期のバージョンから利用可能です。 IIS 7.x 以降は ISAPI フィルターは 「古い」ので HTTP モジュールを使うように・・・、ということになってます。
が、実際のところ新しい HTTP モジュールはちょっと情報不足で、なかなかかゆいところに手が届かないのが実情ではないでしょうか。
その点、歴史の長い ISAPI は情報がたくさんあって、ちょっとしたことをやるにはやっぱり便利です。
・・・というか、単に私が慣れているだけかもしれませんが・・・
ま、いずれにせよ今回は IIS のログファイルの書き込み内容をカスタマイズする方法を示します。
・・・と、その前に HTTP モジュールの場合。。。
ちなみに、HTTP モジュールの話が出てきたのでついでに話しておくと、IIS の組み込みのログファイルへの書き込みではなく、 独自のログファイルに出力するのであれば、
#define _WINSOCKAPI_
#include "rhttpmod.h"
#include "myhttpmod.h"
HRESULT __stdcall RegisterModule(
DWORD dwServerVersion,
IHttpModuleRegistrationInfo * pModuleInfo,
IHttpServer * pGlobalInfo
) {
::OutputDebugString ( TEXT("RegisterModule") );
return pModuleInfo->SetRequestNotifications(
new MyHttpModuleFactory,
RQ_LOG_REQUEST,
0
);
}
と、RQ_LOG_REQUEST を登録しておき、次のように OnLogRequest を実装します。
REQUEST_NOTIFICATION_STATUS MyHttpModule::OnLogRequest( IN IHttpContext* pHttpContext, IN IHttpEventProvider* pProvider ){ return RQ_NOTIFICATION_CONTINUE; }
ところが、IIS のアクセスログ自体をカスタマイズする方法がわからなかったので、ISAPI フィルタで片付けた、というのが本音だったりします(苦笑)。 (どなたかご存知なら教えてください)
ISAPI フィルタによるログファイルの書き換え
概要
ISAPI フィルタでログファイルの書き込み挙動を変更するには、SF_NOTIFY_LOG 通知を受け取るフィルタを作成します。
SF_NOTIFY_LOG 通知は IIS がログファイルを書き込む直前に呼び出されます。またそのハンドラには、 これから書き込むログ情報を保持する HTTP_FILTER_LOG 構造体へのポインタが渡されます。このデータを書き換えることによって、 ログファイルへの書き込み内容を変更することができます。
SF_NOTIFY_LOG 通知を登録するのは以下の箇所です。
/*
Log Test ISAPI Filter
Keisuke Oyama
dadosan@keicode.com
URL: http:
*/
#include <windows.h>
#include <httpfilt.h>
#include <stdio.h>
#include "handlers.h"
///////////////////////////////////////////////////////////////////////////////
BOOL WINAPI GetFilterVersion(
PHTTP_FILTER_VERSION pVer ) {
pVer->dwFilterVersion = HTTP_FILTER_REVISION;
lstrcpy(pVer->lpszFilterDesc, "log filt");
pVer->dwFlags =
SF_NOTIFY_ORDER_DEFAULT |
SF_NOTIFY_LOG;
return TRUE;
}
///////////////////////////////////////////////////////////////////////////////
DWORD WINAPI HttpFilterProc(
PHTTP_FILTER_CONTEXT pfc,
DWORD dwNotificationType,
LPVOID pvNotification) {
switch (dwNotificationType)
{
case SF_NOTIFY_LOG:
return OnLog(pfc, (PHTTP_FILTER_LOG) pvNotification);
}
return SF_STATUS_REQ_NEXT_NOTIFICATION;
}
///////////////////////////////////////////////////////////////////////////////
BOOL WINAPI TerminateFilter( DWORD dwFlags) {
return TRUE;
}
上記によって SF_NOTIFY_LOG 通知が処理できるようになりますから、 次のようにしてログの内容を書き換えます。
ここでは、パスの部分を xxxxxx という文字にしています。
/* Log Test ISAPI Filter Handlers Keisuke Oyama dadosan@keicode.com URL: http: */ #include <windows.h> #include <httpfilt.h> #include <strsafe.h> #include "handlers.h" DWORD OnLog(PHTTP_FILTER_CONTEXT pfc, PHTTP_FILTER_LOG pLog) { ::OutputDebugStringA("===== OnLog =====\n"); // // 元のターゲットを出力する // ::OutputDebugStringA( pLog->pszTarget ); // // ターゲットバッファを差し替える // char* buf = (char*) pfc->AllocMem( pfc, LOGTARGET_MAXSIZE, NULL); StringCbCopyA( buf, LOGTARGET_MAXSIZE, "xxxxx" ); pLog->pszTarget = (CHAR*) buf; return SF_STATUS_REQ_NEXT_NOTIFICATION; }
注意点としては、メモリの割り当てをフィルターコンテキストから利用できる AllocMem を利用して行うということです。
MemAlloc で呼び出したメモリは後ほど不要になった時に IIS によって自動的に解放されます。このため、 ここで割り当てたメモリをログの書き込みに利用し、その後不要になった時に IIS に解放させることができるわけです。
その他の箇所については、サンプルコードをご覧ください。
ISAPI フィルタのビルド
上記のサンプルコードは、Windows SDK から nmake してビルドしてください。
うまく行けば logflt.dll という ISAPI フィルタ DLL が作成されるはずです。
ISAPI フィルタの組み込み
ISAPI フィルタの IIS への組み込みは IIS マネージャから簡単にできます。
ISAPI Filters を選択します。
追加 (Add...) をクリックして、適当に名前をつけて DLL を選ぶだけです。
動作確認に便利な DebugView もついでに入れておきましょう
それから ISAPI フィルタの動作確認をするためには、Debug トレースを利用するのが一番簡単だと思います。 サンプルコードの中から OutputDebugString を利用して出力している箇所は DebugView などのツールで確認できます。
DebugView をダウンロードしたら、Admin で起動して、Capture Global Win32 を有効にします。これでキャプチャできるようになります。
動作確認
上で作った ISAPI フィルタを仕掛けておき、ブラウザから HTTP 要求を送ります。
DebugView には動作していることを示すエントリが書き込まれるはずです。
また、IIS のアクセスログを見ると確かに、ログのエントリが書き換わっているはずです。
以上、ISAPI フィルタを利用して IIS のアクセスログを書き換える方法を示しました。