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 * %...c: Status of the connection.
125 * 'X' = connection aborted before the response completed.
126 * '+' = connection may be kept alive after the response is sent.
127 * '-' = connection will be closed after the response is sent.
128 * %...{FOOBAR}C: The contents of the HTTP cookie FOOBAR
129 * %...{FOOBAR}e: The contents of the environment variable FOOBAR
132 * %...a: remote IP-address
133 * %...A: local IP-address
134 * %...{Foobar}i: The contents of Foobar: header line(s) in the request
135 * sent to the client.
136 * %...l: remote logname (from identd, if supplied)
137 * %...{Foobar}n: The contents of note "Foobar" from another module.
138 * %...{Foobar}o: The contents of Foobar: header line(s) in the reply.
139 * %...p: the port the request was served to
140 * %...P: the process ID of the child that serviced the request.
141 * %...r: first line of request
142 * %...s: status. For requests that got internally redirected, this
143 * is status of the *original* request --- %...>s for the last.
144 * %...t: time, in common log format time format
145 * %...{format}t: The time, in the form given by format, which should
146 * be in strftime(3) format.
147 * %...T: the time taken to serve the request, in seconds.
148 * %...D: the time taken to serve the request, in micro seconds.
149 * %...u: remote user (from auth; may be bogus if return status (%s) is 401)
150 * %...U: the URL path requested.
151 * %...v: the configured name of the server (i.e. which virtual host?)
152 * %...V: the server name according to the UseCanonicalName setting
153 * %...m: the request method
154 * %...H: the request protocol
155 * %...q: the query string prepended by "?", or empty if no query string
157 * The '...' can be nothing at all (e.g. "%h %u %r %s %b"), or it can
158 * indicate conditions for inclusion of the item (which will cause it
159 * to be replaced with '-' if the condition is not met). Note that
160 * there is no escaping performed on the strings from %r, %...i and
161 * %...o; some with long memories may remember that I thought this was
162 * a bad idea, once upon a time, and I'm still not comfortable with
163 * it, but it is difficult to see how to "do the right thing" with all
164 * of '%..i', unless we URL-escape everything and break with CLF.
166 * The forms of condition are a list of HTTP status codes, which may
167 * or may not be preceded by '!'. Thus, '%400,501{User-agent}i' logs
168 * User-agent: on 400 errors and 501 errors (Bad Request, Not
169 * Implemented) only; '%!200,304,302{Referer}i' logs Referer: on all
170 * requests which did *not* return some sort of normal status.
172 * The default LogFormat reproduces CLF; see below.
174 * The way this is supposed to work with virtual hosts is as follows:
175 * a virtual host can have its own LogFormat, or its own TransferLog.
176 * If it doesn't have its own LogFormat, it inherits from the main
177 * server. If it doesn't have its own TransferLog, it writes to the
178 * same descriptor (meaning the same process for "| ...").
182 #include "apr_strings.h"
184 #include "apr_hash.h"
185 #include "apr_optional.h"
187 #define APR_WANT_STRFUNC
188 #include "apr_want.h"
190 #include "ap_config.h"
191 #include "mod_log_config.h"
193 #include "http_config.h"
194 #include "http_core.h" /* For REMOTE_NAME */
195 #include "http_log.h"
196 #include "http_protocol.h"
198 #if APR_HAVE_UNISTD_H
205 #define DEFAULT_LOG_FORMAT "%h %l %u %t \"%r\" %>s %b"
207 module AP_MODULE_DECLARE_DATA log_config_module;
209 static int xfer_flags = (APR_WRITE | APR_APPEND | APR_CREATE);
210 static apr_fileperms_t xfer_perms = APR_OS_DEFAULT;
211 static apr_hash_t *log_hash;
213 /* POSIX.1 defines PIPE_BUF as the maximum number of bytes that is
214 * guaranteed to be atomic when writing a pipe. And PIPE_BUF >= 512
215 * is guaranteed. So we'll just guess 512 in the event the system
216 * doesn't have this. Now, for file writes there is actually no limit,
217 * the entire write is atomic. Whether all systems implement this
218 * correctly is another question entirely ... so we'll just use PIPE_BUF
219 * because it's probably a good guess as to what is implemented correctly
223 #define LOG_BUFSIZE PIPE_BUF
225 #define LOG_BUFSIZE (512)
229 * multi_log_state is our per-(virtual)-server configuration. We store
230 * an array of the logs we are going to use, each of type config_log_state.
231 * If a default log format is given by LogFormat, store in default_format
232 * (backward compat. with mod_log_config). We also store for each virtual
233 * server a pointer to the logs specified for the main server, so that if this
234 * vhost has no logs defined, we can use the main server's logs instead.
236 * So, for the main server, config_logs contains a list of the log files
237 * and server_config_logs in empty. For a vhost, server_config_logs
238 * points to the same array as config_logs in the main server, and
239 * config_logs points to the array of logs defined inside this vhost,
240 * which might be empty.
244 const char *default_format_string;
245 apr_array_header_t *default_format;
246 apr_array_header_t *config_logs;
247 apr_array_header_t *server_config_logs;
248 apr_table_t *formats;
252 * config_log_state holds the status of a single log file. fname might
253 * be NULL, which means this module does no logging for this
254 * request. format might be NULL, in which case the default_format
255 * from the multi_log_state should be used, or if that is NULL as
256 * well, use the CLF. log_fd is NULL before the log file is opened and
257 * set to a valid fd after it is opened.
262 const char *format_string;
263 apr_array_header_t *format;
268 char outbuf[LOG_BUFSIZE];
274 * Note that many of these could have ap_sprintfs replaced with static buffers.
278 ap_log_handler_fn_t *func;
282 apr_array_header_t *conditions;
285 static char *format_integer(apr_pool_t *p, int i)
287 return apr_psprintf(p, "%d", i);
290 static char *pfmt(apr_pool_t *p, int i)
296 return format_integer(p, i);
300 static const char *constant_item(request_rec *dummy, char *stuff)
305 static const char *log_remote_host(request_rec *r, char *a)
307 return ap_get_remote_host(r->connection, r->per_dir_config,
311 static const char *log_remote_address(request_rec *r, char *a)
313 return r->connection->remote_ip;
316 static const char *log_local_address(request_rec *r, char *a)
318 return r->connection->local_ip;
321 static const char *log_remote_logname(request_rec *r, char *a)
323 return ap_get_remote_logname(r);
326 static const char *log_remote_user(request_rec *r, char *a)
328 char *rvalue = r->user;
330 if (rvalue == NULL) {
333 else if (strlen(rvalue) == 0) {
339 static const char *log_request_line(request_rec *r, char *a)
341 /* NOTE: If the original request contained a password, we
342 * re-write the request line here to contain XXXXXX instead:
343 * (note the truncation before the protocol string for HTTP/0.9 requests)
344 * (note also that r->the_request contains the unmodified request)
346 return (r->parsed_uri.password) ? apr_pstrcat(r->pool, r->method, " ",
347 ap_unparse_uri_components(r->pool, &r->parsed_uri, 0),
348 r->assbackwards ? NULL : " ", r->protocol, NULL)
352 static const char *log_request_file(request_rec *r, char *a)
356 static const char *log_request_uri(request_rec *r, char *a)
360 static const char *log_request_method(request_rec *r, char *a)
364 static const char *log_request_protocol(request_rec *r, char *a)
368 static const char *log_request_query(request_rec *r, char *a)
370 return (r->args != NULL) ? apr_pstrcat(r->pool, "?", r->args, NULL)
373 static const char *log_status(request_rec *r, char *a)
375 return pfmt(r->pool, r->status);
378 static const char *clf_log_bytes_sent(request_rec *r, char *a)
380 if (!r->sent_bodyct) {
384 return apr_psprintf(r->pool, "%ld", r->bytes_sent);
388 static const char *log_bytes_sent(request_rec *r, char *a)
390 if (!r->sent_bodyct) {
394 return apr_psprintf(r->pool, "%ld", r->bytes_sent);
399 static const char *log_header_in(request_rec *r, char *a)
401 return apr_table_get(r->headers_in, a);
404 static const char *log_header_out(request_rec *r, char *a)
406 const char *cp = apr_table_get(r->headers_out, a);
407 if (!strcasecmp(a, "Content-type") && r->content_type) {
408 cp = ap_field_noparam(r->pool, r->content_type);
413 return apr_table_get(r->err_headers_out, a);
416 static const char *log_note(request_rec *r, char *a)
418 return apr_table_get(r->notes, a);
420 static const char *log_env_var(request_rec *r, char *a)
422 return apr_table_get(r->subprocess_env, a);
425 static const char *log_cookie(request_rec *r, char *a)
428 const char *start_cookie;
430 if ((cookies = apr_table_get(r->headers_in, "Cookie"))) {
431 if ((start_cookie = ap_strstr_c(cookies,a))) {
432 char *cookie, *end_cookie;
433 start_cookie += strlen(a) + 1; /* cookie_name + '=' */
434 cookie = apr_pstrdup(r->pool, start_cookie);
435 /* kill everything in cookie after ';' */
436 end_cookie = strchr(cookie, ';');
446 static const char *log_request_time(request_rec *r, char *a)
448 apr_exploded_time_t xt;
450 char tstr[MAX_STRING_LEN];
453 hi. i think getting the time again at the end of the request
454 just for logging is dumb. i know it's "required" for CLF.
455 folks writing log parsing tools don't realise that out of order
456 times have always been possible (consider what happens if one
457 process calculates the time to log, but then there's a context
458 switch before it writes and before that process is run again the
459 log rotation occurs) and they should just fix their tools rather
460 than force the server to pay extra cpu cycles. if you've got
461 a problem with this, you can set the define. -djg
463 #ifdef I_INSIST_ON_EXTRA_CYCLES_FOR_CLF_COMPLIANCE
464 apr_explode_localtime(&xt, apr_time_now());
466 apr_explode_localtime(&xt, r->request_time);
468 if (a && *a) { /* Custom format */
469 apr_strftime(tstr, &retcode, MAX_STRING_LEN, a, &xt);
471 else { /* CLF format */
484 apr_snprintf(tstr, sizeof(tstr), "[%02d/%s/%d:%02d:%02d:%02d %c%.2d%.2d]",
485 xt.tm_mday, apr_month_snames[xt.tm_mon], xt.tm_year+1900,
486 xt.tm_hour, xt.tm_min, xt.tm_sec,
487 sign, timz / (60*60), timz % (60*60));
490 return apr_pstrdup(r->pool, tstr);
493 static const char *log_request_duration(request_rec *r, char *a)
495 return apr_psprintf(r->pool, "%qd", (apr_time_now() - r->request_time)
499 static const char *log_request_duration_microseconds(request_rec *r, char *a)
501 return apr_psprintf(r->pool, "%qd", (apr_time_now() - r->request_time));
504 /* These next two routines use the canonical name:port so that log
505 * parsers don't need to duplicate all the vhost parsing crud.
507 static const char *log_virtual_host(request_rec *r, char *a)
509 return r->server->server_hostname;
512 static const char *log_server_port(request_rec *r, char *a)
514 return apr_psprintf(r->pool, "%u",
515 r->server->port ? r->server->port : ap_default_port(r));
518 /* This respects the setting of UseCanonicalName so that
519 * the dynamic mass virtual hosting trick works better.
521 static const char *log_server_name(request_rec *r, char *a)
523 return ap_get_server_name(r);
526 static const char *log_child_pid(request_rec *r, char *a)
528 return apr_psprintf(r->pool, "%ld", (long) getpid());
531 static const char *log_connection_status(request_rec *r, char *a)
533 if (r->connection->aborted)
536 if ((r->connection->keepalive) &&
537 ((r->server->keep_alive_max - r->connection->keepalives) > 0)) {
543 /*****************************************************************
545 * Parsing the log format string
548 static char *parse_log_misc_string(apr_pool_t *p, log_format_item *it,
554 it->func = constant_item;
555 it->conditions = NULL;
558 while (*s && *s != '%') {
562 * This might allocate a few chars extra if there's a backslash
563 * escape in the format string.
565 it->arg = apr_palloc(p, s - *sa + 1);
569 while (*s && *s != '%') {
596 * Allow the loop to deal with this *s in the normal
597 * fashion so that it handles end of string etc.
610 static char *parse_log_item(apr_pool_t *p, log_format_item *it, const char **sa)
613 ap_log_handler *handler;
616 return parse_log_misc_string(p, it, sa);
620 it->condition_sense = 0;
621 it->conditions = NULL;
623 it->arg = ""; /* For safety's sake... */
631 it->condition_sense = !it->condition_sense;
650 it->arg = ap_getword(p, &s, '}');
664 while (apr_isdigit(*++s)) {
665 i = i * 10 + (*s) - '0';
667 if (!it->conditions) {
668 it->conditions = apr_array_make(p, 4, sizeof(int));
670 *(int *) apr_array_push(it->conditions) = i;
674 handler = (ap_log_handler *)apr_hash_get(log_hash, s++, 1);
680 return apr_pstrcat(p, "Unrecognized LogFormat directive %",
683 it->func = handler->func;
684 if (it->want_orig == -1) {
685 it->want_orig = handler->want_orig_default;
692 return "Ran off end of LogFormat parsing args to some directive";
695 static apr_array_header_t *parse_log_string(apr_pool_t *p, const char *s, const char **err)
697 apr_array_header_t *a = apr_array_make(p, 30, sizeof(log_format_item));
701 if ((res = parse_log_item(p, (log_format_item *) apr_array_push(a), &s))) {
708 parse_log_item(p, (log_format_item *) apr_array_push(a), &s);
712 /*****************************************************************
717 static const char *process_item(request_rec *r, request_rec *orig,
718 log_format_item *item)
722 /* First, see if we need to process this thing at all... */
724 if (item->conditions && item->conditions->nelts != 0) {
726 int *conds = (int *) item->conditions->elts;
729 for (i = 0; i < item->conditions->nelts; ++i) {
730 if (r->status == conds[i]) {
736 if ((item->condition_sense && in_list)
737 || (!item->condition_sense && !in_list)) {
742 /* We do. Do it... */
744 cp = (*item->func) (item->want_orig ? orig : r, item->arg);
745 return cp ? cp : "-";
749 static void flush_log(config_log_state *cls)
751 if (cls->outcnt && cls->log_fd != NULL) {
752 apr_file_write(cls->log_fd, cls->outbuf, &cls->outcnt);
758 static int config_log_transaction(request_rec *r, config_log_state *cls,
759 apr_array_header_t *default_format)
761 log_format_item *items;
768 apr_array_header_t *format;
771 if (cls->fname == NULL) {
776 * See if we've got any conditional envariable-controlled logging decisions
779 if (cls->condition_var != NULL) {
780 envar = cls->condition_var;
782 if (apr_table_get(r->subprocess_env, envar) == NULL) {
787 if (apr_table_get(r->subprocess_env, &envar[1]) != NULL) {
793 format = cls->format ? cls->format : default_format;
795 strs = apr_palloc(r->pool, sizeof(char *) * (format->nelts));
796 strl = apr_palloc(r->pool, sizeof(int) * (format->nelts));
797 items = (log_format_item *) format->elts;
807 for (i = 0; i < format->nelts; ++i) {
808 strs[i] = process_item(r, orig, &items[i]);
811 for (i = 0; i < format->nelts; ++i) {
812 len += strl[i] = strlen(strs[i]);
816 if (len + cls->outcnt > LOG_BUFSIZE) {
819 if (len >= LOG_BUFSIZE) {
822 str = apr_palloc(r->pool, len + 1);
823 for (i = 0, s = str; i < format->nelts; ++i) {
824 memcpy(s, strs[i], strl[i]);
828 apr_file_write(cls->log_fd, str, &w);
831 for (i = 0, s = &cls->outbuf[cls->outcnt]; i < format->nelts; ++i) {
832 memcpy(s, strs[i], strl[i]);
838 str = apr_palloc(r->pool, len + 1);
840 for (i = 0, s = str; i < format->nelts; ++i) {
841 memcpy(s, strs[i], strl[i]);
845 apr_file_write(cls->log_fd, str, &len);
851 static int multi_log_transaction(request_rec *r)
853 multi_log_state *mls = ap_get_module_config(r->server->module_config,
855 config_log_state *clsarray;
859 * Log this transaction..
861 if (mls->config_logs->nelts) {
862 clsarray = (config_log_state *) mls->config_logs->elts;
863 for (i = 0; i < mls->config_logs->nelts; ++i) {
864 config_log_state *cls = &clsarray[i];
866 config_log_transaction(r, cls, mls->default_format);
869 else if (mls->server_config_logs) {
870 clsarray = (config_log_state *) mls->server_config_logs->elts;
871 for (i = 0; i < mls->server_config_logs->nelts; ++i) {
872 config_log_state *cls = &clsarray[i];
874 config_log_transaction(r, cls, mls->default_format);
881 /*****************************************************************
886 static void *make_config_log_state(apr_pool_t *p, server_rec *s)
888 multi_log_state *mls;
890 mls = (multi_log_state *) apr_palloc(p, sizeof(multi_log_state));
891 mls->config_logs = apr_array_make(p, 1, sizeof(config_log_state));
892 mls->default_format_string = NULL;
893 mls->default_format = NULL;
894 mls->server_config_logs = NULL;
895 mls->formats = apr_table_make(p, 4);
896 apr_table_setn(mls->formats, "CLF", DEFAULT_LOG_FORMAT);
902 * Use the merger to simply add a pointer from the vhost log state
903 * to the log of logs specified for the non-vhost configuration. Make sure
904 * vhosts inherit any globally-defined format names.
907 static void *merge_config_log_state(apr_pool_t *p, void *basev, void *addv)
909 multi_log_state *base = (multi_log_state *) basev;
910 multi_log_state *add = (multi_log_state *) addv;
912 add->server_config_logs = base->config_logs;
913 if (!add->default_format) {
914 add->default_format_string = base->default_format_string;
915 add->default_format = base->default_format;
917 add->formats = apr_table_overlay(p, base->formats, add->formats);
923 * Set the default logfile format, or define a nickname for a format string.
925 static const char *log_format(cmd_parms *cmd, void *dummy, const char *fmt,
928 const char *err_string = NULL;
929 multi_log_state *mls = ap_get_module_config(cmd->server->module_config,
933 * If we were given two arguments, the second is a name to be given to the
934 * format. This syntax just defines the nickname - it doesn't actually
935 * make the format the default.
938 parse_log_string(cmd->pool, fmt, &err_string);
939 if (err_string == NULL) {
940 apr_table_setn(mls->formats, name, fmt);
944 mls->default_format_string = fmt;
945 mls->default_format = parse_log_string(cmd->pool, fmt, &err_string);
951 static const char *add_custom_log(cmd_parms *cmd, void *dummy, const char *fn,
952 const char *fmt, const char *envclause)
954 const char *err_string = NULL;
955 multi_log_state *mls = ap_get_module_config(cmd->server->module_config,
957 config_log_state *cls;
959 cls = (config_log_state *) apr_array_push(mls->config_logs);
960 cls->condition_var = NULL;
961 if (envclause != NULL) {
962 if (strncasecmp(envclause, "env=", 4) != 0) {
963 return "error in condition clause";
965 if ((envclause[4] == '\0')
966 || ((envclause[4] == '!') && (envclause[5] == '\0'))) {
967 return "missing environment variable name";
969 cls->condition_var = apr_pstrdup(cmd->pool, &envclause[4]);
973 cls->format_string = fmt;
978 cls->format = parse_log_string(cmd->pool, fmt, &err_string);
985 static const char *set_transfer_log(cmd_parms *cmd, void *dummy,
988 return add_custom_log(cmd, dummy, fn, NULL, NULL);
991 static const char *set_cookie_log(cmd_parms *cmd, void *dummy, const char *fn)
993 return add_custom_log(cmd, dummy, fn, "%{Cookie}n \"%r\" %t", NULL);
996 static const command_rec config_log_cmds[] =
998 AP_INIT_TAKE23("CustomLog", add_custom_log, NULL, RSRC_CONF,
999 "a file name, a custom log format string or format name, "
1000 "and an optional \"env=\" clause (see docs)"),
1001 AP_INIT_TAKE1("TransferLog", set_transfer_log, NULL, RSRC_CONF,
1002 "the filename of the access log"),
1003 AP_INIT_TAKE12("LogFormat", log_format, NULL, RSRC_CONF,
1004 "a log format string (see docs) and an optional format name"),
1005 AP_INIT_TAKE1("CookieLog", set_cookie_log, NULL, RSRC_CONF,
1006 "the filename of the cookie log"),
1010 static config_log_state *open_config_log(server_rec *s, apr_pool_t *p,
1011 config_log_state *cls,
1012 apr_array_header_t *default_format)
1014 apr_status_t status;
1016 if (cls->log_fd != NULL) {
1017 return cls; /* virtual config shared w/main server */
1020 if (cls->fname == NULL) {
1021 return cls; /* Leave it NULL to decline. */
1024 if (*cls->fname == '|') {
1027 pl = ap_open_piped_log(p, cls->fname + 1);
1031 cls->log_fd = ap_piped_log_write_fd(pl);
1034 const char *fname = ap_server_root_relative(p, cls->fname);
1035 if ((status = apr_file_open(&cls->log_fd, fname, xfer_flags, xfer_perms, p))
1037 ap_log_error(APLOG_MARK, APLOG_ERR, status, s,
1038 "could not open transfer log file %s.", fname);
1042 #ifdef BUFFERED_LOGS
1049 static config_log_state *open_multi_logs(server_rec *s, apr_pool_t *p)
1052 multi_log_state *mls = ap_get_module_config(s->module_config,
1053 &log_config_module);
1054 config_log_state *clsarray;
1058 if (mls->default_format_string) {
1059 format = apr_table_get(mls->formats, mls->default_format_string);
1061 mls->default_format = parse_log_string(p, format, &dummy);
1065 if (!mls->default_format) {
1066 mls->default_format = parse_log_string(p, DEFAULT_LOG_FORMAT, &dummy);
1069 if (mls->config_logs->nelts) {
1070 clsarray = (config_log_state *) mls->config_logs->elts;
1071 for (i = 0; i < mls->config_logs->nelts; ++i) {
1072 config_log_state *cls = &clsarray[i];
1074 if (cls->format_string) {
1075 format = apr_table_get(mls->formats, cls->format_string);
1077 cls->format = parse_log_string(p, format, &dummy);
1081 cls = open_config_log(s, p, cls, mls->default_format);
1084 else if (mls->server_config_logs) {
1085 clsarray = (config_log_state *) mls->server_config_logs->elts;
1086 for (i = 0; i < mls->server_config_logs->nelts; ++i) {
1087 config_log_state *cls = &clsarray[i];
1089 if (cls->format_string) {
1090 format = apr_table_get(mls->formats, cls->format_string);
1092 cls->format = parse_log_string(p, format, &dummy);
1096 cls = open_config_log(s, p, cls, mls->default_format);
1103 #ifdef BUFFERED_LOGS
1104 static apr_status_t flush_all_logs(void *data)
1106 server_rec *s = data;
1107 multi_log_state *mls;
1108 apr_array_header_t *log_list;
1109 config_log_state *clsarray;
1112 for (; s; s = s->next) {
1113 mls = ap_get_module_config(s->module_config, &log_config_module);
1115 if (mls->config_logs->nelts) {
1116 log_list = mls->config_logs;
1118 else if (mls->server_config_logs) {
1119 log_list = mls->server_config_logs;
1122 clsarray = (config_log_state *) log_list->elts;
1123 for (i = 0; i < log_list->nelts; ++i) {
1124 flush_log(&clsarray[i]);
1132 static void init_config_log(apr_pool_t *pc, apr_pool_t *p, apr_pool_t *pt, server_rec *s)
1134 /* First, do "physical" server, which gets default log fd and format
1135 * for the virtual servers, if they don't override...
1138 open_multi_logs(s, p);
1140 /* Then, virtual servers */
1142 for (s = s->next; s; s = s->next) {
1143 open_multi_logs(s, p);
1147 static void init_child(apr_pool_t *p, server_rec *s)
1149 #ifdef BUFFERED_LOGS
1150 /* Now register the last buffer flush with the cleanup engine */
1151 apr_pool_cleanup_register(p, s, flush_all_logs, flush_all_logs);
1155 static void ap_register_log_handler(apr_pool_t *p, char *tag,
1156 ap_log_handler_fn_t *handler, int def)
1158 ap_log_handler *log_struct = apr_palloc(p, sizeof(*log_struct));
1159 log_struct->func = handler;
1160 log_struct->want_orig_default = def;
1162 apr_hash_set(log_hash, tag, 1, (const void *)log_struct);
1165 static void log_pre_config(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp)
1167 static APR_OPTIONAL_FN_TYPE(ap_register_log_handler) *log_pfn_register;
1169 log_pfn_register = APR_RETRIEVE_OPTIONAL_FN(ap_register_log_handler);
1171 if (log_pfn_register) {
1172 log_pfn_register(p, "h", log_remote_host, 0);
1173 log_pfn_register(p, "a", log_remote_address, 0 );
1174 log_pfn_register(p, "A", log_local_address, 0 );
1175 log_pfn_register(p, "l", log_remote_logname, 0);
1176 log_pfn_register(p, "u", log_remote_user, 0);
1177 log_pfn_register(p, "t", log_request_time, 0);
1178 log_pfn_register(p, "f", log_request_file, 0);
1179 log_pfn_register(p, "b", clf_log_bytes_sent, 0);
1180 log_pfn_register(p, "B", log_bytes_sent, 0);
1181 log_pfn_register(p, "i", log_header_in, 0);
1182 log_pfn_register(p, "o", log_header_out, 0);
1183 log_pfn_register(p, "n", log_note, 0);
1184 log_pfn_register(p, "e", log_env_var, 0);
1185 log_pfn_register(p, "V", log_server_name, 0);
1186 log_pfn_register(p, "v", log_virtual_host, 0);
1187 log_pfn_register(p, "p", log_server_port, 0);
1188 log_pfn_register(p, "P", log_child_pid, 0);
1189 log_pfn_register(p, "H", log_request_protocol, 0);
1190 log_pfn_register(p, "m", log_request_method, 0);
1191 log_pfn_register(p, "q", log_request_query, 0);
1192 log_pfn_register(p, "c", log_connection_status, 0);
1193 log_pfn_register(p, "C", log_cookie, 0);
1194 log_pfn_register(p, "r", log_request_line, 1);
1195 log_pfn_register(p, "D", log_request_duration_microseconds, 1);
1196 log_pfn_register(p, "T", log_request_duration, 1);
1197 log_pfn_register(p, "U", log_request_uri, 1);
1198 log_pfn_register(p, "s", log_status, 1);
1202 static void register_hooks(apr_pool_t *p)
1204 ap_hook_pre_config(log_pre_config,NULL,NULL,APR_HOOK_REALLY_FIRST);
1205 ap_hook_child_init(init_child,NULL,NULL,APR_HOOK_MIDDLE);
1206 ap_hook_open_logs(init_config_log,NULL,NULL,APR_HOOK_MIDDLE);
1207 ap_hook_log_transaction(multi_log_transaction,NULL,NULL,APR_HOOK_MIDDLE);
1209 /* Init log_hash before we register the optional function. It is
1210 * possible for the optional function, ap_register_log_handler,
1211 * to be called before any other mod_log_config hooks are called.
1212 * As a policy, we should init everything required by an optional function
1213 * before calling APR_REGISTER_OPTIONAL_FN.
1215 log_hash = apr_hash_make(p);
1216 APR_REGISTER_OPTIONAL_FN(ap_register_log_handler);
1219 module AP_MODULE_DECLARE_DATA log_config_module =
1221 STANDARD20_MODULE_STUFF,
1222 NULL, /* create per-dir config */
1223 NULL, /* merge per-dir config */
1224 make_config_log_state, /* server config */
1225 merge_config_log_state, /* merge server config */
1226 config_log_cmds, /* command apr_table_t */
1227 register_hooks /* register hooks */