hgomez 2002/10/28 06:38:07
Modified: jk/native/apache-2.0 mod_jk.c
Log:
Add JkRequestLogFormat in Apache 2.0.
May be Glenn should take a look if I didn't introduce problems here...
Revision Changes Path
1.58 +408 -1 jakarta-tomcat-connectors/jk/native/apache-2.0/mod_jk.c
Index: mod_jk.c
===================================================================
RCS file: /home/cvs/jakarta-tomcat-connectors/jk/native/apache-2.0/mod_jk.c,v
retrieving revision 1.57
retrieving revision 1.58
diff -u -r1.57 -r1.58
--- mod_jk.c 18 Oct 2002 10:23:15 -0000 1.57
+++ mod_jk.c 28 Oct 2002 14:38:07 -0000 1.58
@@ -111,6 +111,7 @@
#define JK_WORKER_ID ("jakarta.worker")
#define JK_HANDLER ("jakarta-servlet")
+#define JK_DURATION ("jakarta.worker.duration")
#define JK_MAGIC_TYPE ("application/x-jakarta-servlet")
#define NULL_FOR_EMPTY(x) ((x && !strlen(x)) ? NULL : x)
@@ -151,6 +152,13 @@
int was_initialized;
/*
+ * Request Logging
+ */
+
+ char *format_string;
+ apr_array_header_t *format;
+
+ /*
* SSL Support
*/
int ssl_enable;
@@ -877,6 +885,378 @@
return NULL;
}
+/*****************************************************************
+ *
+ * Actually logging.
+ */
+
+typedef const char *(*item_key_func) (request_rec *, char *);
+
+typedef struct {
+ item_key_func func;
+ char *arg;
+} request_log_format_item;
+
+static const char *process_item(request_rec *r,
+ request_log_format_item *item)
+{
+ const char *cp;
+
+ cp = (*item->func) (r,item->arg);
+ return cp ? cp : "-";
+}
+
+static int request_log_transaction(request_rec *r,
+ jk_server_conf_t *conf)
+{
+ request_log_format_item *items;
+ char *str, *s;
+ int i;
+ int len = 0;
+ const char **strs;
+ int *strl;
+ apr_array_header_t *format = conf->format;
+
+ strs = ap_palloc(r->pool, sizeof(char *) * (format->nelts));
+ strl = ap_palloc(r->pool, sizeof(int) * (format->nelts));
+ items = (request_log_format_item *) format->elts;
+ for (i = 0; i < format->nelts; ++i) {
+ strs[i] = process_item(r, &items[i]);
+ }
+ for (i = 0; i < format->nelts; ++i) {
+ len += strl[i] = strlen(strs[i]);
+ }
+ str = ap_palloc(r->pool, len + 1);
+ for (i = 0, s = str; i < format->nelts; ++i) {
+ memcpy(s, strs[i], strl[i]);
+ s += strl[i];
+ }
+ *s = 0;
+
+ jk_log(conf->log ? conf->log : main_log, JK_LOG_REQUEST, str);
+}
+
+/*****************************************************************
+ *
+ * Parsing the log format string
+ */
+
+static char *format_integer(apr_pool_t *p, int i)
+{
+ return apr_psprintf(p, "%d", i);
+}
+
+static char *pfmt(apr_pool_t *p, int i)
+{
+ if (i <= 0) {
+ return "-";
+ }
+ else {
+ return format_integer(p, i);
+ }
+}
+
+static const char *constant_item(request_rec *dummy, char *stuff)
+{
+ return stuff;
+}
+
+static const char *log_worker_name(request_rec *r, char *a)
+{
+ return ap_table_get(r->notes, JK_WORKER_ID);
+}
+
+
+static const char *log_request_duration(request_rec *r, char *a)
+{
+ return ap_table_get(r->notes, JK_DURATION);
+}
+
+static const char *log_request_line(request_rec *r, char *a)
+{
+ /* NOTE: If the original request contained a password, we
+ * re-write the request line here to contain XXXXXX instead:
+ * (note the truncation before the protocol string for HTTP/0.9
requests)
+ * (note also that r->the_request contains the unmodified request)
+ */
+ return (r->parsed_uri.password) ? ap_pstrcat(r->pool, r->method, " ",
+ apr_uri_unparse(r->pool, &r->parsed_uri,
0),
+ r->assbackwards ? NULL : " ", r->protocol,
NULL)
+ : r->the_request;
+}
+
+/* These next two routines use the canonical name:port so that log
+ * parsers don't need to duplicate all the vhost parsing crud.
+ */
+static const char *log_virtual_host(request_rec *r, char *a)
+{
+ return r->server->server_hostname;
+}
+
+static const char *log_server_port(request_rec *r, char *a)
+{
+ return apr_psprintf(r->pool, "%u",
+ r->server->port ? r->server->port : ap_default_port(r));
+}
+
+/* This respects the setting of UseCanonicalName so that
+ * the dynamic mass virtual hosting trick works better.
+ */
+static const char *log_server_name(request_rec *r, char *a)
+{
+ return ap_get_server_name(r);
+}
+
+static const char *log_request_uri(request_rec *r, char *a)
+{
+ return r->uri;
+}
+static const char *log_request_method(request_rec *r, char *a)
+{
+ return r->method;
+}
+
+static const char *log_request_protocol(request_rec *r, char *a)
+{
+ return r->protocol;
+}
+static const char *log_request_query(request_rec *r, char *a)
+{
+ return (r->args != NULL) ? ap_pstrcat(r->pool, "?", r->args, NULL)
+ : "";
+}
+static const char *log_status(request_rec *r, char *a)
+{
+ return pfmt(r->pool,r->status);
+}
+
+static const char *clf_log_bytes_sent(request_rec *r, char *a)
+{
+ if (!r->sent_bodyct) {
+ return "-";
+ }
+ else {
+ return apr_off_t_toa(r->pool, r->bytes_sent);
+ }
+}
+
+static const char *log_bytes_sent(request_rec *r, char *a)
+{
+ if (!r->sent_bodyct) {
+ return "0";
+ }
+ else {
+ return apr_psprintf(r->pool, "%" APR_OFF_T_FMT, r->bytes_sent);
+ }
+}
+
+static struct log_item_list {
+ char ch;
+ item_key_func func;
+} log_item_keys[] = {
+
+ {
+ 'T', log_request_duration
+ },
+ {
+ 'r', log_request_line
+ },
+ {
+ 'U', log_request_uri
+ },
+ {
+ 's', log_status
+ },
+ {
+ 'b', clf_log_bytes_sent
+ },
+ {
+ 'B', log_bytes_sent
+ },
+ {
+ 'V', log_server_name
+ },
+ {
+ 'v', log_virtual_host
+ },
+ {
+ 'p', log_server_port
+ },
+ {
+ 'H', log_request_protocol
+ },
+ {
+ 'm', log_request_method
+ },
+ {
+ 'q', log_request_query
+ },
+ {
+ 'w', log_worker_name
+ },
+ {
+ '\0'
+ }
+};
+
+static struct log_item_list *find_log_func(char k)
+{
+ int i;
+
+ for (i = 0; log_item_keys[i].ch; ++i)
+ if (k == log_item_keys[i].ch) {
+ return &log_item_keys[i];
+ }
+
+ return NULL;
+}
+
+static char *parse_request_log_misc_string(apr_pool_t *p,
+ request_log_format_item *it,
+ const char **sa)
+{
+ const char *s;
+ char *d;
+
+ it->func = constant_item;
+
+ s = *sa;
+ while (*s && *s != '%') {
+ s++;
+ }
+ /*
+ * This might allocate a few chars extra if there's a backslash
+ * escape in the format string.
+ */
+ it->arg = ap_palloc(p, s - *sa + 1);
+
+ d = it->arg;
+ s = *sa;
+ while (*s && *s != '%') {
+ if (*s != '\\') {
+ *d++ = *s++;
+ }
+ else {
+ s++;
+ switch (*s) {
+ case '\\':
+ *d++ = '\\';
+ s++;
+ break;
+ case 'n':
+ *d++ = '\n';
+ s++;
+ break;
+ case 't':
+ *d++ = '\t';
+ s++;
+ break;
+ default:
+ /* copy verbatim */
+ *d++ = '\\';
+ /*
+ * Allow the loop to deal with this *s in the normal
+ * fashion so that it handles end of string etc.
+ * properly.
+ */
+ break;
+ }
+ }
+ }
+ *d = '\0';
+
+ *sa = s;
+ return NULL;
+}
+
+static char *parse_request_log_item(apr_pool_t *p,
+ request_log_format_item *it,
+ const char **sa)
+{
+ const char *s = *sa;
+ int i;
+ struct log_item_list *l;
+
+ if (*s != '%') {
+ return parse_request_log_misc_string(p, it, sa);
+ }
+
+ ++s;
+ it->arg = ""; /* For safety's sake... */
+
+ l = find_log_func(*s++);
+ if (!l) {
+ char dummy[2];
+
+ dummy[0] = s[-1];
+ dummy[1] = '\0';
+ return ap_pstrcat(p, "Unrecognized JkRequestLogFormat directive %",
+ dummy, NULL);
+ }
+ it->func = l->func;
+ *sa = s;
+ return NULL;
+}
+
+static apr_array_header_t *parse_request_log_string(apr_pool_t *p, const char *s,
+ const char **err)
+{
+ apr_array_header_t *a = ap_make_array(p, 15, sizeof(request_log_format_item));
+ char *res;
+
+ while (*s) {
+ if ((res = parse_request_log_item(p, (request_log_format_item *)
ap_push_array(a), &s))) {
+ *err = res;
+ return NULL;
+ }
+ }
+
+ s = "\n";
+ parse_request_log_item(p, (request_log_format_item *) ap_push_array(a), &s);
+ return a;
+}
+
+/*
+ * JkRequestLogFormat Directive Handling
+ *
+ * JkRequestLogFormat format string
+ *
+ * %b - Bytes sent, excluding HTTP headers. In CLF format
+ * %B - Bytes sent, excluding HTTP headers.
+ * %H - The request protocol
+ * %m - The request method
+ * %p - The canonical Port of the server serving the request
+ * %q - The query string (prepended with a ? if a query string exists,
+ * otherwise an empty string)
+ * %r - First line of request
+ * %s - request HTTP status code
+ * %T - Requset duration, elapsed time to handle request in seconds '.' micro
seconds
+ * %U - The URL path requested, not including any query string.
+ * %v - The canonical ServerName of the server serving the request.
+ * %V - The server name according to the UseCanonicalName setting.
+ * %w - Tomcat worker name
+ */
+
+static const char *jk_set_request_log_format(cmd_parms *cmd,
+ void *dummy,
+ char *format)
+{
+ const char *err_string = NULL;
+ server_rec *s = cmd->server;
+ jk_server_conf_t *conf =
+ (jk_server_conf_t *)ap_get_module_config(s->module_config, &jk_module);
+
+ conf->format_string = ap_pstrdup(cmd->pool,format);
+ if( format != NULL ) {
+ conf->format = parse_request_log_string(cmd->pool, format, &err_string);
+ }
+ if( conf->format == NULL )
+ return "JkRequestLogFormat format array NULL";
+
+ return err_string;
+}
+
+
/*
* JkExtractSSL Directive Handling
*
@@ -1146,6 +1526,9 @@
AP_INIT_TAKE1(
"JkLogStampFormat", jk_set_log_fmt, NULL, RSRC_CONF,
"The Jakarta Tomcat module log format, follow strftime synthax"),
+ AP_INIT_TAKE1(
+ "JkRequestLogFormat", jk_set_request_log_format, NULL, RSRC_CONF,
+ "The Jakarta mod_jk module request log format string"),
/*
* Apache has multiple SSL modules (for example apache_ssl, stronghold
@@ -1309,6 +1692,7 @@
jk_worker_t *worker = wc_get_worker_for_name(worker_name, l);
if(worker) {
+ struct timeval tv_begin,tv_end;
int rc = JK_FALSE;
apache_private_data_t private_data;
jk_ws_service_t s;
@@ -1323,6 +1707,11 @@
s.ws_private = &private_data;
s.pool = &private_data.p;
+#ifndef NO_GETTIMEOFDAY
+ if(conf->format != NULL) {
+ gettimeofday(&tv_begin, NULL);
+ }
+#endif
if(init_ws_service(&private_data, &s, conf)) {
jk_endpoint_t *end = NULL;
@@ -1373,6 +1762,24 @@
/* #endif */
}
}
+
+#ifndef NO_GETTIMEOFDAY
+ if(conf->format != NULL) {
+ char *duration = NULL;
+ char *status = NULL;
+ long micro,seconds;
+ gettimeofday(&tv_end, NULL);
+ if( tv_end.tv_usec < tv_begin.tv_usec ) {
+ tv_end.tv_usec += 1000000;
+ tv_end.tv_sec--;
+ }
+ micro = tv_end.tv_usec - tv_begin.tv_usec;
+ seconds = tv_end.tv_sec - tv_begin.tv_sec;
+ duration = apr_psprintf(r->pool,"%.1d.%.6d",seconds,micro);
+ ap_table_setn(r->notes, JK_DURATION, duration);
+ request_log_transaction(r,conf);
+ }
+#endif
jk_close_pool(&private_data.p);
--
To unsubscribe, e-mail: <mailto:tomcat-dev-unsubscribe@;jakarta.apache.org>
For additional commands, e-mail: <mailto:tomcat-dev-help@;jakarta.apache.org>