1 /* ====================================================================
2 * The Apache Software License, Version 1.1
4 * Copyright (c) 2000-2001 The Apache Software Foundation. All rights
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in
16 * the documentation and/or other materials provided with the
19 * 3. The end-user documentation included with the redistribution,
20 * if any, must include the following acknowledgment:
21 * "This product includes software developed by the
22 * Apache Software Foundation (http://www.apache.org/)."
23 * Alternately, this acknowledgment may appear in the software itself,
24 * if and wherever such third-party acknowledgments normally appear.
26 * 4. The names "Apache" and "Apache Software Foundation" must
27 * not be used to endorse or promote products derived from this
28 * software without prior written permission. For written
29 * permission, please contact apache@apache.org.
31 * 5. Products derived from this software may not be called "Apache",
32 * nor may "Apache" appear in their name, without prior written
33 * permission of the Apache Software Foundation.
35 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
36 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
37 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
38 * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
39 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
41 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
42 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
43 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
44 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
45 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
47 * ====================================================================
49 * This software consists of voluntary contributions made by many
50 * individuals on behalf of the Apache Software Foundation. For more
51 * information on the Apache Software Foundation, please see
52 * <http://www.apache.org/>.
54 * Portions of this software are based upon public domain software
55 * originally written at the National Center for Supercomputing Applications,
56 * University of Illinois, Urbana-Champaign.
60 * Modified by djm@va.pubnix.com:
61 * If no TransferLog is given explicitly, decline to log.
63 * This is module implements the TransferLog directive (same as the
64 * common log module), and additional directives, LogFormat and CustomLog.
69 * TransferLog fn Logs transfers to fn in standard log format, unless
70 * a custom format is set with LogFormat
71 * LogFormat format Set a log format from TransferLog files
73 * Log to file fn with format given by the format
76 * CookieLog fn For backwards compatability with old Cookie
77 * logging module - now deprecated.
79 * There can be any number of TransferLog and CustomLog
80 * commands. Each request will be logged to _ALL_ the
81 * named files, in the appropriate format.
83 * If no TransferLog or CustomLog directive appears in a VirtualHost,
84 * the request will be logged to the log file(s) defined outside
85 * the virtual host section. If a TransferLog or CustomLog directive
86 * appears in the VirtualHost section, the log files defined outside
87 * the VirtualHost will _not_ be used. This makes this module compatable
88 * with the CLF and config log modules, where the use of TransferLog
89 * inside the VirtualHost section overrides its use outside.
93 * TransferLog logs/access_log
95 * LogFormat "... custom format ..."
96 * TransferLog log/virtual_only
97 * CustomLog log/virtual_useragents "%t %{user-agent}i"
100 * This will log using CLF to access_log any requests handled by the
101 * main server, while any requests to the virtual host will be logged
102 * with the "... custom format..." to virtual_only _AND_ using
103 * the custom user-agent log to virtual_useragents.
105 * Note that the NCSA referer and user-agent logs are easily added with
107 * CustomLog logs/referer "%{referer}i -> %U"
108 * CustomLog logs/agent "%{user-agent}i"
110 * RefererIgnore functionality can be obtained with conditional
111 * logging (SetEnvIf and CustomLog ... env=!VAR).
113 * But using this method allows much easier modification of the
114 * log format, e.g. to log hosts along with UA:
115 * CustomLog logs/referer "%{referer}i %U %h"
117 * The argument to LogFormat and CustomLog is a string, which can include
118 * literal characters copied into the log files, and '%' directives as
121 * %...B: bytes sent, excluding HTTP headers.
122 * %...b: bytes sent, excluding HTTP headers in CLF format, i.e. a '-'
123 * when no bytes where sent (rather than a '0'.
124 * %...{FOOBAR}C: The contents of the HTTP cookie FOOBAR
125 * %...{FOOBAR}e: The contents of the environment variable FOOBAR
128 * %...a: remote IP-address
129 * %...A: local IP-address
130 * %...{Foobar}i: The contents of Foobar: header line(s) in the request
131 * sent to the client.
132 * %...l: remote logname (from identd, if supplied)
133 * %...{Foobar}n: The contents of note "Foobar" from another module.
134 * %...{Foobar}o: The contents of Foobar: header line(s) in the reply.
135 * %...p: the port the request was served to
136 * %...P: the process ID of the child that serviced the request.
137 * %...r: first line of request
138 * %...s: status. For requests that got internally redirected, this
139 * is status of the *original* request --- %...>s for the last.
140 * %...t: time, in common log format time format
141 * %...{format}t: The time, in the form given by format, which should
142 * be in strftime(3) format.
143 * %...T: the time taken to serve the request, in seconds.
144 * %...D: the time taken to serve the request, in micro seconds.
145 * %...u: remote user (from auth; may be bogus if return status (%s) is 401)
146 * %...U: the URL path requested.
147 * %...v: the configured name of the server (i.e. which virtual host?)
148 * %...V: the server name according to the UseCanonicalName setting
149 * %...m: the request method
150 * %...H: the request protocol
151 * %...q: the query string prepended by "?", or empty if no query string
152 * %...X: Status of the connection.
153 * 'X' = connection aborted before the response completed.
154 * '+' = connection may be kept alive after the response is sent.
155 * '-' = connection will be closed after the response is sent.
156 (This directive was %...c in late versions of Apache 1.3, but
157 this conflicted with the historical ssl %...{var}c syntax.)
159 * The '...' can be nothing at all (e.g. "%h %u %r %s %b"), or it can
160 * indicate conditions for inclusion of the item (which will cause it
161 * to be replaced with '-' if the condition is not met). Note that
162 * there is no escaping performed on the strings from %r, %...i and
163 * %...o; some with long memories may remember that I thought this was
164 * a bad idea, once upon a time, and I'm still not comfortable with
165 * it, but it is difficult to see how to "do the right thing" with all
166 * of '%..i', unless we URL-escape everything and break with CLF.
168 * The forms of condition are a list of HTTP status codes, which may
169 * or may not be preceded by '!'. Thus, '%400,501{User-agent}i' logs
170 * User-agent: on 400 errors and 501 errors (Bad Request, Not
171 * Implemented) only; '%!200,304,302{Referer}i' logs Referer: on all
172 * requests which did *not* return some sort of normal status.
174 * The default LogFormat reproduces CLF; see below.
176 * The way this is supposed to work with virtual hosts is as follows:
177 * a virtual host can have its own LogFormat, or its own TransferLog.
178 * If it doesn't have its own LogFormat, it inherits from the main
179 * server. If it doesn't have its own TransferLog, it writes to the
180 * same descriptor (meaning the same process for "| ...").
184 #include "apr_strings.h"
186 #include "apr_hash.h"
187 #include "apr_optional.h"
189 #define APR_WANT_STRFUNC
190 #include "apr_want.h"
192 #include "ap_config.h"
193 #include "mod_log_config.h"
195 #include "http_config.h"
196 #include "http_core.h" /* For REMOTE_NAME */
197 #include "http_log.h"
198 #include "http_protocol.h"
199 #include "util_time.h"
201 #if APR_HAVE_UNISTD_H
208 #define DEFAULT_LOG_FORMAT "%h %l %u %t \"%r\" %>s %b"
210 module AP_MODULE_DECLARE_DATA log_config_module;
212 static int xfer_flags = (APR_WRITE | APR_APPEND | APR_CREATE);
213 static apr_fileperms_t xfer_perms = APR_OS_DEFAULT;
214 static apr_hash_t *log_hash;
216 /* POSIX.1 defines PIPE_BUF as the maximum number of bytes that is
217 * guaranteed to be atomic when writing a pipe. And PIPE_BUF >= 512
218 * is guaranteed. So we'll just guess 512 in the event the system
219 * doesn't have this. Now, for file writes there is actually no limit,
220 * the entire write is atomic. Whether all systems implement this
221 * correctly is another question entirely ... so we'll just use PIPE_BUF
222 * because it's probably a good guess as to what is implemented correctly
226 #define LOG_BUFSIZE PIPE_BUF
228 #define LOG_BUFSIZE (512)
232 * multi_log_state is our per-(virtual)-server configuration. We store
233 * an array of the logs we are going to use, each of type config_log_state.
234 * If a default log format is given by LogFormat, store in default_format
235 * (backward compat. with mod_log_config). We also store for each virtual
236 * server a pointer to the logs specified for the main server, so that if this
237 * vhost has no logs defined, we can use the main server's logs instead.
239 * So, for the main server, config_logs contains a list of the log files
240 * and server_config_logs is empty. For a vhost, server_config_logs
241 * points to the same array as config_logs in the main server, and
242 * config_logs points to the array of logs defined inside this vhost,
243 * which might be empty.
247 const char *default_format_string;
248 apr_array_header_t *default_format;
249 apr_array_header_t *config_logs;
250 apr_array_header_t *server_config_logs;
251 apr_table_t *formats;
255 * config_log_state holds the status of a single log file. fname might
256 * be NULL, which means this module does no logging for this
257 * request. format might be NULL, in which case the default_format
258 * from the multi_log_state should be used, or if that is NULL as
259 * well, use the CLF. log_fd is NULL before the log file is opened and
260 * set to a valid fd after it is opened.
265 const char *format_string;
266 apr_array_header_t *format;
271 char outbuf[LOG_BUFSIZE];
277 * Note that many of these could have ap_sprintfs replaced with static buffers.
281 ap_log_handler_fn_t *func;
285 apr_array_header_t *conditions;
288 static char *format_integer(apr_pool_t *p, int i)
290 return apr_itoa(p, i);
293 static char *pfmt(apr_pool_t *p, int i)
299 return format_integer(p, i);
303 static const char *constant_item(request_rec *dummy, char *stuff)
308 static const char *log_remote_host(request_rec *r, char *a)
310 return ap_get_remote_host(r->connection, r->per_dir_config,
314 static const char *log_remote_address(request_rec *r, char *a)
316 return r->connection->remote_ip;
319 static const char *log_local_address(request_rec *r, char *a)
321 return r->connection->local_ip;
324 static const char *log_remote_logname(request_rec *r, char *a)
326 return ap_get_remote_logname(r);
329 static const char *log_remote_user(request_rec *r, char *a)
331 char *rvalue = r->user;
333 if (rvalue == NULL) {
336 else if (strlen(rvalue) == 0) {
342 static const char *log_request_line(request_rec *r, char *a)
344 /* NOTE: If the original request contained a password, we
345 * re-write the request line here to contain XXXXXX instead:
346 * (note the truncation before the protocol string for HTTP/0.9 requests)
347 * (note also that r->the_request contains the unmodified request)
349 return (r->parsed_uri.password) ? apr_pstrcat(r->pool, r->method, " ",
350 apr_uri_unparse(r->pool, &r->parsed_uri, 0),
351 r->assbackwards ? NULL : " ", r->protocol, NULL)
355 static const char *log_request_file(request_rec *r, char *a)
359 static const char *log_request_uri(request_rec *r, char *a)
363 static const char *log_request_method(request_rec *r, char *a)
367 static const char *log_request_protocol(request_rec *r, char *a)
371 static const char *log_request_query(request_rec *r, char *a)
373 return (r->args != NULL) ? apr_pstrcat(r->pool, "?", r->args, NULL)
376 static const char *log_status(request_rec *r, char *a)
378 return pfmt(r->pool, r->status);
381 static const char *clf_log_bytes_sent(request_rec *r, char *a)
383 if (!r->sent_bodyct) {
387 return apr_off_t_toa(r->pool, r->bytes_sent);
391 static const char *log_bytes_sent(request_rec *r, char *a)
393 if (!r->sent_bodyct) {
397 return apr_psprintf(r->pool, "%" APR_OFF_T_FMT, r->bytes_sent);
402 static const char *log_header_in(request_rec *r, char *a)
404 return apr_table_get(r->headers_in, a);
407 static const char *log_header_out(request_rec *r, char *a)
409 const char *cp = apr_table_get(r->headers_out, a);
410 if (!strcasecmp(a, "Content-type") && r->content_type) {
411 cp = ap_field_noparam(r->pool, r->content_type);
416 return apr_table_get(r->err_headers_out, a);
419 static const char *log_note(request_rec *r, char *a)
421 return apr_table_get(r->notes, a);
423 static const char *log_env_var(request_rec *r, char *a)
425 return apr_table_get(r->subprocess_env, a);
428 static const char *log_cookie(request_rec *r, char *a)
431 const char *start_cookie;
433 if ((cookies = apr_table_get(r->headers_in, "Cookie"))) {
434 if ((start_cookie = ap_strstr_c(cookies,a))) {
435 char *cookie, *end_cookie;
436 start_cookie += strlen(a) + 1; /* cookie_name + '=' */
437 cookie = apr_pstrdup(r->pool, start_cookie);
438 /* kill everything in cookie after ';' */
439 end_cookie = strchr(cookie, ';');
449 static const char *log_request_time(request_rec *r, char *a)
451 apr_exploded_time_t xt;
453 char tstr[MAX_STRING_LEN];
456 hi. i think getting the time again at the end of the request
457 just for logging is dumb. i know it's "required" for CLF.
458 folks writing log parsing tools don't realise that out of order
459 times have always been possible (consider what happens if one
460 process calculates the time to log, but then there's a context
461 switch before it writes and before that process is run again the
462 log rotation occurs) and they should just fix their tools rather
463 than force the server to pay extra cpu cycles. if you've got
464 a problem with this, you can set the define. -djg
466 #ifdef I_INSIST_ON_EXTRA_CYCLES_FOR_CLF_COMPLIANCE
467 ap_explode_recent_localtime(&xt, apr_time_now());
469 ap_explode_recent_localtime(&xt, r->request_time);
471 if (a && *a) { /* Custom format */
472 apr_strftime(tstr, &retcode, MAX_STRING_LEN, a, &xt);
474 else { /* CLF format */
487 apr_snprintf(tstr, sizeof(tstr), "[%02d/%s/%d:%02d:%02d:%02d %c%.2d%.2d]",
488 xt.tm_mday, apr_month_snames[xt.tm_mon], xt.tm_year+1900,
489 xt.tm_hour, xt.tm_min, xt.tm_sec,
490 sign, timz / (60*60), timz % (60*60));
493 return apr_pstrdup(r->pool, tstr);
496 static const char *log_request_duration(request_rec *r, char *a)
498 return apr_psprintf(r->pool, "%qd", (apr_time_now() - r->request_time)
502 static const char *log_request_duration_microseconds(request_rec *r, char *a)
504 return apr_psprintf(r->pool, "%qd", (apr_time_now() - r->request_time));
507 /* These next two routines use the canonical name:port so that log
508 * parsers don't need to duplicate all the vhost parsing crud.
510 static const char *log_virtual_host(request_rec *r, char *a)
512 return r->server->server_hostname;
515 static const char *log_server_port(request_rec *r, char *a)
517 return apr_psprintf(r->pool, "%u",
518 r->server->port ? r->server->port : ap_default_port(r));
521 /* This respects the setting of UseCanonicalName so that
522 * the dynamic mass virtual hosting trick works better.
524 static const char *log_server_name(request_rec *r, char *a)
526 return ap_get_server_name(r);
529 static const char *log_child_pid(request_rec *r, char *a)
531 return apr_psprintf(r->pool, "%ld", (long) getpid());
534 static const char *log_connection_status(request_rec *r, char *a)
536 if (r->connection->aborted)
539 if (r->connection->keepalive &&
540 (!r->server->keep_alive_max ||
541 (r->server->keep_alive_max - r->connection->keepalives) > 0)) {
547 /*****************************************************************
549 * Parsing the log format string
552 static char *parse_log_misc_string(apr_pool_t *p, log_format_item *it,
558 it->func = constant_item;
559 it->conditions = NULL;
562 while (*s && *s != '%') {
566 * This might allocate a few chars extra if there's a backslash
567 * escape in the format string.
569 it->arg = apr_palloc(p, s - *sa + 1);
573 while (*s && *s != '%') {
600 * Allow the loop to deal with this *s in the normal
601 * fashion so that it handles end of string etc.
614 static char *parse_log_item(apr_pool_t *p, log_format_item *it, const char **sa)
617 ap_log_handler *handler;
620 return parse_log_misc_string(p, it, sa);
624 it->condition_sense = 0;
625 it->conditions = NULL;
627 it->arg = ""; /* For safety's sake... */
635 it->condition_sense = !it->condition_sense;
654 it->arg = ap_getword(p, &s, '}');
668 while (apr_isdigit(*++s)) {
669 i = i * 10 + (*s) - '0';
671 if (!it->conditions) {
672 it->conditions = apr_array_make(p, 4, sizeof(int));
674 *(int *) apr_array_push(it->conditions) = i;
678 handler = (ap_log_handler *)apr_hash_get(log_hash, s++, 1);
684 return apr_pstrcat(p, "Unrecognized LogFormat directive %",
687 it->func = handler->func;
688 if (it->want_orig == -1) {
689 it->want_orig = handler->want_orig_default;
696 return "Ran off end of LogFormat parsing args to some directive";
699 static apr_array_header_t *parse_log_string(apr_pool_t *p, const char *s, const char **err)
701 apr_array_header_t *a = apr_array_make(p, 30, sizeof(log_format_item));
705 if ((res = parse_log_item(p, (log_format_item *) apr_array_push(a), &s))) {
712 parse_log_item(p, (log_format_item *) apr_array_push(a), &s);
716 /*****************************************************************
721 static const char *process_item(request_rec *r, request_rec *orig,
722 log_format_item *item)
726 /* First, see if we need to process this thing at all... */
728 if (item->conditions && item->conditions->nelts != 0) {
730 int *conds = (int *) item->conditions->elts;
733 for (i = 0; i < item->conditions->nelts; ++i) {
734 if (r->status == conds[i]) {
740 if ((item->condition_sense && in_list)
741 || (!item->condition_sense && !in_list)) {
746 /* We do. Do it... */
748 cp = (*item->func) (item->want_orig ? orig : r, item->arg);
749 return cp ? cp : "-";
753 static void flush_log(config_log_state *cls)
755 if (cls->outcnt && cls->log_fd != NULL) {
756 apr_file_write(cls->log_fd, cls->outbuf, &cls->outcnt);
762 static int config_log_transaction(request_rec *r, config_log_state *cls,
763 apr_array_header_t *default_format)
765 log_format_item *items;
772 apr_array_header_t *format;
775 if (cls->fname == NULL) {
780 * See if we've got any conditional envariable-controlled logging decisions
783 if (cls->condition_var != NULL) {
784 envar = cls->condition_var;
786 if (apr_table_get(r->subprocess_env, envar) == NULL) {
791 if (apr_table_get(r->subprocess_env, &envar[1]) != NULL) {
797 format = cls->format ? cls->format : default_format;
799 strs = apr_palloc(r->pool, sizeof(char *) * (format->nelts));
800 strl = apr_palloc(r->pool, sizeof(int) * (format->nelts));
801 items = (log_format_item *) format->elts;
811 for (i = 0; i < format->nelts; ++i) {
812 strs[i] = process_item(r, orig, &items[i]);
815 for (i = 0; i < format->nelts; ++i) {
816 len += strl[i] = strlen(strs[i]);
820 if (len + cls->outcnt > LOG_BUFSIZE) {
823 if (len >= LOG_BUFSIZE) {
826 str = apr_palloc(r->pool, len + 1);
827 for (i = 0, s = str; i < format->nelts; ++i) {
828 memcpy(s, strs[i], strl[i]);
832 apr_file_write(cls->log_fd, str, &w);
835 for (i = 0, s = &cls->outbuf[cls->outcnt]; i < format->nelts; ++i) {
836 memcpy(s, strs[i], strl[i]);
842 str = apr_palloc(r->pool, len + 1);
844 for (i = 0, s = str; i < format->nelts; ++i) {
845 memcpy(s, strs[i], strl[i]);
849 apr_file_write(cls->log_fd, str, &len);
855 static int multi_log_transaction(request_rec *r)
857 multi_log_state *mls = ap_get_module_config(r->server->module_config,
859 config_log_state *clsarray;
863 * Log this transaction..
865 if (mls->config_logs->nelts) {
866 clsarray = (config_log_state *) mls->config_logs->elts;
867 for (i = 0; i < mls->config_logs->nelts; ++i) {
868 config_log_state *cls = &clsarray[i];
870 config_log_transaction(r, cls, mls->default_format);
873 else if (mls->server_config_logs) {
874 clsarray = (config_log_state *) mls->server_config_logs->elts;
875 for (i = 0; i < mls->server_config_logs->nelts; ++i) {
876 config_log_state *cls = &clsarray[i];
878 config_log_transaction(r, cls, mls->default_format);
885 /*****************************************************************
890 static void *make_config_log_state(apr_pool_t *p, server_rec *s)
892 multi_log_state *mls;
894 mls = (multi_log_state *) apr_palloc(p, sizeof(multi_log_state));
895 mls->config_logs = apr_array_make(p, 1, sizeof(config_log_state));
896 mls->default_format_string = NULL;
897 mls->default_format = NULL;
898 mls->server_config_logs = NULL;
899 mls->formats = apr_table_make(p, 4);
900 apr_table_setn(mls->formats, "CLF", DEFAULT_LOG_FORMAT);
906 * Use the merger to simply add a pointer from the vhost log state
907 * to the log of logs specified for the non-vhost configuration. Make sure
908 * vhosts inherit any globally-defined format names.
911 static void *merge_config_log_state(apr_pool_t *p, void *basev, void *addv)
913 multi_log_state *base = (multi_log_state *) basev;
914 multi_log_state *add = (multi_log_state *) addv;
916 add->server_config_logs = base->config_logs;
917 if (!add->default_format) {
918 add->default_format_string = base->default_format_string;
919 add->default_format = base->default_format;
921 add->formats = apr_table_overlay(p, base->formats, add->formats);
927 * Set the default logfile format, or define a nickname for a format string.
929 static const char *log_format(cmd_parms *cmd, void *dummy, const char *fmt,
932 const char *err_string = NULL;
933 multi_log_state *mls = ap_get_module_config(cmd->server->module_config,
937 * If we were given two arguments, the second is a name to be given to the
938 * format. This syntax just defines the nickname - it doesn't actually
939 * make the format the default.
942 parse_log_string(cmd->pool, fmt, &err_string);
943 if (err_string == NULL) {
944 apr_table_setn(mls->formats, name, fmt);
948 mls->default_format_string = fmt;
949 mls->default_format = parse_log_string(cmd->pool, fmt, &err_string);
955 static const char *add_custom_log(cmd_parms *cmd, void *dummy, const char *fn,
956 const char *fmt, const char *envclause)
958 const char *err_string = NULL;
959 multi_log_state *mls = ap_get_module_config(cmd->server->module_config,
961 config_log_state *cls;
963 cls = (config_log_state *) apr_array_push(mls->config_logs);
964 cls->condition_var = NULL;
965 if (envclause != NULL) {
966 if (strncasecmp(envclause, "env=", 4) != 0) {
967 return "error in condition clause";
969 if ((envclause[4] == '\0')
970 || ((envclause[4] == '!') && (envclause[5] == '\0'))) {
971 return "missing environment variable name";
973 cls->condition_var = apr_pstrdup(cmd->pool, &envclause[4]);
977 cls->format_string = fmt;
982 cls->format = parse_log_string(cmd->pool, fmt, &err_string);
989 static const char *set_transfer_log(cmd_parms *cmd, void *dummy,
992 return add_custom_log(cmd, dummy, fn, NULL, NULL);
995 static const char *set_cookie_log(cmd_parms *cmd, void *dummy, const char *fn)
997 return add_custom_log(cmd, dummy, fn, "%{Cookie}n \"%r\" %t", NULL);
1000 static const command_rec config_log_cmds[] =
1002 AP_INIT_TAKE23("CustomLog", add_custom_log, NULL, RSRC_CONF,
1003 "a file name, a custom log format string or format name, "
1004 "and an optional \"env=\" clause (see docs)"),
1005 AP_INIT_TAKE1("TransferLog", set_transfer_log, NULL, RSRC_CONF,
1006 "the filename of the access log"),
1007 AP_INIT_TAKE12("LogFormat", log_format, NULL, RSRC_CONF,
1008 "a log format string (see docs) and an optional format name"),
1009 AP_INIT_TAKE1("CookieLog", set_cookie_log, NULL, RSRC_CONF,
1010 "the filename of the cookie log"),
1014 static config_log_state *open_config_log(server_rec *s, apr_pool_t *p,
1015 config_log_state *cls,
1016 apr_array_header_t *default_format)
1018 apr_status_t status;
1020 const char *userdata_key = "open_config_log";
1022 /* Skip opening the log the first time through. It's really
1023 * good to avoid starting the piped log process during preflight.
1025 apr_pool_userdata_get(&data, userdata_key, s->process->pool);
1027 apr_pool_userdata_setn((const void *)1, userdata_key,
1028 NULL, s->process->pool);
1029 /* If logging for the first time after a restart, keep going. */
1030 if (!ap_my_generation) {
1035 if (cls->log_fd != NULL) {
1036 return cls; /* virtual config shared w/main server */
1039 if (cls->fname == NULL) {
1040 return cls; /* Leave it NULL to decline. */
1043 if (*cls->fname == '|') {
1046 pl = ap_open_piped_log(p, cls->fname + 1);
1050 cls->log_fd = ap_piped_log_write_fd(pl);
1053 const char *fname = ap_server_root_relative(p, cls->fname);
1054 if ((status = apr_file_open(&cls->log_fd, fname, xfer_flags, xfer_perms, p))
1056 ap_log_error(APLOG_MARK, APLOG_ERR, status, s,
1057 "could not open transfer log file %s.", fname);
1060 apr_file_set_inherit(cls->log_fd);
1062 #ifdef BUFFERED_LOGS
1069 static config_log_state *open_multi_logs(server_rec *s, apr_pool_t *p)
1072 multi_log_state *mls = ap_get_module_config(s->module_config,
1073 &log_config_module);
1074 config_log_state *clsarray;
1078 if (mls->default_format_string) {
1079 format = apr_table_get(mls->formats, mls->default_format_string);
1081 mls->default_format = parse_log_string(p, format, &dummy);
1085 if (!mls->default_format) {
1086 mls->default_format = parse_log_string(p, DEFAULT_LOG_FORMAT, &dummy);
1089 if (mls->config_logs->nelts) {
1090 clsarray = (config_log_state *) mls->config_logs->elts;
1091 for (i = 0; i < mls->config_logs->nelts; ++i) {
1092 config_log_state *cls = &clsarray[i];
1094 if (cls->format_string) {
1095 format = apr_table_get(mls->formats, cls->format_string);
1097 cls->format = parse_log_string(p, format, &dummy);
1101 cls = open_config_log(s, p, cls, mls->default_format);
1104 else if (mls->server_config_logs) {
1105 clsarray = (config_log_state *) mls->server_config_logs->elts;
1106 for (i = 0; i < mls->server_config_logs->nelts; ++i) {
1107 config_log_state *cls = &clsarray[i];
1109 if (cls->format_string) {
1110 format = apr_table_get(mls->formats, cls->format_string);
1112 cls->format = parse_log_string(p, format, &dummy);
1116 cls = open_config_log(s, p, cls, mls->default_format);
1123 #ifdef BUFFERED_LOGS
1124 static apr_status_t flush_all_logs(void *data)
1126 server_rec *s = data;
1127 multi_log_state *mls;
1128 apr_array_header_t *log_list;
1129 config_log_state *clsarray;
1132 for (; s; s = s->next) {
1133 mls = ap_get_module_config(s->module_config, &log_config_module);
1135 if (mls->config_logs->nelts) {
1136 log_list = mls->config_logs;
1138 else if (mls->server_config_logs) {
1139 log_list = mls->server_config_logs;
1142 clsarray = (config_log_state *) log_list->elts;
1143 for (i = 0; i < log_list->nelts; ++i) {
1144 flush_log(&clsarray[i]);
1152 static int init_config_log(apr_pool_t *pc, apr_pool_t *p, apr_pool_t *pt, server_rec *s)
1154 /* First, do "physical" server, which gets default log fd and format
1155 * for the virtual servers, if they don't override...
1158 open_multi_logs(s, p);
1160 /* Then, virtual servers */
1162 for (s = s->next; s; s = s->next) {
1163 open_multi_logs(s, p);
1168 static void init_child(apr_pool_t *p, server_rec *s)
1170 #ifdef BUFFERED_LOGS
1171 /* Now register the last buffer flush with the cleanup engine */
1172 apr_pool_cleanup_register(p, s, flush_all_logs, flush_all_logs);
1176 static void ap_register_log_handler(apr_pool_t *p, char *tag,
1177 ap_log_handler_fn_t *handler, int def)
1179 ap_log_handler *log_struct = apr_palloc(p, sizeof(*log_struct));
1180 log_struct->func = handler;
1181 log_struct->want_orig_default = def;
1183 apr_hash_set(log_hash, tag, 1, (const void *)log_struct);
1186 static void log_pre_config(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp)
1188 static APR_OPTIONAL_FN_TYPE(ap_register_log_handler) *log_pfn_register;
1190 log_pfn_register = APR_RETRIEVE_OPTIONAL_FN(ap_register_log_handler);
1192 if (log_pfn_register) {
1193 log_pfn_register(p, "h", log_remote_host, 0);
1194 log_pfn_register(p, "a", log_remote_address, 0 );
1195 log_pfn_register(p, "A", log_local_address, 0 );
1196 log_pfn_register(p, "l", log_remote_logname, 0);
1197 log_pfn_register(p, "u", log_remote_user, 0);
1198 log_pfn_register(p, "t", log_request_time, 0);
1199 log_pfn_register(p, "f", log_request_file, 0);
1200 log_pfn_register(p, "b", clf_log_bytes_sent, 0);
1201 log_pfn_register(p, "B", log_bytes_sent, 0);
1202 log_pfn_register(p, "i", log_header_in, 0);
1203 log_pfn_register(p, "o", log_header_out, 0);
1204 log_pfn_register(p, "n", log_note, 0);
1205 log_pfn_register(p, "e", log_env_var, 0);
1206 log_pfn_register(p, "V", log_server_name, 0);
1207 log_pfn_register(p, "v", log_virtual_host, 0);
1208 log_pfn_register(p, "p", log_server_port, 0);
1209 log_pfn_register(p, "P", log_child_pid, 0);
1210 log_pfn_register(p, "H", log_request_protocol, 0);
1211 log_pfn_register(p, "m", log_request_method, 0);
1212 log_pfn_register(p, "q", log_request_query, 0);
1213 log_pfn_register(p, "X", log_connection_status, 0);
1214 log_pfn_register(p, "C", log_cookie, 0);
1215 log_pfn_register(p, "r", log_request_line, 1);
1216 log_pfn_register(p, "D", log_request_duration_microseconds, 1);
1217 log_pfn_register(p, "T", log_request_duration, 1);
1218 log_pfn_register(p, "U", log_request_uri, 1);
1219 log_pfn_register(p, "s", log_status, 1);
1223 static void register_hooks(apr_pool_t *p)
1225 ap_hook_pre_config(log_pre_config,NULL,NULL,APR_HOOK_REALLY_FIRST);
1226 ap_hook_child_init(init_child,NULL,NULL,APR_HOOK_MIDDLE);
1227 ap_hook_open_logs(init_config_log,NULL,NULL,APR_HOOK_MIDDLE);
1228 ap_hook_log_transaction(multi_log_transaction,NULL,NULL,APR_HOOK_MIDDLE);
1230 /* Init log_hash before we register the optional function. It is
1231 * possible for the optional function, ap_register_log_handler,
1232 * to be called before any other mod_log_config hooks are called.
1233 * As a policy, we should init everything required by an optional function
1234 * before calling APR_REGISTER_OPTIONAL_FN.
1236 log_hash = apr_hash_make(p);
1237 APR_REGISTER_OPTIONAL_FN(ap_register_log_handler);
1240 module AP_MODULE_DECLARE_DATA log_config_module =
1242 STANDARD20_MODULE_STUFF,
1243 NULL, /* create per-dir config */
1244 NULL, /* merge per-dir config */
1245 make_config_log_state, /* server config */
1246 merge_config_log_state, /* merge server config */
1247 config_log_cmds, /* command apr_table_t */
1248 register_hooks /* register hooks */