From owner-freebsd-ports@FreeBSD.ORG Mon Jun 7 08:17:53 2004 Return-Path: Delivered-To: freebsd-ports@freebsd.org Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id A557116A4CE; Mon, 7 Jun 2004 08:17:53 +0000 (GMT) Received: from dppl.com (sapas.dppl.biz [216.182.10.231]) by mx1.FreeBSD.org (Postfix) with ESMTP id CCD7D43D1F; Mon, 7 Jun 2004 08:17:52 +0000 (GMT) (envelope-from yds@CoolRat.org) Received: from pcp09548474pcs.union01.nj.comcast.net (pcp09548474pcs.union01.nj.comcast.net [68.37.173.89]) (IDENT: WhyDS, AUTH: PLAIN yds, TLS: TLSv1/SSLv3,256bits,AES256-SHA) by dppl.com with esmtp; Mon, 07 Jun 2004 04:17:26 -0400 Date: Mon, 07 Jun 2004 04:17:24 -0400 From: Yarema To: Clement Laforet Message-ID: <61670F38EE92BEC06E2BE009@volyn.coolrat.org> X-Mailer: Mulberry/3.1.4 (Linux/x86) MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="==========B6C94F11EFDA6764AC7E==========" cc: Ports FreeBSD Subject: apache2 & mod_log_config-st & mod_log_mysql X-BeenThere: freebsd-ports@freebsd.org X-Mailman-Version: 2.1.1 Precedence: list List-Id: Porting software to FreeBSD List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 07 Jun 2004 08:17:53 -0000 --==========B6C94F11EFDA6764AC7E========== Content-Type: text/plain; charset=us-ascii; format=flowed Content-Transfer-Encoding: 7bit Content-Disposition: inline Hello Clement, I have a production setup using apache+mod_ssl with mod_log_sql. (The latter leaves something to be desired.) So I was very happy to discover mod_log_mysql for apache2, both of which you maintain. While combing through the docs for mod_log_mysql at a few things struck me as somewhat incomplete. The docs list as one of the requirements to have a fixed apr_reslist.c -- which is missing from the way you implemented the mod_log_mysql -> mod_log_config-st -> apache2 ports dependencies. Then there's the whole issue of having mod_log_config-st in a separate port, itself missing the modified mod_logio.c, which returns i/o counts as numbers to mod_mod_log_config, not as strings as the original would do. So here's what I propose. How about dropping the mod_log_config-st entirely and mod_log_mysql dependency on it. And replacing the whole mess with the four additional patches to the apache2 port that I'm attaching with this email. So far as I can tell this does not break anything and does fix the two omissions mentioned above. Not to mention just being simpler IMHO. The patches were derived from the sources in except for apr_reslist.c, version 1.9 of which was downloaded from Seems like the Right Thing (TM) to me. :) What do you think? -- Yarema http://yds.CoolRat.org --==========B6C94F11EFDA6764AC7E========== Content-Type: text/plain; charset=iso-8859-1; name="patch-srclib:apr-util:misc:apr_reslist.c" Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename="patch-srclib:apr-util:misc:apr_reslist.c"; size=3583 --- srclib/apr-util/misc/apr_reslist.c.orig Fri Feb 13 04:52:43 2004 +++ srclib/apr-util/misc/apr_reslist.c Mon Mar 15 08:21:26 2004 @@ -49,6 +49,7 @@ int smax; /* soft maximum on the total number of resources */ int hmax; /* hard maximum on the total number of resources */ apr_interval_time_t ttl; /* TTL when we have too many resources */ + apr_interval_time_t timeout; /* Timeout for waiting on resource */ apr_reslist_constructor constructor; apr_reslist_destructor destructor; void *params; /* opaque data passed to constructor and destructor = calls */ @@ -118,12 +119,9 @@ res =3D apr_pcalloc(reslist->pool, sizeof(*res)); =20 rv =3D reslist->constructor(&res->opaque, reslist->params, = reslist->pool); - if (rv !=3D APR_SUCCESS) { - return rv; - } =20 *ret_res =3D res; - return APR_SUCCESS; + return rv; } =20 /** @@ -132,14 +130,7 @@ */ static apr_status_t destroy_resource(apr_reslist_t *reslist, apr_res_t = *res) { - apr_status_t rv; - - rv =3D reslist->destructor(res->opaque, reslist->params, = reslist->pool); - if (rv !=3D APR_SUCCESS) { - return rv; - } - - return APR_SUCCESS; + return reslist->destructor(res->opaque, reslist->params, = reslist->pool); } =20 static apr_status_t reslist_cleanup(void *data_) @@ -187,6 +178,7 @@ /* Create the resource */ rv =3D create_resource(reslist, &res); if (rv !=3D APR_SUCCESS) { + free_container(reslist, res); apr_thread_mutex_unlock(reslist->listlock); return rv; } @@ -313,7 +305,15 @@ * a new one, or something becomes free. */ else while (reslist->ntotal >=3D reslist->hmax && reslist->nidle <=3D 0) { - apr_thread_cond_wait(reslist->avail, reslist->listlock); + if (reslist->timeout) { + if ((rv =3D apr_thread_cond_timedwait(reslist->avail,=20 + reslist->listlock, reslist->timeout)) !=3D APR_SUCCESS) { + apr_thread_mutex_unlock(reslist->listlock); + return rv; + } + } + else + apr_thread_cond_wait(reslist->avail, reslist->listlock); } /* If we popped out of the loop, first try to see if there * are new resources available for immediate use. */ @@ -329,17 +329,13 @@ * a resource to fill the slot and use it. */ else { rv =3D create_resource(reslist, &res); - - if (rv !=3D APR_SUCCESS) { - apr_thread_mutex_unlock(reslist->listlock); - return rv; + if (rv =3D=3D APR_SUCCESS) { + reslist->ntotal++; + *resource =3D res->opaque; } - - reslist->ntotal++; - *resource =3D res->opaque; free_container(reslist, res); apr_thread_mutex_unlock(reslist->listlock); - return APR_SUCCESS; + return rv; } } =20 @@ -356,6 +352,23 @@ apr_thread_mutex_unlock(reslist->listlock); =20 return reslist_maint(reslist); +} + +APU_DECLARE(void) apr_reslist_timeout_set(apr_reslist_t *reslist, + apr_interval_time_t timeout) +{ + reslist->timeout =3D timeout; +} + +APU_DECLARE(apr_status_t) apr_reslist_invalidate(apr_reslist_t *reslist, + void *resource) +{ + apr_status_t ret; + apr_thread_mutex_lock(reslist->listlock); + ret =3D reslist->destructor(resource, reslist->params, reslist->pool); + reslist->ntotal--; + apr_thread_mutex_unlock(reslist->listlock); + return ret; } =20 #endif /* APR_HAS_THREADS */ --==========B6C94F11EFDA6764AC7E========== Content-Type: text/plain; charset=iso-8859-1; name="patch-modules:loggers:mod_log_config.c" Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename="patch-modules:loggers:mod_log_config.c"; size=61326 --- modules/loggers/mod_log_config.c.orig Wed Mar 3 06:07:50 2004 +++ modules/loggers/mod_log_config.c Fri Oct 17 04:58:07 2003 @@ -17,7 +17,12 @@ * Modified by djm@va.pubnix.com: * If no TransferLog is given explicitly, decline to log. * - * This is module implements the TransferLog directive (same as the + * Modified by st: + * Added logic to give other log writers a more detailed view of the + * data to be logged. + * Added item %R, which returns the unmodified URL (this is not %U). + * + * This module implements the TransferLog directive (same as the * common log module), and additional directives, LogFormat and CustomLog. * * @@ -27,12 +32,25 @@ * a custom format is set with LogFormat * LogFormat format Set a log format from TransferLog files * CustomLog fn format - * Log to file fn with format given by the format + * Log to fn with format given by the format * argument * * CookieLog fn For backwards compatability with old Cookie * logging module - now deprecated. * + * fn is a URL-like descriptor of the form "writer:path". The exact format + * of "path" depends on the log writer to use. + * This module implements two default log writers, "file" and "pipe". + * + * For backwards compatibility: fn may also be a simple filesystem path=20 + * without the "writer:"-part, and possibly prepended by a | to indicate + * logging into a pipe. These fn will be handled by the build-in file or + * pipe log writer. + * Furthermore, if a "writer:"-part exists in fn but no matching log = writer=20 + * was found, this module will fall back to log into a file named [fn]. In = + * other words: No error will be posted upon missing log writer, the = default + * file log writer will be used. + * * There can be any number of TransferLog and CustomLog * commands. Each request will be logged to _ALL_ the * named files, in the appropriate format. @@ -47,11 +65,11 @@ *=20 * Examples: * - * TransferLog logs/access_log + * TransferLog file:logs/access_log * * LogFormat "... custom format ..." - * TransferLog log/virtual_only - * CustomLog log/virtual_useragents "%t %{user-agent}i" + * TransferLog file:log/virtual_only + * CustomLog file:log/virtual_useragents "%t %{user-agent}i" * * * This will log using CLF to access_log any requests handled by the @@ -61,15 +79,15 @@ * * Note that the NCSA referer and user-agent logs are easily added with * CustomLog: - * CustomLog logs/referer "%{referer}i -> %U" - * CustomLog logs/agent "%{user-agent}i" + * CustomLog file:logs/referer "%{referer}i -> %U" + * CustomLog file:logs/agent "%{user-agent}i" * * RefererIgnore functionality can be obtained with conditional * logging (SetEnvIf and CustomLog ... env=3D!VAR). * * But using this method allows much easier modification of the * log format, e.g. to log hosts along with UA: - * CustomLog logs/referer "%{referer}i %U %h" + * CustomLog file:logs/referer "%{referer}i %U %h" * * The argument to LogFormat and CustomLog is a string, which can include * literal characters copied into the log files, and '%' directives as @@ -91,8 +109,8 @@ * %...{Foobar}o: The contents of Foobar: header line(s) in the reply. * %...p: the port the request was served to * %...P: the process ID of the child that serviced the request. - * %...{format}P: the process ID or thread ID of the child/thread that - * serviced the request + * %...{format}P: the process ID (pid) or thread ID (tid) of the=20 + * child/thread that serviced the request * %...r: first line of request * %...s: status. For requests that got internally redirected, this * is status of the *original* request --- %...>s for the last. @@ -103,6 +121,7 @@ * %...D: the time taken to serve the request, in micro seconds. * %...u: remote user (from auth; may be bogus if return status (%s) is = 401) * %...U: the URL path requested. + * %...R: the URL requested, unmodified * %...v: the configured name of the server (i.e. which virtual host?) * %...V: the server name according to the UseCanonicalName setting * %...m: the request method @@ -112,9 +131,9 @@ * 'X' =3D connection aborted before the response completed. * '+' =3D connection may be kept alive after the response is = sent. * '-' =3D connection will be closed after the response is sent. - (This directive was %...c in late versions of Apache 1.3, but - this conflicted with the historical ssl %...{var}c syntax.) -* + * (This directive was %...c in late versions of Apache 1.3, but + * this conflicted with the historical ssl %...{var}c syntax.) + * * The '...' can be nothing at all (e.g. "%h %u %r %s %b"), or it can * indicate conditions for inclusion of the item (which will cause it * to be replaced with '-' if the condition is not met). Note that @@ -144,7 +163,6 @@ #include "apr_lib.h" #include "apr_hash.h" #include "apr_optional.h" -#include "apr_anylock.h" =20 #define APR_WANT_STRFUNC #include "apr_want.h" @@ -157,7 +175,6 @@ #include "http_log.h" #include "http_protocol.h" #include "util_time.h" -#include "ap_mpm.h" =20 #if APR_HAVE_UNISTD_H #include @@ -173,30 +190,35 @@ =20 static int xfer_flags =3D (APR_WRITE | APR_APPEND | APR_CREATE); static apr_fileperms_t xfer_perms =3D APR_OS_DEFAULT; + +typedef struct { + union { + ap_log_handler_fn_t *func; + ap_log_ehandler_fn_t *efunc; + } handler; + int oldstyle; + int want_orig_default; +} log_handler; static apr_hash_t *log_hash; -static apr_status_t ap_default_log_writer(request_rec *r, - void *handle,=20 - const char **strs, - int *strl, - int nelts, - apr_size_t len); -static apr_status_t ap_buffered_log_writer(request_rec *r, - void *handle,=20 - const char **strs, - int *strl, - int nelts, - apr_size_t len); -static void *ap_default_log_writer_init(apr_pool_t *p, server_rec *s,=20 - const char* name); -static void *ap_buffered_log_writer_init(apr_pool_t *p, server_rec *s,=20 - const char* name); - -static void ap_log_set_writer_init(ap_log_writer_init *handle); -static void ap_log_set_writer(ap_log_writer *handle); -static ap_log_writer *log_writer =3D ap_default_log_writer; -static ap_log_writer_init *log_writer_init =3D ap_default_log_writer_init; + +typedef struct { + ap_log_ewriter_setup *setup; + ap_log_ewriter *write; + ap_log_ewriter_init *init; + ap_log_ewriter_exit *exit; +} log_ewriter; +static apr_hash_t *writer_hash; + +static void *ap_old_log_writer_init(apr_pool_t *p, server_rec *s,=20 + const char* name); +static apr_status_t ap_filepipe_log_ewriter(request_rec *r, + void *handle,=20 + apr_array_header_t *data); + +static ap_log_writer *log_writer =3D NULL; +static ap_log_writer_init *log_writer_init =3D NULL; + static int buffered_logs =3D 0; /* default unbuffered */ -static apr_array_header_t *all_buffered_logs =3D NULL; =20 /* POSIX.1 defines PIPE_BUF as the maximum number of bytes that is * guaranteed to be atomic when writing a pipe. And PIPE_BUF >=3D 512 @@ -242,23 +264,26 @@ * request. format might be NULL, in which case the default_format * from the multi_log_state should be used, or if that is NULL as * well, use the CLF.=20 - * log_writer is NULL before the log file is opened and is - * set to a opaque structure (usually a fd) after it is opened. -=20 + * writer_data is NULL before the log file is opened and is + * set to an opaque structure (usually a fd) after it is opened. */ + typedef struct { apr_file_t *handle; apr_size_t outcnt; char outbuf[LOG_BUFSIZE]; - apr_anylock_t mutex; } buffered_log; =20 typedef struct { const char *fname; const char *format_string; apr_array_header_t *format; - void *log_writer; + log_ewriter *writer; + void *writer_data; + + int condition_sense; char *condition_var; + apr_array_header_t *conditions; } config_log_state; =20 /* @@ -267,168 +292,179 @@ */ =20 typedef struct { - ap_log_handler_fn_t *func; + log_handler *handler; char *arg; int condition_sense; int want_orig; apr_array_header_t *conditions; } log_format_item; =20 -static char *format_integer(apr_pool_t *p, int i) -{ - return apr_itoa(p, i); -} - -static char *pfmt(apr_pool_t *p, int i) -{ - if (i <=3D 0) { - return "-"; - } - else { - return format_integer(p, i); - } -} - -static const char *constant_item(request_rec *dummy, char *stuff) +static void *constant_item(request_rec *r, char *stuff, = ap_log_ehandler_data *d) { - return stuff; + d->data=3Dstuff; + d->arg=3DNULL; + d->type=3DAP_LOG_EHANDLER_RETURN_CONST; } =20 -static const char *log_remote_host(request_rec *r, char *a) +static void *log_remote_host(request_rec *r, char *a, ap_log_ehandler_data = *d) { - return ap_escape_logitem(r->pool, ap_get_remote_host(r->connection, - = r->per_dir_config, - REMOTE_NAME, = NULL)); + d->data=3D(void *) ap_get_remote_host(r->connection, + r->per_dir_config, + REMOTE_NAME, NULL); + d->type=3DAP_LOG_EHANDLER_RETURN_STRING; } =20 -static const char *log_remote_address(request_rec *r, char *a) +static void *log_remote_address(request_rec *r, char *a, = ap_log_ehandler_data *d) { - return r->connection->remote_ip; + d->data=3Dr->connection->remote_ip; + d->type=3DAP_LOG_EHANDLER_RETURN_STRING; } =20 -static const char *log_local_address(request_rec *r, char *a) +static void *log_local_address(request_rec *r, char *a, = ap_log_ehandler_data *d) { - return r->connection->local_ip; + d->data=3Dr->connection->local_ip; + d->type=3DAP_LOG_EHANDLER_RETURN_STRING; } =20 -static const char *log_remote_logname(request_rec *r, char *a) +static void *log_remote_logname(request_rec *r, char *a, = ap_log_ehandler_data *d) { - return ap_escape_logitem(r->pool, ap_get_remote_logname(r)); + d->data=3D(void *) ap_get_remote_logname(r); + d->type=3DAP_LOG_EHANDLER_RETURN_STRING; } =20 -static const char *log_remote_user(request_rec *r, char *a) +static void *log_remote_user(request_rec *r, char *a, ap_log_ehandler_data = *d) { - char *rvalue =3D r->user; - - if (rvalue =3D=3D NULL) { + d->data =3D r->user; + d->type=3DAP_LOG_EHANDLER_RETURN_STRING; + =20 + /* + if (d->data =3D=3D NULL) { rvalue =3D "-"; } - else if (strlen(rvalue) =3D=3D 0) { + else if (strlen(d->data) =3D=3D 0) { rvalue =3D "\"\""; } else { rvalue =3D ap_escape_logitem(r->pool, rvalue); } - - return rvalue; + */ } =20 -static const char *log_request_line(request_rec *r, char *a) +static void *log_request_line(request_rec *r, char *a, = ap_log_ehandler_data *d) { /* 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 ap_escape_logitem(r->pool, - (r->parsed_uri.password) - ? apr_pstrcat(r->pool, r->method, " ", - apr_uri_unparse(r->pool, - = &r->parsed_uri, 0), - r->assbackwards ? NULL : " ", - r->protocol, NULL) - : r->the_request); + d->data =3D (r->parsed_uri.password) + ? apr_pstrcat(r->pool, r->method, " ", + apr_uri_unparse(r->pool, + &r->parsed_uri, 0), + r->assbackwards ? NULL : " ", + r->protocol, NULL) + : r->the_request; + d->type =3D AP_LOG_EHANDLER_RETURN_STRING; } =20 -static const char *log_request_file(request_rec *r, char *a) +static void *log_request_file(request_rec *r, char *a, = ap_log_ehandler_data *d) { - return ap_escape_logitem(r->pool, r->filename); + d->data =3D r->filename; + d->type =3D AP_LOG_EHANDLER_RETURN_STRING; } -static const char *log_request_uri(request_rec *r, char *a) + +static void *log_request_uri(request_rec *r, char *a, ap_log_ehandler_data = *d) { - return ap_escape_logitem(r->pool, r->uri); + d->data =3D r->uri; + d->type =3D AP_LOG_EHANDLER_RETURN_STRING; } -static const char *log_request_method(request_rec *r, char *a) + +static void *log_unparsed_request_uri(request_rec *r, char *a, = ap_log_ehandler_data *d) { - return ap_escape_logitem(r->pool, r->method); + d->data =3D r->unparsed_uri; + d->type =3D AP_LOG_EHANDLER_RETURN_STRING; } -static const char *log_request_protocol(request_rec *r, char *a) + +static void *log_request_method(request_rec *r, char *a, = ap_log_ehandler_data *d) { - return ap_escape_logitem(r->pool, r->protocol); + d->data =3D (void *)r->method; + d->type =3D AP_LOG_EHANDLER_RETURN_STRING; } -static const char *log_request_query(request_rec *r, char *a) +static void *log_request_protocol(request_rec *r, char *a, = ap_log_ehandler_data *d) { - return (r->args) ? apr_pstrcat(r->pool, "?", - ap_escape_logitem(r->pool, r->args), = NULL) - : ""; + d->data =3D r->protocol; + d->type =3D AP_LOG_EHANDLER_RETURN_STRING; } -static const char *log_status(request_rec *r, char *a) +static void *log_request_query(request_rec *r, char *a, = ap_log_ehandler_data *d) +{=20 + if (r->args) + d->data=3Dapr_pstrcat(r->pool, "?", r->args, NULL); + d->type=3DAP_LOG_EHANDLER_RETURN_STRING; +} +static void *log_status(request_rec *r, char *a, ap_log_ehandler_data *d) { - return pfmt(r->pool, r->status); + if (r->status > 0) { + d->data=3Dapr_palloc(r->pool,sizeof(ap_log_unumber_t)); + *((ap_log_unumber_t *) d->data)=3Dr->status; + } + d->type=3DAP_LOG_EHANDLER_RETURN_UNUMBER; } =20 -static const char *clf_log_bytes_sent(request_rec *r, char *a) +static void *clf_log_bytes_sent(request_rec *r, char *a, = ap_log_ehandler_data *d) { if (!r->sent_bodyct || !r->bytes_sent) { - return "-"; + d->data=3D"-"; } else { - return apr_off_t_toa(r->pool, r->bytes_sent); + d->data=3Dapr_off_t_toa(r->pool, r->bytes_sent); } + d->type=3DAP_LOG_EHANDLER_RETURN_STRING; } =20 -static const char *log_bytes_sent(request_rec *r, char *a) +static void *log_bytes_sent(request_rec *r, char *a, ap_log_ehandler_data = *d) { - if (!r->sent_bodyct || !r->bytes_sent) { - return "0"; - } - else { - return apr_psprintf(r->pool, "%" APR_OFF_T_FMT, r->bytes_sent); + if (r->header_only =3D=3D 0) { + d->data=3Dapr_palloc(r->pool,sizeof(ap_log_unumber_t)); + *((ap_log_unumber_t *) d->data)=3Dr->bytes_sent; } + d->type=3DAP_LOG_EHANDLER_RETURN_UNUMBER; } =20 - -static const char *log_header_in(request_rec *r, char *a) +static void *log_header_in(request_rec *r, char *a, ap_log_ehandler_data = *d) { - return ap_escape_logitem(r->pool, apr_table_get(r->headers_in, a)); + d->data=3D(void *) apr_table_get(r->headers_in, a); + d->type=3DAP_LOG_EHANDLER_RETURN_STRING; } =20 -static const char *log_header_out(request_rec *r, char *a) +static void *log_header_out(request_rec *r, char *a, ap_log_ehandler_data = *d) { - const char *cp =3D apr_table_get(r->headers_out, a); - if (!strcasecmp(a, "Content-type") && r->content_type) { - cp =3D ap_field_noparam(r->pool, r->content_type); - } - if (cp) { - return ap_escape_logitem(r->pool, cp); - } - return ap_escape_logitem(r->pool, apr_table_get(r->err_headers_out, = a)); + if (!strcasecmp(a, "Content-type") && r->content_type)=20 + d->data =3D ap_field_noparam(r->pool, r->content_type); + else + d->data =3D (void *) apr_table_get(r->headers_out, a); + if (! d->data)=20 + d->data =3D (void *) apr_table_get(r->err_headers_out, a); + d->type=3DAP_LOG_EHANDLER_RETURN_STRING; } =20 -static const char *log_note(request_rec *r, char *a) +static void *log_note(request_rec *r, char *a, ap_log_ehandler_data *d) { - return ap_escape_logitem(r->pool, apr_table_get(r->notes, a)); + d->data =3D (void *) apr_table_get(r->notes, a); + d->type=3DAP_LOG_EHANDLER_RETURN_STRING; } -static const char *log_env_var(request_rec *r, char *a) + +static void *log_env_var(request_rec *r, char *a, ap_log_ehandler_data *d) { - return ap_escape_logitem(r->pool, apr_table_get(r->subprocess_env, = a)); + d->data =3D (void *) apr_table_get(r->subprocess_env, a); + d->type=3DAP_LOG_EHANDLER_RETURN_STRING; } =20 -static const char *log_cookie(request_rec *r, char *a) +static void *log_cookie(request_rec *r, char *a, ap_log_ehandler_data *d) { const char *cookies; const char *start_cookie; =20 + d->type=3DAP_LOG_EHANDLER_RETURN_STRING; if ((cookies =3D apr_table_get(r->headers_in, "Cookie"))) { if ((start_cookie =3D ap_strstr_c(cookies,a))) { char *cookie, *end_cookie; @@ -439,169 +475,94 @@ if (end_cookie) { *end_cookie =3D '\0'; } - return ap_escape_logitem(r->pool, cookie); + d->data=3Dcookie; } } - return NULL; -} - -static const char *log_request_time_custom(request_rec *r, char *a, - apr_time_exp_t *xt) -{ - apr_size_t retcode; - char tstr[MAX_STRING_LEN]; - apr_strftime(tstr, &retcode, sizeof(tstr), a, xt); - return apr_pstrdup(r->pool, tstr); } =20 -#define DEFAULT_REQUEST_TIME_SIZE 32 -typedef struct { - unsigned t; - char timestr[DEFAULT_REQUEST_TIME_SIZE]; - unsigned t_validate; -} cached_request_time; - -#define TIME_CACHE_SIZE 4 -#define TIME_CACHE_MASK 3 -static cached_request_time request_time_cache[TIME_CACHE_SIZE]; - -static const char *log_request_time(request_rec *r, char *a) +static void *log_request_time(request_rec *r, char *a, = ap_log_ehandler_data *d) { - apr_time_exp_t xt; - - /* ### I think getting the time again at the end of the request - * just for logging is dumb. i know it's "required" for CLF. - * folks writing log parsing tools don't realise that out of order - * times have always been possible (consider what happens if one - * process calculates the time to log, but then there's a context - * switch before it writes and before that process is run again the - * log rotation occurs) and they should just fix their tools rather - * than force the server to pay extra cpu cycles. if you've got - * a problem with this, you can set the define. -djg - */ - if (a && *a) { /* Custom format */ - /* The custom time formatting uses a very large temp buffer - * on the stack. To avoid using so much stack space in the - * common case where we're not using a custom format, the code - * for the custom format in a separate function. (That's why - * log_request_time_custom is not inlined right here.) - */ -#ifdef I_INSIST_ON_EXTRA_CYCLES_FOR_CLF_COMPLIANCE - ap_explode_recent_localtime(&xt, apr_time_now()); -#else - ap_explode_recent_localtime(&xt, r->request_time); -#endif - return log_request_time_custom(r, a, &xt); - } - else { /* CLF format */ - /* This code uses the same technique as = ap_explode_recent_localtime(): - * optimistic caching with logic to detect and correct race = conditions. - * See the comments in server/util_time.c for more information. - */ - cached_request_time* cached_time =3D apr_palloc(r->pool, - = sizeof(*cached_time)); + d->type=3DAP_LOG_EHANDLER_RETURN_DATETIME; + d->data=3Dapr_palloc(r->pool,sizeof(apr_time_t)); #ifdef I_INSIST_ON_EXTRA_CYCLES_FOR_CLF_COMPLIANCE - apr_time_t request_time =3D apr_time_now(); + *((apr_time_t *) d->data) =3D apr_time_now(); #else - apr_time_t request_time =3D r->request_time; + *((apr_time_t *) d->data) =3D r->request_time; #endif - unsigned t_seconds =3D (unsigned)apr_time_sec(request_time); - unsigned i =3D t_seconds & TIME_CACHE_MASK; - memcpy(cached_time, &(request_time_cache[i]), = sizeof(*cached_time)); - if ((t_seconds !=3D cached_time->t) || - (t_seconds !=3D cached_time->t_validate)) { - - /* Invalid or old snapshot, so compute the proper time string - * and store it in the cache - */ - char sign; - int timz; - - ap_explode_recent_localtime(&xt, r->request_time); - timz =3D xt.tm_gmtoff; - if (timz < 0) { - timz =3D -timz; - sign =3D '-'; - } - else { - sign =3D '+'; - } - cached_time->t =3D t_seconds; - apr_snprintf(cached_time->timestr, DEFAULT_REQUEST_TIME_SIZE, - "[%02d/%s/%d:%02d:%02d:%02d %c%.2d%.2d]", - xt.tm_mday, apr_month_snames[xt.tm_mon], - xt.tm_year+1900, xt.tm_hour, xt.tm_min, = xt.tm_sec, - sign, timz / (60*60), (timz % (60*60)) / 60); - cached_time->t_validate =3D t_seconds; - memcpy(&(request_time_cache[i]), cached_time, - sizeof(*cached_time)); - } - return cached_time->timestr; - } } =20 -static const char *log_request_duration(request_rec *r, char *a) +static void *log_request_duration(request_rec *r, char *a, = ap_log_ehandler_data *d) { - apr_time_t duration =3D apr_time_now() - r->request_time; - return apr_psprintf(r->pool, "%" APR_TIME_T_FMT, = apr_time_sec(duration)); + d->data=3Dapr_palloc(r->pool,sizeof(ap_log_unumber_t)); + *((ap_log_unumber_t *) d->data) =3D apr_time_sec(apr_time_now() - = r->request_time); + d->arg=3Da; + d->type=3DAP_LOG_EHANDLER_RETURN_UNUMBER; } =20 -static const char *log_request_duration_microseconds(request_rec *r, char = *a) +static void *log_request_duration_microseconds(request_rec *r, char *a, = ap_log_ehandler_data *d) { - return apr_psprintf(r->pool, "%" APR_TIME_T_FMT,=20 - (apr_time_now() - r->request_time)); + d->data=3Dapr_palloc(r->pool,sizeof(ap_log_unumber_t)); + *((ap_log_unumber_t *) d->data) =3D apr_time_now() - r->request_time; + d->arg=3Da; + d->type=3DAP_LOG_EHANDLER_RETURN_UNUMBER; } =20 /* 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) +static void *log_virtual_host(request_rec *r, char *a, = ap_log_ehandler_data *d) { - return ap_escape_logitem(r->pool, r->server->server_hostname); + d->data =3D r->server->server_hostname; + d->arg=3Da; + d->type =3D AP_LOG_EHANDLER_RETURN_STRING; } =20 -static const char *log_server_port(request_rec *r, char *a) +static void *log_server_port(request_rec *r, char *a, ap_log_ehandler_data = *d) { - return apr_psprintf(r->pool, "%u", - r->server->port ? r->server->port : = ap_default_port(r)); + d->data=3Dapr_palloc(r->pool,sizeof(ap_log_unumber_t)); + *((ap_log_unumber_t *) d->data) =3D r->server->port ? r->server->port = : ap_default_port(r); + d->arg=3Da; + d->type=3DAP_LOG_EHANDLER_RETURN_UNUMBER; } =20 /* 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) +static void *log_server_name(request_rec *r, char *a, ap_log_ehandler_data = *d) { - return ap_escape_logitem(r->pool, ap_get_server_name(r)); + d->data =3D (void *) ap_get_server_name(r); + d->arg=3Da; + d->type =3D AP_LOG_EHANDLER_RETURN_STRING; } =20 -static const char *log_pid_tid(request_rec *r, char *a) +static void *log_pid_tid(request_rec *r, char *a, ap_log_ehandler_data *d) { - if (*a =3D=3D '\0' || !strcmp(a, "pid")) { - return apr_psprintf(r->pool, "%" APR_PID_T_FMT, getpid()); + d->arg=3Da; + if (!a || *a =3D=3D '\0' || !strcmp(a, "pid")) { + d->data =3D apr_palloc(r->pool,sizeof(ap_log_unumber_t)); + *((ap_log_unumber_t *) d->data) =3D getpid(); } - else if (!strcmp(a, "tid")) { #if APR_HAS_THREADS - apr_os_thread_t tid =3D apr_os_thread_current(); -#else - int tid =3D 0; /* APR will format "0" anyway but an arg is needed = */ -#endif - return apr_psprintf(r->pool, "%pT", &tid); + else if (!strcmp(a, "tid")) { + d->data =3D apr_palloc(r->pool,sizeof(ap_log_unumber_t)); + *((ap_log_unumber_t *) d->data) =3D apr_os_thread_current(); } - /* bogus format */ - return a; +#endif + d->type =3D AP_LOG_EHANDLER_RETURN_UNUMBER; } =20 -static const char *log_connection_status(request_rec *r, char *a) +static void *log_connection_status(request_rec *r, char *a, = ap_log_ehandler_data *d) { if (r->connection->aborted) - return "X"; - - if (r->connection->keepalive =3D=3D AP_CONN_KEEPALIVE &&=20 + d->data =3D "X"; + else if (r->connection->keepalive =3D=3D AP_CONN_KEEPALIVE &&=20 (!r->server->keep_alive_max || - (r->server->keep_alive_max - r->connection->keepalives) > 0)) { - return "+"; - } - return "-"; + (r->server->keep_alive_max - r->connection->keepalives) > 0))=20 + d->data =3D "+"; + else + d->data =3D "-"; + d->arg=3Da; + d->type =3D AP_LOG_EHANDLER_RETURN_STRING; } =20 /***************************************************************** @@ -615,7 +576,7 @@ const char *s; char *d; =20 - it->func =3D constant_item; + it->handler =3D (log_handler *)apr_hash_get(log_hash, "%", 1); it->conditions =3D NULL; =20 s =3D *sa; @@ -674,7 +635,6 @@ static char *parse_log_item(apr_pool_t *p, log_format_item *it, const char = **sa) { const char *s =3D *sa; - ap_log_handler *handler; =20 if (*s !=3D '%') { return parse_log_misc_string(p, it, sa); @@ -686,14 +646,15 @@ =20 if (*s =3D=3D '%') { it->arg =3D "%"; - it->func =3D constant_item; + it->handler =3D (log_handler *)apr_hash_get(log_hash, "%", 1); + *sa =3D ++s; =20 return NULL; } =20 it->want_orig =3D -1; - it->arg =3D ""; /* For safety's sake... */ + it->arg =3D NULL; /* For safety's sake... */ =20 while (*s) { int i; @@ -744,8 +705,8 @@ break; =20 default: - handler =3D (ap_log_handler *)apr_hash_get(log_hash, s++, 1); - if (!handler) { + it->handler =3D (log_handler *)apr_hash_get(log_hash, s++, 1); + if (!it->handler) { char dummy[2]; =20 dummy[0] =3D s[-1]; @@ -753,9 +714,8 @@ return apr_pstrcat(p, "Unrecognized LogFormat directive = %", dummy, NULL); } - it->func =3D handler->func; if (it->want_orig =3D=3D -1) { - it->want_orig =3D handler->want_orig_default; + it->want_orig =3D it->handler->want_orig_default;=20 } *sa =3D s; return NULL; @@ -776,9 +736,6 @@ return NULL; } } - - s =3D APR_EOL_STR; - parse_log_item(p, (log_format_item *) apr_array_push(a), &s); return a; } =20 @@ -787,11 +744,106 @@ * Actually logging. */ =20 -static const char *process_item(request_rec *r, request_rec *orig, - log_format_item *item) +static const char *format_request_time_custom(request_rec *r, char *a, + apr_time_exp_t *xt) { - const char *cp; + apr_size_t retcode; + char tstr[MAX_STRING_LEN]; + apr_strftime(tstr, &retcode, sizeof(tstr), a, xt); + return apr_pstrdup(r->pool, tstr); +} + +#define DEFAULT_REQUEST_TIME_SIZE 32 +typedef struct { + unsigned t; + char timestr[DEFAULT_REQUEST_TIME_SIZE]; + unsigned t_validate; +} cached_request_time; + +#define TIME_CACHE_SIZE 4 +#define TIME_CACHE_MASK 3 +static cached_request_time request_time_cache[TIME_CACHE_SIZE]; + +static const char *format_request_time(request_rec *r, char *a, apr_time_t = *t, cached_request_time *cache) +{ + apr_time_exp_t xt; + + /* ### I think getting the time again at the end of the request + * just for logging is dumb. i know it's "required" for CLF. + * folks writing log parsing tools don't realise that out of order + * times have always been possible (consider what happens if one + * process calculates the time to log, but then there's a context + * switch before it writes and before that process is run again the + * log rotation occurs) and they should just fix their tools rather + * than force the server to pay extra cpu cycles. if you've got + * a problem with this, you can set the define. -djg + */ + if (a && *a) { /* Custom format */ + /* The custom time formatting uses a very large temp buffer + * on the stack. To avoid using so much stack space in the + * common case where we're not using a custom format, the code + * for the custom format in a separate function. (That's why + * log_request_time_custom is not inlined right here.) + */ +#ifdef I_INSIST_ON_EXTRA_CYCLES_FOR_CLF_COMPLIANCE + ap_explode_recent_localtime(&xt, apr_time_now()); +#else + ap_explode_recent_localtime(&xt, *t); +#endif + return format_request_time_custom(r, a, &xt); + } + else { /* CLF format */ + /* This code uses the same technique as = ap_explode_recent_localtime(): + * optimistic caching with logic to detect and correct race = conditions. + * See the comments in server/util_time.c for more information. + */ + cached_request_time* cached_time =3D apr_palloc(r->pool, + = sizeof(*cached_time)); +#ifdef I_INSIST_ON_EXTRA_CYCLES_FOR_CLF_COMPLIANCE + apr_time_t request_time =3D apr_time_now(); +#else + apr_time_t request_time =3D *t; +#endif + unsigned t_seconds =3D (unsigned)apr_time_sec(request_time); + unsigned i =3D t_seconds & TIME_CACHE_MASK; + memcpy(cached_time, &(request_time_cache[i]), = sizeof(*cached_time)); + if ((t_seconds !=3D cached_time->t) || + (t_seconds !=3D cached_time->t_validate)) { + + /* Invalid or old snapshot, so compute the proper time string + * and store it in the cache + */ + char sign; + int timz; + + ap_explode_recent_localtime(&xt, *t); + timz =3D xt.tm_gmtoff; + if (timz < 0) { + timz =3D -timz; + sign =3D '-'; + } + else { + sign =3D '+'; + } + cached_time->t =3D t_seconds; + apr_snprintf(cached_time->timestr, DEFAULT_REQUEST_TIME_SIZE, + "[%02d/%s/%d:%02d:%02d:%02d %c%.2d%.2d]", + xt.tm_mday, apr_month_snames[xt.tm_mon], + xt.tm_year+1900, xt.tm_hour, xt.tm_min, = xt.tm_sec, + sign, timz / (60*60), timz % (60*60)); + cached_time->t_validate =3D t_seconds; + memcpy(&(request_time_cache[i]), cached_time, + sizeof(*cached_time)); + } + return cached_time->timestr; + } +} + =20 +static void process_item(request_rec *r, request_rec *orig, + log_format_item *item, + ap_log_ehandler_data *d) +{ /* First, see if we need to process this thing at all... */ =20 if (item->conditions && item->conditions->nelts !=3D 0) { @@ -808,14 +860,22 @@ =20 if ((item->condition_sense && in_list) || (!item->condition_sense && !in_list)) { - return "-"; + d->type=3DAP_LOG_EHANDLER_RETURN_STRING; + return; } } =20 + /* We do. Do it... */ =20 - cp =3D (*item->func) (item->want_orig ? orig : r, item->arg); - return cp ? cp : "-"; + if (item->handler->oldstyle) { + if (! (d->data =3D (void *)(*item->handler->handler.func) = (item->want_orig ? orig : r, item->arg))) + d->data =3D "-"; + d->type =3D AP_LOG_EHANDLER_RETURN_OLDSTYLE; + } + else { + (*item->handler->handler.efunc) (item->want_orig ? orig : r, = item->arg, d); + } } =20 static void flush_log(buffered_log *buf) @@ -837,9 +897,10 @@ int i; apr_size_t len =3D 0; apr_array_header_t *format; - char *envar; apr_status_t rv; - + apr_array_header_t *data; + ap_log_ehandler_data *d; + =20 if (cls->fname =3D=3D NULL) { return DECLINED; } @@ -849,25 +910,14 @@ * to make. */ if (cls->condition_var !=3D NULL) { - envar =3D cls->condition_var; - if (*envar !=3D '!') { - if (apr_table_get(r->subprocess_env, envar) =3D=3D NULL) { - return DECLINED; - } - } - else { - if (apr_table_get(r->subprocess_env, &envar[1]) !=3D NULL) { - return DECLINED; - } + if ((cls->condition_sense && apr_table_get(r->subprocess_env, = cls->condition_var) !=3D NULL) + ||=20 + (!cls->condition_sense && apr_table_get(r->subprocess_env, = cls->condition_var) =3D=3D NULL)) + { + return DECLINED; } } =20 - format =3D cls->format ? cls->format : default_format; - - strs =3D apr_palloc(r->pool, sizeof(char *) * (format->nelts)); - strl =3D apr_palloc(r->pool, sizeof(int) * (format->nelts)); - items =3D (log_format_item *) format->elts; - orig =3D r; while (orig->prev) { orig =3D orig->prev; @@ -876,20 +926,84 @@ r =3D r->next; } =20 - for (i =3D 0; i < format->nelts; ++i) { - strs[i] =3D process_item(r, orig, &items[i]); + if (cls->conditions && cls->conditions->nelts !=3D 0) { + int *conds =3D (int *) cls->conditions->elts; + int in_list =3D 0; + + for (i =3D 0; i < cls->conditions->nelts; ++i) { + if (r->status =3D=3D conds[i]) { + in_list =3D 1; + break; + } + } + + if ((cls->condition_sense && in_list) + || (!cls->condition_sense && !in_list)) { + return DECLINED; + } } =20 + format =3D cls->format ? cls->format : default_format; + data =3D apr_array_make(r->pool, format->nelts, = sizeof(ap_log_ehandler_data)); + items =3D (log_format_item *) format->elts; for (i =3D 0; i < format->nelts; ++i) { - len +=3D strl[i] =3D strlen(strs[i]); + d =3D (ap_log_ehandler_data *) apr_array_push(data); + d->data =3D NULL; + d->arg =3D items[i].arg; + process_item(r, orig, &items[i], d); } - if (!log_writer) { - ap_log_rerror(APLOG_MARK, APLOG_ERR, APR_EGENERAL, r, - "log writer isn't correctly setup"); - return HTTP_INTERNAL_SERVER_ERROR; + =20 + if (cls->writer) { /* this is a new style writer */ + rv =3D cls->writer->write(r, cls->writer_data, data); + } + else if (log_writer) { /* this is an old style writer */ + strs =3D apr_palloc(r->pool, sizeof(char *) * (format->nelts)); + strl =3D apr_palloc(r->pool, sizeof(int) * (format->nelts)); + for (i =3D 0; i < data->nelts; ++i) { + d=3D&(((ap_log_ehandler_data*)(data->elts))[i]); + if ((d) && (d->data)) { + switch (d->type) { + case AP_LOG_EHANDLER_RETURN_OLDSTYLE: + strs[i] =3D d->data; + break; + =20 + case AP_LOG_EHANDLER_RETURN_CONST: + strs[i] =3D d->data; + break; + =20 + case AP_LOG_EHANDLER_RETURN_STRING: + if (strlen(d->data)=3D=3D0) + strs[i] =3D "\"\""; + else + strs[i] =3D ap_escape_logitem(r->pool, d->data); + break; + =20 + case AP_LOG_EHANDLER_RETURN_NUMBER: + strs[i] =3D apr_psprintf(r->pool,"%" = AP_LOG_NUMBER_T_FMT,*((ap_log_number_t *) d->data)); + break; + =20 + case AP_LOG_EHANDLER_RETURN_UNUMBER: + strs[i] =3D apr_psprintf(r->pool,"%" = AP_LOG_UNUMBER_T_FMT,*((ap_log_unumber_t *) d->data)); + break; + =20 + case AP_LOG_EHANDLER_RETURN_DATETIME: + strs[i] =3D format_request_time(r,d->arg,d->data,NULL); + break; + } + } + else { + strs[i]=3D"-"; + } + } + for (i =3D 0; i < format->nelts; ++i) { + len +=3D strl[i] =3D strlen(strs[i]); + } + rv =3D log_writer(r, cls->writer_data, strs, strl, format->nelts, = len); + /* xxx: do we return an error on log_writer? */ + } + else { /* no writer at all, use our file writer as default */ + rv =3D ap_filepipe_log_ewriter(r, cls->writer_data, data); } - rv =3D log_writer(r, cls->log_writer, strs, strl, format->nelts, len); - /* xxx: do we return an error on log_writer? */ return OK; } =20 @@ -1000,21 +1114,87 @@ multi_log_state *mls =3D = ap_get_module_config(cmd->server->module_config, &log_config_module); config_log_state *cls; - + char *pos; + log_ewriter *writer; + int i; + =20 cls =3D (config_log_state *) apr_array_push(mls->config_logs); cls->condition_var =3D NULL; + cls->conditions =3D NULL; if (envclause !=3D NULL) { - if (strncasecmp(envclause, "env=3D", 4) !=3D 0) { - return "error in condition clause"; + if (strncasecmp(envclause, "env=3D", 4) =3D=3D 0) { + i =3D 4; + if (cls->condition_sense =3D (envclause[i] =3D=3D '!')) { + i++; + } + if (envclause[i] =3D=3D '\0') { + return "missing environment variable name"; + } + else { + cls->condition_var =3D apr_pstrdup(cmd->pool, = &envclause[i]); + } + } + else if (strncasecmp(envclause, "status=3D", 7) =3D=3D 0) { + i =3D 7; + if (cls->condition_sense =3D (envclause[i] =3D=3D '!')) { + i++; + } + if (envclause[i] =3D=3D '\0') { + return "missing status code(s)"; + } + else { + pos =3D (char*)&envclause[i]; + while (*pos) { + switch (*pos) { + case ',': + ++pos; + break; + + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + i =3D *pos - '0'; + while (apr_isdigit(*++pos)) { + i =3D i * 10 + (*pos) - '0'; + } + if (!cls->conditions) { + cls->conditions =3D apr_array_make(cmd->pool, = 4, sizeof(int)); + } + *(int *) apr_array_push(cls->conditions) =3D i; + break; + =20 + default: + return "illegal character within status code(s)"; + } + } + } } - if ((envclause[4] =3D=3D '\0') - || ((envclause[4] =3D=3D '!') && (envclause[5] =3D=3D '\0'))) = { - return "missing environment variable name"; + else { + return "error in condition clause"; } - cls->condition_var =3D apr_pstrdup(cmd->pool, &envclause[4]); } =20 cls->fname =3D fn; + if ((pos =3D strchr(fn,':')) && (cls->writer =3D = apr_hash_get(writer_hash, fn, pos-fn)) ) { + cls->fname=3Dpos+1; + } + else { + cls->writer=3DNULL; + } + /* xxx Doesn't return an error if a key ("bla:/file") is given but no=20 + * corresponding writer exists. The reason is backwards compatibility, + * to be able to fall back to the old file write mechanism -- but is=20 + * this really necessary? Is there anybody (except fellow Amigans) + * who uses : in file system paths? + */ + =20 cls->format_string =3D fmt; if (fmt =3D=3D NULL) { cls->format =3D NULL; @@ -1022,8 +1202,7 @@ else { cls->format =3D parse_log_string(cmd->pool, fmt, &err_string); } - cls->log_writer =3D NULL; - + cls->writer_data =3D NULL; return err_string; } =20 @@ -1041,10 +1220,6 @@ static const char *set_buffered_logs_on(cmd_parms *parms, void *dummy, int = flag) { buffered_logs =3D flag; - if (buffered_logs) { - ap_log_set_writer_init(ap_buffered_log_writer_init); - ap_log_set_writer(ap_buffered_log_writer); - } return NULL; } static const command_rec config_log_cmds[] =3D @@ -1067,16 +1242,25 @@ config_log_state *cls, apr_array_header_t = *default_format) { - if (cls->log_writer !=3D NULL) { + if (cls->writer_data !=3D NULL) { return cls; /* virtual config shared w/main server */ } =20 if (cls->fname =3D=3D NULL) { return cls; /* Leave it NULL to decline. */ } - =20 - cls->log_writer =3D log_writer_init(p, s, cls->fname); - if (cls->log_writer =3D=3D NULL) + + if (cls->writer) { /* new style style writer */ + cls->writer_data =3D cls->writer->setup(p, s, cls->fname); + } + else if (log_writer_init) { /* old style writer */ + cls->writer_data =3D log_writer_init(p, s, cls->fname); + } + else { /* default, takes care of old "|pipe" as well as simple "file" = syntax */ + cls->writer_data =3D ap_old_log_writer_init(p, s, cls->fname); + } + =20 + if (cls->writer_data =3D=3D NULL) return NULL;=20 =20 return cls; @@ -1152,23 +1336,22 @@ buffered_log *buf; int i; =20 - if (!buffered_logs) - return APR_SUCCESS; - =20 for (; s; s =3D s->next) { mls =3D ap_get_module_config(s->module_config, = &log_config_module); - log_list =3D NULL; if (mls->config_logs->nelts) { log_list =3D mls->config_logs; } else if (mls->server_config_logs) { log_list =3D mls->server_config_logs; } + else { + log_list =3D NULL; + } if (log_list) { clsarray =3D (config_log_state *) log_list->elts; for (i =3D 0; i < log_list->nelts; ++i) { - buf =3D clsarray[i].log_writer; - flush_log(buf); + if ((clsarray[i].writer) && (clsarray[i].writer->exit)) + clsarray[i].writer->exit(s, clsarray[i].writer_data); } } } @@ -1178,17 +1361,10 @@ =20 static int init_config_log(apr_pool_t *pc, apr_pool_t *p, apr_pool_t *pt, = server_rec *s) { - int res; - - /* First init the buffered logs array, which is needed when opening = the logs. */ - if (buffered_logs) { - all_buffered_logs =3D apr_array_make(p, 5, sizeof(buffered_log = *)); - } - - /* Next, do "physical" server, which gets default log fd and format + /* First, do "physical" server, which gets default log fd and format * for the virtual servers, if they don't override... */ - res =3D open_multi_logs(s, p); + int res =3D open_multi_logs(s, p); =20 /* Then, virtual servers */ =20 @@ -1201,39 +1377,30 @@ =20 static void init_child(apr_pool_t *p, server_rec *s) { - int mpm_threads; - - ap_mpm_query(AP_MPMQ_MAX_THREADS, &mpm_threads); - - /* Now register the last buffer flush with the cleanup engine */ - if (buffered_logs) { - int i; - buffered_log **array =3D (buffered_log **)all_buffered_logs->elts; - =20 - apr_pool_cleanup_register(p, s, flush_all_logs, flush_all_logs); + multi_log_state *mls; + apr_array_header_t *log_list; + config_log_state *clsarray; + buffered_log *buf; + int i; =20 - for (i =3D 0; i < all_buffered_logs->nelts; i++) { - buffered_log *this =3D array[i]; - =20 -#if APR_HAS_THREADS - if (mpm_threads > 1) { - apr_status_t rv; + apr_pool_cleanup_register(p, s, flush_all_logs, flush_all_logs); =20 - this->mutex.type =3D apr_anylock_threadmutex; - rv =3D apr_thread_mutex_create(&this->mutex.lock.tm, - APR_THREAD_MUTEX_DEFAULT, - p); - if (rv !=3D APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s, - "could not initialize buffered log mutex, = " - "transfer log may become corrupted"); - this->mutex.type =3D apr_anylock_none; - } - } - else -#endif - { - this->mutex.type =3D apr_anylock_none; + for (; s; s =3D s->next) { + mls =3D ap_get_module_config(s->module_config, = &log_config_module); + if (mls->config_logs->nelts) { + log_list =3D mls->config_logs; + } + else if (mls->server_config_logs) { + log_list =3D mls->server_config_logs; + } + else { + log_list =3D NULL; + } + if (log_list) { + clsarray =3D (config_log_state *) log_list->elts; + for (i =3D 0; i < log_list->nelts; ++i) { + if ((clsarray[i].writer) && (clsarray[i].writer->init)) + clsarray[i].writer->init(p, s, = clsarray[i].writer_data); } } } @@ -1242,173 +1409,257 @@ static void ap_register_log_handler(apr_pool_t *p, char *tag,=20 ap_log_handler_fn_t *handler, int def) { - ap_log_handler *log_struct =3D apr_palloc(p, sizeof(*log_struct)); - log_struct->func =3D handler; + log_handler *log_struct =3D apr_palloc(p, sizeof(*log_struct)); + log_struct->handler.func =3D handler; log_struct->want_orig_default =3D def; + log_struct->oldstyle =3D -1; =20 apr_hash_set(log_hash, tag, 1, (const void *)log_struct); } -static void ap_log_set_writer_init(ap_log_writer_init *handle) +static void ap_register_log_ehandler(apr_pool_t *p, char *tag,=20 + ap_log_ehandler_fn_t *handler, int = def) { - log_writer_init =3D handle; + log_handler *log_struct =3D apr_palloc(p, sizeof(*log_struct)); + log_struct->handler.efunc =3D handler; + log_struct->want_orig_default =3D def; + log_struct->oldstyle =3D 0; +=20 + apr_hash_set(log_hash, tag, 1, (const void *)log_struct); +} =20 +static ap_log_writer_init* ap_log_set_writer_init(ap_log_writer_init = *handle) +{ + ap_log_writer_init *old =3D log_writer_init; + log_writer_init =3D handle; + =20 + return old; } -static void ap_log_set_writer(ap_log_writer *handle) +static ap_log_writer* ap_log_set_writer(ap_log_writer *handle) { + ap_log_writer *old =3D log_writer; log_writer =3D handle; + =20 + return old; } =20 -static apr_status_t ap_default_log_writer( request_rec *r, - void *handle,=20 - const char **strs, - int *strl, - int nelts, - apr_size_t len) +static void ap_register_log_ewriter(apr_pool_t *p, char *key,=20 + ap_log_ewriter_setup *setup, + ap_log_ewriter *write, + ap_log_ewriter_init *init, + ap_log_ewriter_exit *exit) +{ + log_ewriter *writer_struct =3D apr_palloc(p, sizeof(*writer_struct)); + writer_struct->setup =3D setup; + writer_struct->write =3D write; + writer_struct->init =3D init; + writer_struct->exit =3D exit; + apr_hash_set(writer_hash, key, APR_HASH_KEY_STRING, (const void = *)writer_struct); +} + +static apr_status_t ap_filepipe_log_ewriter(request_rec *r, + void *handle,=20 + apr_array_header_t *data) =20 { char *str; char *s; + const char **strs; + int *strl; int i; + int len =3D 0; apr_status_t rv; + buffered_log *buf =3D (buffered_log*)handle; + ap_log_ehandler_data *d; =20 - str =3D apr_palloc(r->pool, len + 1); + strs =3D apr_palloc(r->pool, sizeof(char *) * (data->nelts)); + strl =3D apr_palloc(r->pool, sizeof(int) * (data->nelts)); + for (i =3D 0; i < data->nelts; ++i) { + d=3D&(((ap_log_ehandler_data*)(data->elts))[i]); + if ((d) && (d->data)) { + switch (d->type) + { + case AP_LOG_EHANDLER_RETURN_OLDSTYLE: + strs[i] =3D d->data; + break; + =20 + case AP_LOG_EHANDLER_RETURN_CONST: + strs[i] =3D d->data; + break; + =20 + case AP_LOG_EHANDLER_RETURN_STRING: + if (strlen(d->data)=3D=3D0) + strs[i] =3D "\"\""; + else + strs[i] =3D ap_escape_logitem(r->pool, d->data); + break; =20 - for (i =3D 0, s =3D str; i < nelts; ++i) { - memcpy(s, strs[i], strl[i]); - s +=3D strl[i]; - } + case AP_LOG_EHANDLER_RETURN_NUMBER: + strs[i] =3D apr_psprintf(r->pool,"%" = AP_LOG_NUMBER_T_FMT,*((ap_log_number_t *) d->data)); + break; =20 - rv =3D apr_file_write((apr_file_t*)handle, str, &len); + case AP_LOG_EHANDLER_RETURN_UNUMBER: + strs[i] =3D apr_psprintf(r->pool,"%" = AP_LOG_UNUMBER_T_FMT,*((ap_log_unumber_t *) d->data)); + break; =20 - return rv; -} -static void *ap_default_log_writer_init(apr_pool_t *p, server_rec *s,=20 - const char* name) -{ - if (*name =3D=3D '|') { - piped_log *pl; + case AP_LOG_EHANDLER_RETURN_DATETIME: + strs[i] =3D format_request_time(r,d->arg,d->data,NULL); + break; + } + } + else { + strs[i]=3D"-"; + } + len +=3D strl[i] =3D strlen(strs[i]); + } + len +=3D strlen(APR_EOL_STR); =20 - pl =3D ap_open_piped_log(p, name + 1); - if (pl =3D=3D NULL) { - return NULL;; + if (!buffered_logs) { + str =3D apr_palloc(r->pool, len + 1); + for (i =3D 0, s =3D str; i < data->nelts; ++i) { + memcpy(s, strs[i], strl[i]); + s +=3D strl[i]; } - return ap_piped_log_write_fd(pl); + memcpy(s, APR_EOL_STR, strlen(APR_EOL_STR)); + rv =3D apr_file_write((apr_file_t*)handle, str, &len); } else { - const char *fname =3D ap_server_root_relative(p, name); - apr_file_t *fd; - apr_status_t rv; - - if (!fname) { - ap_log_error(APLOG_MARK, APLOG_ERR, APR_EBADPATH, s, - "invalid transfer log path %s.", name); - return NULL; + buffered_log *buf =3D (buffered_log*)handle; + + if (len + buf->outcnt > LOG_BUFSIZE) { + flush_log(buf); } - rv =3D apr_file_open(&fd, fname, xfer_flags, xfer_perms, p); - if (rv !=3D APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, - "could not open transfer log file %s.", = fname); - return NULL; + if (len >=3D LOG_BUFSIZE) { + apr_size_t w; + =20 + str =3D apr_palloc(r->pool, len + 1 ); + for (i =3D 0, s =3D str; i < data->nelts; ++i) { + memcpy(s, strs[i], strl[i]); + s +=3D strl[i]; + } + memcpy(s, APR_EOL_STR, strlen(APR_EOL_STR)); + w =3D len; + rv =3D apr_file_write(buf->handle, str, &w); + } + else { + for (i =3D 0, s =3D &buf->outbuf[buf->outcnt]; i < = data->nelts; ++i) { + memcpy(s, strs[i], strl[i]); + s +=3D strl[i]; + } + memcpy(s, APR_EOL_STR, strlen(APR_EOL_STR)); + buf->outcnt +=3D len; + rv =3D APR_SUCCESS; } - return fd; } + + return rv; } -static void *ap_buffered_log_writer_init(apr_pool_t *p, server_rec *s,=20 - const char* name) + +static void *init_buffered_logs(apr_pool_t *p, void *handle)=20 { buffered_log *b; - b =3D apr_pcalloc(p, sizeof(buffered_log)); - b->handle =3D ap_default_log_writer_init(p, s, name); + b =3D apr_palloc(p, sizeof(buffered_log)); + b->handle =3D handle; + b->outcnt =3D 0; =20 - if (b->handle) { - *(buffered_log **)apr_array_push(all_buffered_logs) =3D b; + if (b->handle) return b; - } else return NULL; } -static apr_status_t ap_buffered_log_writer(request_rec *r, - void *handle,=20 - const char **strs, - int *strl, - int nelts, - apr_size_t len) =20 +static void *ap_file_log_writer_setup(apr_pool_t *p, server_rec *s,=20 + const char* name) { - char *str; - char *s; - int i; + const char *fname =3D ap_server_root_relative(p, name); + apr_file_t *fd; apr_status_t rv; - buffered_log *buf =3D (buffered_log*)handle; =20 - if ((rv =3D APR_ANYLOCK_LOCK(&buf->mutex)) !=3D APR_SUCCESS) { - return rv; + if (!fname) { + ap_log_error(APLOG_MARK, APLOG_ERR, APR_EBADPATH, s, + "invalid transfer log path %s.", name); + return NULL; } - - if (len + buf->outcnt > LOG_BUFSIZE) { - flush_log(buf); + rv =3D apr_file_open(&fd, fname, xfer_flags, xfer_perms, p); + if (rv !=3D APR_SUCCESS) { + ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, + "could not open transfer log file %s.", fname); + return NULL; } - if (len >=3D LOG_BUFSIZE) { - apr_size_t w; + if (buffered_logs) + return init_buffered_logs(p, fd); + else + return fd; +} =20 - str =3D apr_palloc(r->pool, len + 1); - for (i =3D 0, s =3D str; i < nelts; ++i) { - memcpy(s, strs[i], strl[i]); - s +=3D strl[i]; - } - w =3D len; - rv =3D apr_file_write(buf->handle, str, &w); - =20 - } - else { - for (i =3D 0, s =3D &buf->outbuf[buf->outcnt]; i < nelts; ++i) { - memcpy(s, strs[i], strl[i]); - s +=3D strl[i]; - } - buf->outcnt +=3D len; - rv =3D APR_SUCCESS; +static void *ap_pipe_log_writer_setup(apr_pool_t *p, server_rec *s,=20 + const char* name) +{ + piped_log *pl; + + pl =3D ap_open_piped_log(p, name); + if (pl =3D=3D NULL) { + return NULL;; } + if (buffered_logs) + return init_buffered_logs(p, ap_piped_log_write_fd(pl)); + else + return ap_piped_log_write_fd(pl); +} =20 - APR_ANYLOCK_UNLOCK(&buf->mutex); - return rv; +static void *ap_old_log_writer_init(apr_pool_t *p, server_rec *s, + const char* name) +{ + if (*name =3D=3D '|') + return ap_pipe_log_writer_setup(p, s, name + 1); =20 + else + return ap_file_log_writer_setup(p, s, name); +} + +static void ap_filepipe_log_ewriter_exit(server_rec *s, void *data) +{ + if (buffered_logs) + flush_log((buffered_log*)data); } =20 static int log_pre_config(apr_pool_t *p, apr_pool_t *plog, apr_pool_t = *ptemp) { - static APR_OPTIONAL_FN_TYPE(ap_register_log_handler) = *log_pfn_register; - =20 - log_pfn_register =3D = APR_RETRIEVE_OPTIONAL_FN(ap_register_log_handler); + static APR_OPTIONAL_FN_TYPE(ap_register_log_ehandler) = *log_pfn_eregister; =20 - if (log_pfn_register) { - log_pfn_register(p, "h", log_remote_host, 0); - log_pfn_register(p, "a", log_remote_address, 0 ); - log_pfn_register(p, "A", log_local_address, 0 ); - log_pfn_register(p, "l", log_remote_logname, 0); - log_pfn_register(p, "u", log_remote_user, 0); - log_pfn_register(p, "t", log_request_time, 0); - log_pfn_register(p, "f", log_request_file, 0); - log_pfn_register(p, "b", clf_log_bytes_sent, 0); - log_pfn_register(p, "B", log_bytes_sent, 0); - log_pfn_register(p, "i", log_header_in, 0); - log_pfn_register(p, "o", log_header_out, 0); - log_pfn_register(p, "n", log_note, 0); - log_pfn_register(p, "e", log_env_var, 0); - log_pfn_register(p, "V", log_server_name, 0); - log_pfn_register(p, "v", log_virtual_host, 0); - log_pfn_register(p, "p", log_server_port, 0); - log_pfn_register(p, "P", log_pid_tid, 0); - log_pfn_register(p, "H", log_request_protocol, 0); - log_pfn_register(p, "m", log_request_method, 0); - log_pfn_register(p, "q", log_request_query, 0); - log_pfn_register(p, "X", log_connection_status, 0); - log_pfn_register(p, "C", log_cookie, 0); - log_pfn_register(p, "r", log_request_line, 1); - log_pfn_register(p, "D", log_request_duration_microseconds, 1); - log_pfn_register(p, "T", log_request_duration, 1); - log_pfn_register(p, "U", log_request_uri, 1); - log_pfn_register(p, "s", log_status, 1); - } + = ap_register_log_ewriter(p,"file",ap_file_log_writer_setup,ap_filepipe_log_ew= riter,NULL,ap_filepipe_log_ewriter_exit); + = ap_register_log_ewriter(p,"pipe",ap_pipe_log_writer_setup,ap_filepipe_log_ew= riter,NULL,ap_filepipe_log_ewriter_exit); =20 + log_pfn_eregister =3D = APR_RETRIEVE_OPTIONAL_FN(ap_register_log_ehandler); + if (log_pfn_eregister) { + log_pfn_eregister(p, "%", constant_item, 0); + log_pfn_eregister(p, "h", log_remote_host, 0); + log_pfn_eregister(p, "a", log_remote_address, 0 ); + log_pfn_eregister(p, "A", log_local_address, 0 ); + log_pfn_eregister(p, "l", log_remote_logname, 0); + log_pfn_eregister(p, "r", log_request_line, 1); + log_pfn_eregister(p, "u", log_remote_user, 0); + log_pfn_eregister(p, "s", log_status, 1); + log_pfn_eregister(p, "f", log_request_file, 0); + log_pfn_eregister(p, "U", log_request_uri, 1); + log_pfn_eregister(p, "m", log_request_method, 0); + log_pfn_eregister(p, "H", log_request_protocol, 0); + log_pfn_eregister(p, "q", log_request_query, 0); + log_pfn_eregister(p, "b", clf_log_bytes_sent, 0); + log_pfn_eregister(p, "B", log_bytes_sent, 0); + log_pfn_eregister(p, "i", log_header_in, 0); + log_pfn_eregister(p, "o", log_header_out, 0); + log_pfn_eregister(p, "n", log_note, 0); + log_pfn_eregister(p, "e", log_env_var, 0); + log_pfn_eregister(p, "C", log_cookie, 0); + log_pfn_eregister(p, "V", log_server_name, 0); + log_pfn_eregister(p, "v", log_virtual_host, 0); + log_pfn_eregister(p, "p", log_server_port, 0); + log_pfn_eregister(p, "D", log_request_duration_microseconds, 1); + log_pfn_eregister(p, "P", log_pid_tid, 0); + log_pfn_eregister(p, "R", log_unparsed_request_uri, 1); + log_pfn_eregister(p, "t", log_request_time, 0); + log_pfn_eregister(p, "T", log_request_duration, 1); + log_pfn_eregister(p, "X", log_connection_status, 0); + } return OK; } =20 @@ -1429,6 +1680,10 @@ APR_REGISTER_OPTIONAL_FN(ap_register_log_handler); APR_REGISTER_OPTIONAL_FN(ap_log_set_writer_init); APR_REGISTER_OPTIONAL_FN(ap_log_set_writer); + + APR_REGISTER_OPTIONAL_FN(ap_register_log_ehandler); + writer_hash =3D apr_hash_make(p); + APR_REGISTER_OPTIONAL_FN(ap_register_log_ewriter); } =20 module AP_MODULE_DECLARE_DATA log_config_module =3D @@ -1441,4 +1696,3 @@ config_log_cmds, /* command apr_table_t */ register_hooks /* register hooks */ }; - --==========B6C94F11EFDA6764AC7E========== Content-Type: text/plain; charset=iso-8859-1; name="patch-modules:loggers:mod_log_config.h" Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename="patch-modules:loggers:mod_log_config.h"; size=4615 --- modules/loggers/mod_log_config.h.orig Mon Feb 9 15:53:18 2004 +++ modules/loggers/mod_log_config.h Sun Oct 5 07:08:08 2003 @@ -21,17 +21,49 @@ #define _MOD_LOG_CONFIG_H 1 =20 /**=20 - * callback function prototype for a external log handler + * callback function prototype for an external log handler */ + +/* types of returned data */ +#define AP_LOG_EHANDLER_RETURN_CONST -1 /* the text between %-items */ +#define AP_LOG_EHANDLER_RETURN_OLDSTYLE 0 /* ap_escape_logitem() string = */ +#define AP_LOG_EHANDLER_RETURN_STRING 1 /* raw string, not escaped */ +#define AP_LOG_EHANDLER_RETURN_NUMBER 2 /* signed number, = ap_log_number_t */ +#define AP_LOG_EHANDLER_RETURN_UNUMBER 3 /* unsigned number, = ap_log_unumber_t */ +#define AP_LOG_EHANDLER_RETURN_DATETIME 4 /* time, apr_time_t */ + +#define ap_log_number_t apr_int64_t +#define ap_log_unumber_t apr_uint64_t +#define AP_LOG_NUMBER_T_FMT APR_INT64_T_FMT +#define AP_LOG_UNUMBER_T_FMT APR_UINT64_T_FMT + +/* struct to hold returned data */ +typedef struct ap_log_ehandler_data { + int type; /* AP_LOG_EHANDLER_RETURN_*, see above */ + char *arg; /* log item argument, as given in e.g. %{arg}t */ + void *data; /* pointer to data or null if n/a */ +} ap_log_ehandler_data; + typedef const char *ap_log_handler_fn_t(request_rec *r, char *a); +typedef void *ap_log_ehandler_fn_t(request_rec *r, char *a, = ap_log_ehandler_data *d); + +APR_DECLARE_OPTIONAL_FN(void, ap_register_log_handler,=20 + (apr_pool_t *p, char *tag, ap_log_handler_fn_t = *func, + int def)); +APR_DECLARE_OPTIONAL_FN(void, ap_register_log_ehandler,=20 + (apr_pool_t *p, char *tag, ap_log_ehandler_fn_t = *func, + int def)); =20 /** - * callback function prototype for a external writer initilization. + * callback function prototype for an external writer's initialization. */ typedef void *ap_log_writer_init(apr_pool_t *p, server_rec *s,=20 const char *name); +typedef void *ap_log_ewriter_setup(apr_pool_t *p, server_rec *s,=20 + const char *name); + /** - * callback which gets called where there is a log line to write. + * callback which gets called when there is a log line to write. */ typedef apr_status_t ap_log_writer( request_rec *r, @@ -40,23 +72,43 @@ int *lengths, int nelts, apr_size_t len); +typedef apr_status_t ap_log_ewriter( + request_rec *r, + void *handle,=20 + apr_array_header_t *data); =20 -typedef struct ap_log_handler { - ap_log_handler_fn_t *func; - int want_orig_default; -} ap_log_handler; +/** + * callback function prototypes for each child's external writer init and = exit + */ +typedef void ap_log_ewriter_init(apr_pool_t *p, server_rec *s, void = *data); +typedef void ap_log_ewriter_exit(server_rec *s, void *data); =20 -APR_DECLARE_OPTIONAL_FN(void, ap_register_log_handler,=20 - (apr_pool_t *p, char *tag, ap_log_handler_fn_t = *func, - int def)); /** * you will need to set your init handler *BEFORE* the open_logs=20 * in mod_log_config gets executed - */ -APR_DECLARE_OPTIONAL_FN(void, ap_log_set_writer_init,(ap_log_writer_init = *func)); -/**=20 * you should probably set the writer at the same time (ie..before = open_logs) + * + * ap_log_set_writer() deprecated, better use ap_register_log_ewriter() + */ + +APR_DECLARE_OPTIONAL_FN(ap_log_writer_init*, = ap_log_set_writer_init,(ap_log_writer_init *func)); +APR_DECLARE_OPTIONAL_FN(ap_log_writer*, ap_log_set_writer, (ap_log_writer* = func)); + +/* + * Register a new log writer. + * p pool, you get this as argument to your pre_config hook + * key the scheme part of a CustomLog uri, identifies this log writer + * write write a line of log data + * setup called during ap_hook_open_logs + * init called during ap_hook_child_init + * exit called upon child exit (registered as pool cleanup from = ap_hook_child_init()) */ -APR_DECLARE_OPTIONAL_FN(void, ap_log_set_writer, (ap_log_writer* func)); +APR_DECLARE_OPTIONAL_FN(void, ap_register_log_ewriter,=20 + (apr_pool_t *p, char *key,=20 + ap_log_ewriter_setup *setup, + ap_log_ewriter *write, + ap_log_ewriter_init *init, + ap_log_ewriter_exit *exit) + ); =20 #endif /* MOD_LOG_CONFIG */ --==========B6C94F11EFDA6764AC7E========== Content-Type: text/plain; charset=iso-8859-1; name="patch-modules:loggers:mod_logio.c" Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename="patch-modules:loggers:mod_logio.c"; size=1974 --- modules/loggers/mod_logio.c.orig Mon Feb 9 15:53:18 2004 +++ modules/loggers/mod_logio.c Sun Oct 5 07:08:08 2003 @@ -29,7 +29,6 @@ #include "apr_lib.h" #include "apr_hash.h" #include "apr_optional.h" - #define APR_WANT_STRFUNC #include "apr_want.h" =20 @@ -40,6 +39,7 @@ #include "http_config.h" #include "http_connection.h" #include "http_protocol.h" +#include "http_log.h" =20 module AP_MODULE_DECLARE_DATA logio_module; =20 @@ -68,20 +68,23 @@ * Format items... */ =20 -static const char *log_bytes_in(request_rec *r, char *a) +static void *log_bytes_in(request_rec *r, char *a, ap_log_ehandler_data = *d) { logio_config_t *cf =3D = ap_get_module_config(r->connection->conn_config, &logio_module); - - return apr_off_t_toa(r->pool, cf->bytes_in); + d->type =3D AP_LOG_EHANDLER_RETURN_UNUMBER; + d->data =3D apr_palloc(r->pool, sizeof(ap_log_unumber_t)); + *(ap_log_unumber_t*)d->data =3D cf->bytes_in; } =20 -static const char *log_bytes_out(request_rec *r, char *a) +static void *log_bytes_out(request_rec *r, char *a, ap_log_ehandler_data = *d) { logio_config_t *cf =3D = ap_get_module_config(r->connection->conn_config, &logio_module); =20 - return apr_off_t_toa(r->pool, cf->bytes_out); + d->type =3D AP_LOG_EHANDLER_RETURN_UNUMBER; + d->data =3D apr_palloc(r->pool, sizeof(ap_log_unumber_t)); + *(ap_log_unumber_t*)d->data =3D cf->bytes_out; } =20 /* @@ -153,9 +156,9 @@ =20 static int logio_pre_config(apr_pool_t *p, apr_pool_t *plog, apr_pool_t = *ptemp) { - static APR_OPTIONAL_FN_TYPE(ap_register_log_handler) = *log_pfn_register; + static APR_OPTIONAL_FN_TYPE(ap_register_log_ehandler) = *log_pfn_register; =20 - log_pfn_register =3D = APR_RETRIEVE_OPTIONAL_FN(ap_register_log_handler); + log_pfn_register =3D = APR_RETRIEVE_OPTIONAL_FN(ap_register_log_ehandler); =20 if (log_pfn_register) { log_pfn_register(p, "I", log_bytes_in, 0); --==========B6C94F11EFDA6764AC7E==========--