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