Apache2.4.1のmod_luaをいきなり弄ってフックできる箇所を増やしてみたよ

mod_lua、色々触ってみた所、すごい簡単にモジュールっぽい動きが実装できて、可読性も良くて便利。

しかし、個人的にモジュール実装する時に良く使うのは、アクセスログ出力時のフック箇所(ap_hook_log_transaction)である。例えば、リクエスト毎にレスポンス処理前の最終段階であるap_hook_fixupsの段階でrusage()等でリソースの計測始めて、ap_hook_log_transactionの段階で差分を算出し、動的コンテンツ実行に利用したCPU使用時間等を計測する、といった使い方ができる。また、処理始めでカウンターを上げておいて、処理終わってログ書き込む段階でカウンター下げるといった使い方にもap_hook_log_transactionでのフックは便利だったりする。細かい話、コンテンツ処理するhandlerの前後で計ってもいいんだけど、hookに関数登録した方が分かりやすい。

しかし、mod_luaはそこでフックすることができない。これは面白くない。

だったら追加してやろう。ということで実装した。以下パッチ。

--- mod_lua.c.orig      2011-12-19 03:02:21.000000000 +0900
+++ mod_lua.c   2012-03-28 13:56:08.000000000 +0900
@@ -618,6 +618,10 @@
 {
     /* ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, "LuaHookInsertFilter not yet implemented"); */
 }
+static int lua_log_transaction_harness(request_rec *r)
+{
+    return lua_request_rec_hook_harness(r, "log_transaction", APR_HOOK_MIDDLE);
+}

 static int lua_quick_harness(request_rec *r, int lookup)
 {
@@ -957,6 +961,14 @@
     return lua_ssl_is_https ? lua_ssl_is_https(c) : 0;
 }

+static const char *register_log_transaction_hook(cmd_parms *cmd, void *_cfg,
+                                               const char *file,
+                                               const char *function)
+{
+    return register_named_file_function_hook("log_transaction", cmd, _cfg, file,
+                                             function, APR_HOOK_MIDDLE);
+}
+
 /*******************************/

 command_rec lua_commands[] = {
@@ -1049,6 +1061,9 @@
     AP_INIT_RAW_ARGS("Lua_____ByteCodeHack", hack_section_handler, NULL,
                      OR_ALL,
                      "(internal) Byte code handler"),
+    AP_INIT_TAKE2("LuaLogTransaction", register_log_transaction_hook, NULL,
+                  OR_ALL,
+                  "Provide a hook for the log_transaction phase of request processing"),
     {NULL}
 };

@@ -1197,6 +1212,8 @@

     ap_hook_post_config(lua_post_config, NULL, NULL, APR_HOOK_MIDDLE);

+    ap_hook_log_transaction(lua_log_transaction_harness, NULL, NULL, APR_HOOK_MIDDLE);
+
     APR_OPTIONAL_HOOK(ap_lua, lua_open, lua_open_hook, NULL, NULL,
                       APR_HOOK_REALLY_FIRST);

やった事

好きに追加してねー、と言わんばかりの実装になっていたので、やったことをまとめておく。

  • command_recにAP_INIT_TAKE2でApacheのconf用のLuaLogTransactionを登録
  • LuaLogTransactionがconfに書かれた場合にParseする関数register_log_transaction_hookを登録
  • 実際にmod_luaがap_hook_log_transactionで呼び出すための関数lua_log_transaction_harnessを登録

register_log_transaction_hookの中のregister_named_file_function_hookは設定をApacheに登録するためのラッパー関数のようなもので、lua_log_transaction_harnessの中のlua_request_rec_hook_harnessは、LuaをCから呼び出すための組み込みラッパー関数のような役目をしているので、弄る必要はない。結構考えられて実装してある。

こういう風にやれば、フックしたい場所をすぐ追加できるんじゃないかなと思う。ApacheモジュールをCで書いたことなくても、こういうところから始めればすぐ動くので楽しくなってくるかも。

これで、以下のような設定をすると、レスポンス処理の終わった後のアクセスログを書き込む段階でフックすることができる。例えば、apache_class.luaというスクリプトのtimerファンクションを呼び出したい場合は、以下のよう新しい設定「LuaLogTransaction」を書く。

LuaLogTransaction /usr/local/apache2.4/conf/extra/lua/apache_class.lua timer

よしよし、これでレスポンス処理の前後でフックすることができるようになったから、luaでプロセス間通信とかしてやれば楽しいことができそうだ。

フックできているか確認

以下のような設定でフックできているか確認した。

  • luaの内容
function timer(r)
    hook = APACHE.new(r)
    r:debug(hook:clock())
    return apache2.DECLINED
end
  • Apacheの設定
LuaHookTranslateName /usr/local/apache2.4/conf/extra/lua/apache_class.lua timer
LuaLogTransaction /usr/local/apache2.4/conf/extra/lua/apache_class.lua timer

レスポンス生成前後で時間を表示するtimerをセットして、アクセスするCGIで10秒sleepしてみる。

  • ログ出力結果
[Wed Mar 28 15:11:07.253606 2012] [lua:debug] [pid 13417:tid 3069717392] @/usr/local/apache2.4/conf/extra/lua/apache_class.lua(78): [client himitsu:62591] Wed Mar 28 15:11:07 2012
-- 省略 --
[Wed Mar 28 15:11:17.611706 2012] [lua:debug] [pid 13417:tid 3069717392] @/usr/local/apache2.4/conf/extra/lua/apache_class.lua(78): [client himitsu:61812] Wed Mar 28 15:11:17 2012

というような感じで、きちんとlog_transactionのタイミングでフックできていることが分かる。

「Apache2.4.1のmod_luaをいきなり弄ってフックできる箇所を増やしてみたよ」への2件のフィードバック

コメントは受け付けていません。