There's a note that contains the module name, return code, and hook
name when a module fails a request.  Here it is in the access log:

127.0.0.1 - x [04/Nov/2010:16:40:45 -0400] "GET /index.html HTTP/1.1"
500 528 mod_auth_basic.c/500/check_user_id
127.0.0.1 - - [04/Nov/2010:17:26:02 -0400] "GET /test HTTP/1.1" 500 15
mod_test.c/500/handler

There's a debug log message potentially written at the same time:

[Thu Nov 04 17:26:02.381117 2010] [core:debug] [pid 11684:tid
3043707760] log.c(1753): [client 127.0.0.1:54095] mod_test.c handler
-> 500

There's a note that contains the active module, if any.  Here it is
logged from mod_whatkilledus:

[Thu Nov  4 17:25:48 2010] pid 11682 mod_whatkilledus sig 11 crash
[Thu Nov  4 17:25:48 2010] pid 11682 mod_whatkilledus active
connection: 127.0.0.1:54094->127.0.0.1:8080 (conn_rec 9239e20)
[Thu Nov  4 17:25:48 2010] pid 11682 mod_whatkilledus active request
(request_rec 923fcf8):
GET /test?crash HTTP/1.1|Host:127.0.0.1%3a8080|User-Agent:Mozilla/5.0
(X11; U; Linux i686; en-US; rv%3a1.9.2.12) Gecko/20101027 Ubuntu/10.04
(lucid) 
Firefox/3.6.12|Accept:text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8|Accept-Language:en-us,en;q=0.5|Accept-Encoding:gzip,deflate|Accept-Charset:ISO-8859-1,utf-8;q=0.7,*;q=0.7|Keep-Alive:115|Connection:keep-alive|Authorization:Basic
eDp4
[Thu Nov  4 17:25:48 2010] pid 11682 mod_whatkilledus active module:
mod_test.c/handler
[Thu Nov  4 17:25:48 2010] pid 11682 mod_whatkilledus end of report

Let's say you want to do stuff like this in your patched httpd.
Accessing args of a hook, which you'd want to do to log or find a good
place to save info for reporting later or other reasons, is a pain.

args are represented inside the hook macros as ([arg1][,arg2]...)
since different hooks have different argument lists.  I don't know how
to get rid of those parens in order to pass 1 or more to a function
that has other parameters.  IOW, you can't do

my_logging_fn(hook_name, (arg1,arg2,arg3))

Since I only cared about the first arg in my demonstration, I created
a function that can grab the first arg to the hook.  It is invoked
inside the macro as

ap_hook_probe_arg1 args

which expands to

ap_hook_probe_arg1(arg1, arg2, arg3, ...)

That works ok except for hooks which have no args.  AFAIK you can't
have a variadic function with 0 args.  I think the two current hooks
with 0 args are mpm_get_name and optional_fn_retrieve.  The latter
probably deserves a server_rec ptr, but mpm_get_name doesn't.  (My
patch doesn't encounter mpm_get_name()).

Any C tricks for that?

Short of tricks, I guess manufacturing a function or macro name from
the hook name (as is done for DTrace) is the required solution, and
you end up creating a bunch of functions or macros, one set per hook.

Another issue is that the return code types are not consistent (mostly
int, but a few pointers) and I've also kludged that up by casting
everything to void *.  Again, I guess you really need to manufacture a
function or macro name from the hook and invoke that.
Index: server/config.c
===================================================================
--- server/config.c     (revision 1031028)
+++ server/config.c     (working copy)
@@ -50,6 +50,7 @@
 #include "http_vhost.h"
 #include "util_cfgtree.h"
 #include "mpm_common.h"
+#include "ap_hooks_instrument.h"
 
 #define APLOG_UNSET   (APLOG_NO_MODULE - 1)
 APLOG_USE_MODULE(core);
@@ -167,7 +168,8 @@
 AP_IMPLEMENT_HOOK_RUN_FIRST(int, quick_handler, (request_rec *r, int lookup),
                             (r, lookup), DECLINED)
 
-AP_IMPLEMENT_HOOK_VOID(optional_fn_retrieve, (void), ())
+AP_IMPLEMENT_HOOK_VOID(optional_fn_retrieve, (server_rec *main_server),
+                            (main_server))
 
 /****************************************************************
  *
Index: server/core.c
===================================================================
--- server/core.c       (revision 1031028)
+++ server/core.c       (working copy)
@@ -48,6 +48,7 @@
 #include "mod_core.h"
 #include "mod_proxy.h"
 #include "ap_listen.h"
+#include "ap_hooks_instrument.h"
 
 #include "mod_so.h" /* for ap_find_loaded_module_symbol */
 
Index: server/protocol.c
===================================================================
--- server/protocol.c   (revision 1031028)
+++ server/protocol.c   (working copy)
@@ -48,6 +48,7 @@
 #include "util_charset.h"
 #include "util_ebcdic.h"
 #include "scoreboard.h"
+#include "ap_hooks_instrument.h"
 
 #if APR_HAVE_STDARG_H
 #include <stdarg.h>
Index: server/log.c
===================================================================
--- server/log.c        (revision 1031028)
+++ server/log.c        (working copy)
@@ -53,6 +53,7 @@
 #include "http_main.h"
 #include "util_time.h"
 #include "ap_mpm.h"
+#include "ap_hooks_instrument.h"
 
 APLOG_USE_MODULE(core);
 
@@ -1711,6 +1712,56 @@
     apr_pool_cleanup_run(pl->p, pl, piped_log_cleanup);
 }
 
+void *ap_hook_probe_entry(const char *name)
+{
+    if (!strcmp(name, "fixups")
+        || !strcmp(name, "access_checker")
+        || !strcmp(name, "access_checker_ex")
+        || !strcmp(name, "check_user_id")
+        || !strcmp(name, "auth_checker")
+        || !strcmp(name, "type_checker")
+        || !strcmp(name, "map_to_storage")
+        || !strcmp(name, "translate_name")
+        || !strcmp(name, "post_read_request")
+        || !strcmp(name, "quick_handler")
+        || !strcmp(name, "handler")) {
+        return (void *)1;
+    }
+    return NULL;
+}
+
+void ap_hook_probe_invoke(void *ud, const char *name, const char *src, void 
*arg1)
+{
+    if (ud) {
+        request_rec *r = (request_rec *)arg1;
+
+        apr_table_set(r->notes, "ActiveModule",
+                      apr_psprintf(r->pool, "%s/%s", src, name));
+    }
+}
+
+void ap_hook_probe_complete(void *ud, const char *name, const char *src, void 
*rv, void *arg1)
+{
+    if (ud) {
+        int rc = (int)rv;
+        request_rec *r = (request_rec *)arg1;
+        
+        apr_table_unset(r->notes, "ActiveModule");
+        if (rc != HTTP_OK && rc != DECLINED && rc != OK) {
+            ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
+                          "%s %s -> %d",
+                          src, name, rc);
+            apr_table_set(r->notes, "RequestFailer",
+                          apr_psprintf(r->pool, "%s/%d/%s", src, rc, name));
+        }
+    }
+}
+
+const void *ap_hook_probe_arg1(const void *arg1, ...)
+{
+    return arg1;
+}
+
 AP_DECLARE(const char *) ap_parse_log_level(const char *str, int *val)
 {
     char *err = "Log level keyword must be one of emerg/alert/crit/error/warn/"
Index: server/main.c
===================================================================
--- server/main.c       (revision 1031028)
+++ server/main.c       (working copy)
@@ -736,7 +736,7 @@
         apr_pool_destroy(ptemp);
         apr_pool_lock(pconf, 1);
 
-        ap_run_optional_fn_retrieve();
+        ap_run_optional_fn_retrieve(ap_server_conf);
 
         if (ap_run_mpm(pconf, plog, ap_server_conf) != OK)
             break;
Index: server/request.c
===================================================================
--- server/request.c    (revision 1031028)
+++ server/request.c    (working copy)
@@ -45,6 +45,7 @@
 #include "util_charset.h"
 #include "util_script.h"
 #include "ap_expr.h"
+#include "ap_hooks_instrument.h"
 #include "mod_request.h"
 
 #include "mod_core.h"
Index: modules/http/http_request.c
===================================================================
--- modules/http/http_request.c (revision 1031028)
+++ modules/http/http_request.c (working copy)
@@ -42,6 +42,7 @@
 #include "util_filter.h"
 #include "util_charset.h"
 #include "scoreboard.h"
+#include "ap_hooks_instrument.h"
 
 #include "mod_core.h"
 
Index: include/http_config.h
===================================================================
--- include/http_config.h       (revision 1031028)
+++ include/http_config.h       (working copy)
@@ -1241,7 +1241,7 @@
  * This is run immediately before the server starts. Optional functions should
  * be registered during the hook registration phase.
  */
-AP_DECLARE_HOOK(void,optional_fn_retrieve,(void))
+AP_DECLARE_HOOK(void,optional_fn_retrieve,(server_rec *main_server))
 
 #ifdef __cplusplus
 }
Index: include/apr_hooks.h
===================================================================
--- include/apr_hooks.h (revision 1003487)
+++ include/apr_hooks.h (working copy)
@@ -64,7 +64,7 @@
  * @param ns The namespace prefix of the hook functions
  * @param name The name of the hook
  */
-#define APR_HOOK_PROBE_ENTRY(ud,ns,name)
+#define APR_HOOK_PROBE_ENTRY(ud,ns,name,args)
 /**
  * User-defined hook probe macro that is invoked after the hook
  * has run.
@@ -74,7 +74,7 @@
  * @param name The name of the hook
  * @param rv The return value of the hook, or 0 if the hook is void.
  */
-#define APR_HOOK_PROBE_RETURN(ud,ns,name,rv)
+#define APR_HOOK_PROBE_RETURN(ud,ns,name,rv,args)
 /**
  * User-defined hook probe macro that is invoked before calling a
  * hook function.
@@ -85,7 +85,7 @@
  * @param src The value of apr_hook_debug_current at the time the function
  * was hooked (usually the source file implementing the hook function).
  */
-#define APR_HOOK_PROBE_INVOKE(ud,ns,name,src)
+#define APR_HOOK_PROBE_INVOKE(ud,ns,name,src,args)
 /**
  * User-defined hook probe macro that is invoked after calling a
  * hook function.
@@ -97,7 +97,7 @@
  * was hooked (usually the source file implementing the hook function).
  * @param rv The return value of the hook function, or 0 if the hook is void.
  */
-#define APR_HOOK_PROBE_COMPLETE(ud,ns,name,src,rv)
+#define APR_HOOK_PROBE_COMPLETE(ud,ns,name,src,rv,args)
 #endif
 
 /** @} */
@@ -176,20 +176,20 @@
     int n; \
     APR_HOOK_INT_DCL_UD; \
 \
-    APR_HOOK_PROBE_ENTRY(ud, ns, name); \
+    APR_HOOK_PROBE_ENTRY(ud, ns, name, args_use);        \
 \
     if(_hooks.link_##name) \
         { \
         pHook=(ns##_LINK_##name##_t *)_hooks.link_##name->elts; \
         for(n=0 ; n < _hooks.link_##name->nelts ; ++n) \
             { \
-            APR_HOOK_PROBE_INVOKE(ud, ns, name, (char *)pHook[n].szName); \
+            APR_HOOK_PROBE_INVOKE(ud, ns, name, (char *)pHook[n].szName, 
args_use); \
            pHook[n].pFunc args_use; \
-            APR_HOOK_PROBE_COMPLETE(ud, ns, name, (char *)pHook[n].szName, 0); 
\
+            APR_HOOK_PROBE_COMPLETE(ud, ns, name, (char *)pHook[n].szName, 0, 
args_use); \
             } \
         } \
 \
-    APR_HOOK_PROBE_RETURN(ud, ns, name, 0); \
+    APR_HOOK_PROBE_RETURN(ud, ns, name, 0, args_use);    \
 \
     }
 
@@ -220,23 +220,23 @@
     ret rv = ok; \
     APR_HOOK_INT_DCL_UD; \
 \
-    APR_HOOK_PROBE_ENTRY(ud, ns, name); \
+    APR_HOOK_PROBE_ENTRY(ud, ns, name, args_use);        \
 \
     if(_hooks.link_##name) \
         { \
         pHook=(ns##_LINK_##name##_t *)_hooks.link_##name->elts; \
         for(n=0 ; n < _hooks.link_##name->nelts ; ++n) \
             { \
-            APR_HOOK_PROBE_INVOKE(ud, ns, name, (char *)pHook[n].szName); \
+            APR_HOOK_PROBE_INVOKE(ud, ns, name, (char *)pHook[n].szName, 
args_use); \
             rv=pHook[n].pFunc args_use; \
-            APR_HOOK_PROBE_COMPLETE(ud, ns, name, (char *)pHook[n].szName, 
rv); \
+            APR_HOOK_PROBE_COMPLETE(ud, ns, name, (char *)pHook[n].szName, rv, 
args_use); \
             if(rv != ok && rv != decline) \
                 break; \
             rv = ok; \
             } \
         } \
 \
-    APR_HOOK_PROBE_RETURN(ud, ns, name, rv); \
+    APR_HOOK_PROBE_RETURN(ud, ns, name, rv, args_use);   \
 \
     return rv; \
     }
@@ -265,23 +265,23 @@
     ret rv = decline; \
     APR_HOOK_INT_DCL_UD; \
 \
-    APR_HOOK_PROBE_ENTRY(ud, ns, name); \
+    APR_HOOK_PROBE_ENTRY(ud, ns, name, args_use);        \
 \
     if(_hooks.link_##name) \
         { \
         pHook=(ns##_LINK_##name##_t *)_hooks.link_##name->elts; \
         for(n=0 ; n < _hooks.link_##name->nelts ; ++n) \
             { \
-            APR_HOOK_PROBE_INVOKE(ud, ns, name, (char *)pHook[n].szName); \
+            APR_HOOK_PROBE_INVOKE(ud, ns, name, (char *)pHook[n].szName, 
args_use); \
             rv=pHook[n].pFunc args_use; \
-            APR_HOOK_PROBE_COMPLETE(ud, ns, name, (char *)pHook[n].szName, 
rv); \
+            APR_HOOK_PROBE_COMPLETE(ud, ns, name, (char *)pHook[n].szName, rv, 
args_use); \
 \
             if(rv != decline) \
                 break; \
             } \
         } \
 \
-    APR_HOOK_PROBE_RETURN(ud, ns, name, rv); \
+    APR_HOOK_PROBE_RETURN(ud, ns, name, rv, args_use);   \
 \
     return rv; \
     }
Index: include/ap_hooks_instrument.h
===================================================================
--- include/ap_hooks_instrument.h       (revision 0)
+++ include/ap_hooks_instrument.h       (revision 0)
@@ -0,0 +1,44 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AP_HOOKS_INSTRUMENT_H
+#define AP_HOOKS_INSTRUMENT_H
+
+#include "apr_hooks.h"
+
+#define APR_HOOK_PROBES_ENABLED
+
+#undef APR_HOOK_PROBE_ENTRY
+#undef APR_HOOK_PROBE_RETURN
+#undef APR_HOOK_PROBE_INVOKE
+#undef APR_HOOK_PROBE_COMPLETE
+
+#define APR_HOOK_PROBE_ENTRY(ud,ns,name,args) \
+    void *ud = ap_hook_probe_entry(#name)
+
+#define APR_HOOK_PROBE_INVOKE(ud,ns,name,src,args) \
+    ap_hook_probe_invoke(ud, #name, src, ap_hook_probe_arg1 args)
+
+#define APR_HOOK_PROBE_COMPLETE(ud,ns,name,src,rv,args) \
+    ap_hook_probe_complete(ud, #name, src, (void *)rv, ap_hook_probe_arg1 args)
+
+#define APR_HOOK_PROBE_RETURN(ud,ns,name,rv,args)
+
+void *ap_hook_probe_entry(const char *name);
+void ap_hook_probe_complete(void *ud, const char *name, const char *src, void 
*rv, void *arg1);
+const void *ap_hook_probe_arg1(const void *arg1, ...);
+
+#endif

Reply via email to