Apache 2.0系のモジュールには本体に手を入れずに「モジュールのモジュール」によって機能を拡張できるものがあります。mod_log_configモジュールに独自フォーマットを追加する方法。
モジュールのモジュール
Apache 2.0のモジュールは独自にフックポイントなどを追加することで、「モジュールのモジュール」を書くことができます。Apache本体をモジュールによって拡張するように、モジュール自体を別のモジュールによって拡張することができるわけです。今回はオプション関数によって独自のフォーマットを追加できるmod_log_configモジュールに焦点を当てて、その利用方法を見てみます。mod_log_configの拡張方法
mod_log_configモジュールはLogFormatディレクティブで使用するフォーマットを追加するap_register_log_handler関数を外部のモジュールに公開しています。このおかげでmod_log_configモジュールに手を加えるのではなく、別のモジュールでap_register_log_handler関数のポインタを取得・実行することで任意のフォーマットを追加することができます。例として、HTTP Cookieをログに記録するフォーマット%Cを新たに追加するap_hook_pre_configフェーズのハンドラ関数を見てみましょう。
#include "mod_log_config.h" static int pre_config(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp) { static APR_OPTIONAL_FN_TYPE(ap_register_log_handler) *log_register; log_register = APR_RETRIEVE_OPTIONAL_FN(ap_register_log_handler); if (!log_register) return DECLINED; log_register(p, "C", log_cookie, 0); return OK; } static void register_hooks(apr_pool_t *p) { ap_hook_pre_config(pre_config, NULL, NULL, APR_HOOK_LAST); }Apache 2.0のモジュールの書き方は把握しているものとして説明は割愛します。ここでミソとなるのが mod_log_config.hをインクルードしている点と、APR_RETRIEVE_OPTIONAL_FN(ap_register_log_handler)でmod_log_configモジュールが公開している関数ap_register_log_handler関数のポインタを取得している点です。取得した関数を実行して、フォーマット%Cと、Cookieの文字列を返す関数log_cookie()を登録しています。log_cookie()関数はこんな感じです。
static const char *log_cookie(request_rec *r, char *a) { return apr_table_get(r->headers_in, "Cookie"); }単純に整形済みの文字列を返すだけの関数です。このモジュールをビルドしてApacheに組み込めばLogFormatディレクティブでフォーマット%Cが利用できるようになります。別にCookieを記録したいだけならばデフォルトの%{foo}Cとか %{Cookie}iとか使えば記録できるので、上記の例には実用的な意味は無いのですがまぁこんな感じにルールを追加できるわけです。
いちおうソースコードを転がしておきます
mod_log_newrule.c
この他にも拡張用の関数を公開している標準モジュールには
- mod_cache.c
- mod_include.c
- mod_cgi.c(mod_cgid.c)
- mod_rewrite.c
- mod_proxy.c
- mod_ssl.c
$ grep APR_OPTIONAL_FN_TYPE modules/*/*.cなどして探してみてください。また使い方というかプロトタイプは関数によって異なりますので注意。
この他にもApacheがモジュールに対してフックを提供しているように、モジュールが他のモジュールに対してフックを提供することもできます。mod_proxyなどがその典型で、フレームワークとしてのmod_proxyモジュールがあり、実際のプロトコルハンドリングを行うproxy_httpモジュールやproxy_ftpモジュール、といった感じにプロトコルごとに個別の単体のモジュールとして実装されています。開発中のApache 2.1ではmod_proxyでTomcatをマウントできるようになるのですが、これもこのmod_proxy独自のフックを使用してAJP13を処理するproxy_ajpモジュールが追加されることになるわけです。
この辺の関数の公開や独自フックの話はどのドキュメントもメロメロなので困ったもんです。関数の公開方法や、独自フックの追加・利用方法の話はまた別の機会に。