1 /* Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
18 * Modified by djm@va.pubnix.com:
19 * If no TransferLog is given explicitly, decline to log.
21 * This is module implements the TransferLog directive (same as the
22 * common log module), and additional directives, LogFormat and CustomLog.
27 * TransferLog fn Logs transfers to fn in standard log format, unless
28 * a custom format is set with LogFormat
29 * LogFormat format Set a log format from TransferLog files
31 * Log to file fn with format given by the format
34 * CookieLog fn For backwards compatability with old Cookie
35 * logging module - now deprecated.
37 * There can be any number of TransferLog and CustomLog
38 * commands. Each request will be logged to _ALL_ the
39 * named files, in the appropriate format.
41 * If no TransferLog or CustomLog directive appears in a VirtualHost,
42 * the request will be logged to the log file(s) defined outside
43 * the virtual host section. If a TransferLog or CustomLog directive
44 * appears in the VirtualHost section, the log files defined outside
45 * the VirtualHost will _not_ be used. This makes this module compatable
46 * with the CLF and config log modules, where the use of TransferLog
47 * inside the VirtualHost section overrides its use outside.
51 * TransferLog logs/access_log
53 * LogFormat "... custom format ..."
54 * TransferLog log/virtual_only
55 * CustomLog log/virtual_useragents "%t %{user-agent}i"
58 * This will log using CLF to access_log any requests handled by the
59 * main server, while any requests to the virtual host will be logged
60 * with the "... custom format..." to virtual_only _AND_ using
61 * the custom user-agent log to virtual_useragents.
63 * Note that the NCSA referer and user-agent logs are easily added with
65 * CustomLog logs/referer "%{referer}i -> %U"
66 * CustomLog logs/agent "%{user-agent}i"
68 * RefererIgnore functionality can be obtained with conditional
69 * logging (SetEnvIf and CustomLog ... env=!VAR).
71 * But using this method allows much easier modification of the
72 * log format, e.g. to log hosts along with UA:
73 * CustomLog logs/referer "%{referer}i %U %h"
75 * The argument to LogFormat and CustomLog is a string, which can include
76 * literal characters copied into the log files, and '%' directives as
79 * %...B: bytes sent, excluding HTTP headers.
80 * %...b: bytes sent, excluding HTTP headers in CLF format, i.e. a '-'
81 * when no bytes where sent (rather than a '0'.
82 * %...{FOOBAR}C: The contents of the HTTP cookie FOOBAR
83 * %...{FOOBAR}e: The contents of the environment variable FOOBAR
86 * %...a: remote IP-address
87 * %...A: local IP-address
88 * %...{Foobar}i: The contents of Foobar: header line(s) in the request
90 * %...l: remote logname (from identd, if supplied)
91 * %...{Foobar}n: The contents of note "Foobar" from another module.
92 * %...{Foobar}o: The contents of Foobar: header line(s) in the reply.
93 * %...p: the port the request was served to
94 * %...P: the process ID of the child that serviced the request.
95 * %...{format}P: the process ID or thread ID of the child/thread that
96 * serviced the request
97 * %...r: first line of request
98 * %...s: status. For requests that got internally redirected, this
99 * is status of the *original* request --- %...>s for the last.
100 * %...t: time, in common log format time format
101 * %...{format}t: The time, in the form given by format, which should
102 * be in strftime(3) format.
103 * %...T: the time taken to serve the request, in seconds.
104 * %...D: the time taken to serve the request, in micro seconds.
105 * %...u: remote user (from auth; may be bogus if return status (%s) is 401)
106 * %...U: the URL path requested.
107 * %...v: the configured name of the server (i.e. which virtual host?)
108 * %...V: the server name according to the UseCanonicalName setting
109 * %...m: the request method
110 * %...H: the request protocol
111 * %...q: the query string prepended by "?", or empty if no query string
112 * %...X: Status of the connection.
113 * 'X' = connection aborted before the response completed.
114 * '+' = connection may be kept alive after the response is sent.
115 * '-' = connection will be closed after the response is sent.
116 (This directive was %...c in late versions of Apache 1.3, but
117 this conflicted with the historical ssl %...{var}c syntax.)
119 * The '...' can be nothing at all (e.g. "%h %u %r %s %b"), or it can
120 * indicate conditions for inclusion of the item (which will cause it
121 * to be replaced with '-' if the condition is not met). Note that
122 * there is no escaping performed on the strings from %r, %...i and
123 * %...o; some with long memories may remember that I thought this was
124 * a bad idea, once upon a time, and I'm still not comfortable with
125 * it, but it is difficult to see how to "do the right thing" with all
126 * of '%..i', unless we URL-escape everything and break with CLF.
128 * The forms of condition are a list of HTTP status codes, which may
129 * or may not be preceded by '!'. Thus, '%400,501{User-agent}i' logs
130 * User-agent: on 400 errors and 501 errors (Bad Request, Not
131 * Implemented) only; '%!200,304,302{Referer}i' logs Referer: on all
132 * requests which did *not* return some sort of normal status.
134 * The default LogFormat reproduces CLF; see below.
136 * The way this is supposed to work with virtual hosts is as follows:
137 * a virtual host can have its own LogFormat, or its own TransferLog.
138 * If it doesn't have its own LogFormat, it inherits from the main
139 * server. If it doesn't have its own TransferLog, it writes to the
140 * same descriptor (meaning the same process for "| ...").
144 #include "apr_strings.h"
146 #include "apr_hash.h"
147 #include "apr_optional.h"
148 #include "apr_anylock.h"
150 #define APR_WANT_STRFUNC
151 #include "apr_want.h"
153 #include "ap_config.h"
154 #include "mod_log_config.h"
156 #include "http_config.h"
157 #include "http_core.h" /* For REMOTE_NAME */
158 #include "http_log.h"
159 #include "http_protocol.h"
160 #include "util_time.h"
163 #if APR_HAVE_UNISTD_H
170 #define DEFAULT_LOG_FORMAT "%h %l %u %t \"%r\" %>s %b"
172 module AP_MODULE_DECLARE_DATA log_config_module;
174 #ifndef APR_LARGEFILE
175 #define APR_LARGEFILE 0
178 static int xfer_flags = (APR_WRITE | APR_APPEND | APR_CREATE | APR_LARGEFILE);
179 static apr_fileperms_t xfer_perms = APR_OS_DEFAULT;
180 static apr_hash_t *log_hash;
181 static apr_status_t ap_default_log_writer(request_rec *r,
187 static apr_status_t ap_buffered_log_writer(request_rec *r,
193 static void *ap_default_log_writer_init(apr_pool_t *p, server_rec *s,
195 static void *ap_buffered_log_writer_init(apr_pool_t *p, server_rec *s,
198 static void ap_log_set_writer_init(ap_log_writer_init *handle);
199 static void ap_log_set_writer(ap_log_writer *handle);
200 static ap_log_writer *log_writer = ap_default_log_writer;
201 static ap_log_writer_init *log_writer_init = ap_default_log_writer_init;
202 static int buffered_logs = 0; /* default unbuffered */
203 static apr_array_header_t *all_buffered_logs = NULL;
205 /* POSIX.1 defines PIPE_BUF as the maximum number of bytes that is
206 * guaranteed to be atomic when writing a pipe. And PIPE_BUF >= 512
207 * is guaranteed. So we'll just guess 512 in the event the system
208 * doesn't have this. Now, for file writes there is actually no limit,
209 * the entire write is atomic. Whether all systems implement this
210 * correctly is another question entirely ... so we'll just use PIPE_BUF
211 * because it's probably a good guess as to what is implemented correctly
215 #define LOG_BUFSIZE PIPE_BUF
217 #define LOG_BUFSIZE (512)
221 * multi_log_state is our per-(virtual)-server configuration. We store
222 * an array of the logs we are going to use, each of type config_log_state.
223 * If a default log format is given by LogFormat, store in default_format
224 * (backward compat. with mod_log_config). We also store for each virtual
225 * server a pointer to the logs specified for the main server, so that if this
226 * vhost has no logs defined, we can use the main server's logs instead.
228 * So, for the main server, config_logs contains a list of the log files
229 * and server_config_logs is empty. For a vhost, server_config_logs
230 * points to the same array as config_logs in the main server, and
231 * config_logs points to the array of logs defined inside this vhost,
232 * which might be empty.
236 const char *default_format_string;
237 apr_array_header_t *default_format;
238 apr_array_header_t *config_logs;
239 apr_array_header_t *server_config_logs;
240 apr_table_t *formats;
244 * config_log_state holds the status of a single log file. fname might
245 * be NULL, which means this module does no logging for this
246 * request. format might be NULL, in which case the default_format
247 * from the multi_log_state should be used, or if that is NULL as
249 * log_writer is NULL before the log file is opened and is
250 * set to a opaque structure (usually a fd) after it is opened.
256 char outbuf[LOG_BUFSIZE];
262 const char *format_string;
263 apr_array_header_t *format;
270 * Note that many of these could have ap_sprintfs replaced with static buffers.
274 ap_log_handler_fn_t *func;
278 apr_array_header_t *conditions;
281 static char *format_integer(apr_pool_t *p, int i)
283 return apr_itoa(p, i);
286 static char *pfmt(apr_pool_t *p, int i)
292 return format_integer(p, i);
296 static const char *constant_item(request_rec *dummy, char *stuff)
301 static const char *log_remote_host(request_rec *r, char *a)
303 return ap_escape_logitem(r->pool, ap_get_remote_host(r->connection,
308 static const char *log_remote_address(request_rec *r, char *a)
310 return r->connection->remote_ip;
313 static const char *log_local_address(request_rec *r, char *a)
315 return r->connection->local_ip;
318 static const char *log_remote_logname(request_rec *r, char *a)
320 return ap_escape_logitem(r->pool, ap_get_remote_logname(r));
323 static const char *log_remote_user(request_rec *r, char *a)
325 char *rvalue = r->user;
327 if (rvalue == NULL) {
330 else if (strlen(rvalue) == 0) {
334 rvalue = ap_escape_logitem(r->pool, rvalue);
340 static const char *log_request_line(request_rec *r, char *a)
342 /* NOTE: If the original request contained a password, we
343 * re-write the request line here to contain XXXXXX instead:
344 * (note the truncation before the protocol string for HTTP/0.9 requests)
345 * (note also that r->the_request contains the unmodified request)
347 return ap_escape_logitem(r->pool,
348 (r->parsed_uri.password)
349 ? apr_pstrcat(r->pool, r->method, " ",
350 apr_uri_unparse(r->pool,
352 r->assbackwards ? NULL : " ",
357 static const char *log_request_file(request_rec *r, char *a)
359 return ap_escape_logitem(r->pool, r->filename);
361 static const char *log_request_uri(request_rec *r, char *a)
363 return ap_escape_logitem(r->pool, r->uri);
365 static const char *log_request_method(request_rec *r, char *a)
367 return ap_escape_logitem(r->pool, r->method);
369 static const char *log_request_protocol(request_rec *r, char *a)
371 return ap_escape_logitem(r->pool, r->protocol);
373 static const char *log_request_query(request_rec *r, char *a)
375 return (r->args) ? apr_pstrcat(r->pool, "?",
376 ap_escape_logitem(r->pool, r->args), NULL)
379 static const char *log_status(request_rec *r, char *a)
381 return pfmt(r->pool, r->status);
384 static const char *clf_log_bytes_sent(request_rec *r, char *a)
386 if (!r->sent_bodyct || !r->bytes_sent) {
390 return apr_off_t_toa(r->pool, r->bytes_sent);
394 static const char *log_bytes_sent(request_rec *r, char *a)
396 if (!r->sent_bodyct || !r->bytes_sent) {
400 return apr_psprintf(r->pool, "%" APR_OFF_T_FMT, r->bytes_sent);
405 static const char *log_header_in(request_rec *r, char *a)
407 return ap_escape_logitem(r->pool, apr_table_get(r->headers_in, a));
410 static APR_INLINE char *find_multiple_headers(apr_pool_t *pool,
411 const apr_table_t *table,
414 const apr_array_header_t *elts;
415 const apr_table_entry_t *t_elt;
416 const apr_table_entry_t *t_end;
424 elts = apr_table_elts(table);
430 t_elt = (const apr_table_entry_t *)elts->elts;
431 t_end = t_elt + elts->nelts;
433 result_list = rp = NULL;
436 if (!strcasecmp(t_elt->key, key)) {
438 result_list = rp = apr_palloc(pool, sizeof(*rp));
441 rp = rp->next = apr_palloc(pool, sizeof(*rp));
446 rp->value = t_elt->val;
447 rp->len = strlen(rp->value);
452 } while (t_elt < t_end);
455 char *result = apr_palloc(pool, len);
460 if (rp != result_list) {
464 memcpy(cp, rp->value, rp->len);
476 static const char *log_header_out(request_rec *r, char *a)
478 const char *cp = NULL;
480 if (!strcasecmp(a, "Content-type") && r->content_type) {
481 cp = ap_field_noparam(r->pool, r->content_type);
483 else if (!strcasecmp(a, "Set-Cookie")) {
484 cp = find_multiple_headers(r->pool, r->headers_out, a);
487 cp = apr_table_get(r->headers_out, a);
490 return ap_escape_logitem(r->pool, cp);
493 static const char *log_note(request_rec *r, char *a)
495 return ap_escape_logitem(r->pool, apr_table_get(r->notes, a));
497 static const char *log_env_var(request_rec *r, char *a)
499 return ap_escape_logitem(r->pool, apr_table_get(r->subprocess_env, a));
502 static const char *log_cookie(request_rec *r, char *a)
505 const char *start_cookie;
507 if ((cookies = apr_table_get(r->headers_in, "Cookie"))) {
508 if ((start_cookie = ap_strstr_c(cookies,a))) {
509 char *cookie, *end_cookie;
510 start_cookie += strlen(a) + 1; /* cookie_name + '=' */
511 cookie = apr_pstrdup(r->pool, start_cookie);
512 /* kill everything in cookie after ';' */
513 end_cookie = strchr(cookie, ';');
517 return ap_escape_logitem(r->pool, cookie);
523 static const char *log_request_time_custom(request_rec *r, char *a,
527 char tstr[MAX_STRING_LEN];
528 apr_strftime(tstr, &retcode, sizeof(tstr), a, xt);
529 return apr_pstrdup(r->pool, tstr);
532 #define DEFAULT_REQUEST_TIME_SIZE 32
535 char timestr[DEFAULT_REQUEST_TIME_SIZE];
537 } cached_request_time;
539 #define TIME_CACHE_SIZE 4
540 #define TIME_CACHE_MASK 3
541 static cached_request_time request_time_cache[TIME_CACHE_SIZE];
543 static const char *log_request_time(request_rec *r, char *a)
547 /* ### I think getting the time again at the end of the request
548 * just for logging is dumb. i know it's "required" for CLF.
549 * folks writing log parsing tools don't realise that out of order
550 * times have always been possible (consider what happens if one
551 * process calculates the time to log, but then there's a context
552 * switch before it writes and before that process is run again the
553 * log rotation occurs) and they should just fix their tools rather
554 * than force the server to pay extra cpu cycles. if you've got
555 * a problem with this, you can set the define. -djg
557 if (a && *a) { /* Custom format */
558 /* The custom time formatting uses a very large temp buffer
559 * on the stack. To avoid using so much stack space in the
560 * common case where we're not using a custom format, the code
561 * for the custom format in a separate function. (That's why
562 * log_request_time_custom is not inlined right here.)
564 #ifdef I_INSIST_ON_EXTRA_CYCLES_FOR_CLF_COMPLIANCE
565 ap_explode_recent_localtime(&xt, apr_time_now());
567 ap_explode_recent_localtime(&xt, r->request_time);
569 return log_request_time_custom(r, a, &xt);
571 else { /* CLF format */
572 /* This code uses the same technique as ap_explode_recent_localtime():
573 * optimistic caching with logic to detect and correct race conditions.
574 * See the comments in server/util_time.c for more information.
576 cached_request_time* cached_time = apr_palloc(r->pool,
577 sizeof(*cached_time));
578 #ifdef I_INSIST_ON_EXTRA_CYCLES_FOR_CLF_COMPLIANCE
579 apr_time_t request_time = apr_time_now();
581 apr_time_t request_time = r->request_time;
583 unsigned t_seconds = (unsigned)apr_time_sec(request_time);
584 unsigned i = t_seconds & TIME_CACHE_MASK;
585 memcpy(cached_time, &(request_time_cache[i]), sizeof(*cached_time));
586 if ((t_seconds != cached_time->t) ||
587 (t_seconds != cached_time->t_validate)) {
589 /* Invalid or old snapshot, so compute the proper time string
590 * and store it in the cache
595 ap_explode_recent_localtime(&xt, request_time);
604 cached_time->t = t_seconds;
605 apr_snprintf(cached_time->timestr, DEFAULT_REQUEST_TIME_SIZE,
606 "[%02d/%s/%d:%02d:%02d:%02d %c%.2d%.2d]",
607 xt.tm_mday, apr_month_snames[xt.tm_mon],
608 xt.tm_year+1900, xt.tm_hour, xt.tm_min, xt.tm_sec,
609 sign, timz / (60*60), (timz % (60*60)) / 60);
610 cached_time->t_validate = t_seconds;
611 memcpy(&(request_time_cache[i]), cached_time,
612 sizeof(*cached_time));
614 return cached_time->timestr;
618 static const char *log_request_duration(request_rec *r, char *a)
620 apr_time_t duration = apr_time_now() - r->request_time;
621 return apr_psprintf(r->pool, "%" APR_TIME_T_FMT, apr_time_sec(duration));
624 static const char *log_request_duration_microseconds(request_rec *r, char *a)
626 return apr_psprintf(r->pool, "%" APR_TIME_T_FMT,
627 (apr_time_now() - r->request_time));
630 /* These next two routines use the canonical name:port so that log
631 * parsers don't need to duplicate all the vhost parsing crud.
633 static const char *log_virtual_host(request_rec *r, char *a)
635 return ap_escape_logitem(r->pool, r->server->server_hostname);
638 static const char *log_server_port(request_rec *r, char *a)
640 return apr_psprintf(r->pool, "%u",
641 r->server->port ? r->server->port : ap_default_port(r));
644 /* This respects the setting of UseCanonicalName so that
645 * the dynamic mass virtual hosting trick works better.
647 static const char *log_server_name(request_rec *r, char *a)
649 return ap_escape_logitem(r->pool, ap_get_server_name(r));
652 static const char *log_pid_tid(request_rec *r, char *a)
654 if (*a == '\0' || !strcmp(a, "pid")) {
655 return apr_psprintf(r->pool, "%" APR_PID_T_FMT, getpid());
657 else if (!strcmp(a, "tid")) {
659 apr_os_thread_t tid = apr_os_thread_current();
661 int tid = 0; /* APR will format "0" anyway but an arg is needed */
663 return apr_psprintf(r->pool, "%pT", &tid);
669 static const char *log_connection_status(request_rec *r, char *a)
671 if (r->connection->aborted)
674 if (r->connection->keepalive == AP_CONN_KEEPALIVE &&
675 (!r->server->keep_alive_max ||
676 (r->server->keep_alive_max - r->connection->keepalives) > 0)) {
682 /*****************************************************************
684 * Parsing the log format string
687 static char *parse_log_misc_string(apr_pool_t *p, log_format_item *it,
693 it->func = constant_item;
694 it->conditions = NULL;
697 while (*s && *s != '%') {
701 * This might allocate a few chars extra if there's a backslash
702 * escape in the format string.
704 it->arg = apr_palloc(p, s - *sa + 1);
708 while (*s && *s != '%') {
735 * Allow the loop to deal with this *s in the normal
736 * fashion so that it handles end of string etc.
749 static char *parse_log_item(apr_pool_t *p, log_format_item *it, const char **sa)
752 ap_log_handler *handler;
755 return parse_log_misc_string(p, it, sa);
759 it->condition_sense = 0;
760 it->conditions = NULL;
764 it->func = constant_item;
771 it->arg = ""; /* For safety's sake... */
779 it->condition_sense = !it->condition_sense;
798 it->arg = ap_getword(p, &s, '}');
812 while (apr_isdigit(*++s)) {
813 i = i * 10 + (*s) - '0';
815 if (!it->conditions) {
816 it->conditions = apr_array_make(p, 4, sizeof(int));
818 *(int *) apr_array_push(it->conditions) = i;
822 handler = (ap_log_handler *)apr_hash_get(log_hash, s++, 1);
828 return apr_pstrcat(p, "Unrecognized LogFormat directive %",
831 it->func = handler->func;
832 if (it->want_orig == -1) {
833 it->want_orig = handler->want_orig_default;
840 return "Ran off end of LogFormat parsing args to some directive";
843 static apr_array_header_t *parse_log_string(apr_pool_t *p, const char *s, const char **err)
845 apr_array_header_t *a = apr_array_make(p, 30, sizeof(log_format_item));
849 if ((res = parse_log_item(p, (log_format_item *) apr_array_push(a), &s))) {
856 parse_log_item(p, (log_format_item *) apr_array_push(a), &s);
860 /*****************************************************************
865 static const char *process_item(request_rec *r, request_rec *orig,
866 log_format_item *item)
870 /* First, see if we need to process this thing at all... */
872 if (item->conditions && item->conditions->nelts != 0) {
874 int *conds = (int *) item->conditions->elts;
877 for (i = 0; i < item->conditions->nelts; ++i) {
878 if (r->status == conds[i]) {
884 if ((item->condition_sense && in_list)
885 || (!item->condition_sense && !in_list)) {
890 /* We do. Do it... */
892 cp = (*item->func) (item->want_orig ? orig : r, item->arg);
893 return cp ? cp : "-";
896 static void flush_log(buffered_log *buf)
898 if (buf->outcnt && buf->handle != NULL) {
899 apr_file_write(buf->handle, buf->outbuf, &buf->outcnt);
905 static int config_log_transaction(request_rec *r, config_log_state *cls,
906 apr_array_header_t *default_format)
908 log_format_item *items;
914 apr_array_header_t *format;
918 if (cls->fname == NULL) {
923 * See if we've got any conditional envariable-controlled logging decisions
926 if (cls->condition_var != NULL) {
927 envar = cls->condition_var;
929 if (apr_table_get(r->subprocess_env, envar) == NULL) {
934 if (apr_table_get(r->subprocess_env, &envar[1]) != NULL) {
940 format = cls->format ? cls->format : default_format;
942 strs = apr_palloc(r->pool, sizeof(char *) * (format->nelts));
943 strl = apr_palloc(r->pool, sizeof(int) * (format->nelts));
944 items = (log_format_item *) format->elts;
954 for (i = 0; i < format->nelts; ++i) {
955 strs[i] = process_item(r, orig, &items[i]);
958 for (i = 0; i < format->nelts; ++i) {
959 len += strl[i] = strlen(strs[i]);
962 ap_log_rerror(APLOG_MARK, APLOG_ERR, APR_EGENERAL, r,
963 "log writer isn't correctly setup");
964 return HTTP_INTERNAL_SERVER_ERROR;
966 rv = log_writer(r, cls->log_writer, strs, strl, format->nelts, len);
967 /* xxx: do we return an error on log_writer? */
971 static int multi_log_transaction(request_rec *r)
973 multi_log_state *mls = ap_get_module_config(r->server->module_config,
975 config_log_state *clsarray;
979 * Log this transaction..
981 if (mls->config_logs->nelts) {
982 clsarray = (config_log_state *) mls->config_logs->elts;
983 for (i = 0; i < mls->config_logs->nelts; ++i) {
984 config_log_state *cls = &clsarray[i];
986 config_log_transaction(r, cls, mls->default_format);
989 else if (mls->server_config_logs) {
990 clsarray = (config_log_state *) mls->server_config_logs->elts;
991 for (i = 0; i < mls->server_config_logs->nelts; ++i) {
992 config_log_state *cls = &clsarray[i];
994 config_log_transaction(r, cls, mls->default_format);
1001 /*****************************************************************
1006 static void *make_config_log_state(apr_pool_t *p, server_rec *s)
1008 multi_log_state *mls;
1010 mls = (multi_log_state *) apr_palloc(p, sizeof(multi_log_state));
1011 mls->config_logs = apr_array_make(p, 1, sizeof(config_log_state));
1012 mls->default_format_string = NULL;
1013 mls->default_format = NULL;
1014 mls->server_config_logs = NULL;
1015 mls->formats = apr_table_make(p, 4);
1016 apr_table_setn(mls->formats, "CLF", DEFAULT_LOG_FORMAT);
1022 * Use the merger to simply add a pointer from the vhost log state
1023 * to the log of logs specified for the non-vhost configuration. Make sure
1024 * vhosts inherit any globally-defined format names.
1027 static void *merge_config_log_state(apr_pool_t *p, void *basev, void *addv)
1029 multi_log_state *base = (multi_log_state *) basev;
1030 multi_log_state *add = (multi_log_state *) addv;
1032 add->server_config_logs = base->config_logs;
1033 if (!add->default_format) {
1034 add->default_format_string = base->default_format_string;
1035 add->default_format = base->default_format;
1037 add->formats = apr_table_overlay(p, base->formats, add->formats);
1043 * Set the default logfile format, or define a nickname for a format string.
1045 static const char *log_format(cmd_parms *cmd, void *dummy, const char *fmt,
1048 const char *err_string = NULL;
1049 multi_log_state *mls = ap_get_module_config(cmd->server->module_config,
1050 &log_config_module);
1053 * If we were given two arguments, the second is a name to be given to the
1054 * format. This syntax just defines the nickname - it doesn't actually
1055 * make the format the default.
1058 parse_log_string(cmd->pool, fmt, &err_string);
1059 if (err_string == NULL) {
1060 apr_table_setn(mls->formats, name, fmt);
1064 mls->default_format_string = fmt;
1065 mls->default_format = parse_log_string(cmd->pool, fmt, &err_string);
1071 static const char *add_custom_log(cmd_parms *cmd, void *dummy, const char *fn,
1072 const char *fmt, const char *envclause)
1074 const char *err_string = NULL;
1075 multi_log_state *mls = ap_get_module_config(cmd->server->module_config,
1076 &log_config_module);
1077 config_log_state *cls;
1079 cls = (config_log_state *) apr_array_push(mls->config_logs);
1080 cls->condition_var = NULL;
1081 if (envclause != NULL) {
1082 if (strncasecmp(envclause, "env=", 4) != 0) {
1083 return "error in condition clause";
1085 if ((envclause[4] == '\0')
1086 || ((envclause[4] == '!') && (envclause[5] == '\0'))) {
1087 return "missing environment variable name";
1089 cls->condition_var = apr_pstrdup(cmd->pool, &envclause[4]);
1093 cls->format_string = fmt;
1098 cls->format = parse_log_string(cmd->pool, fmt, &err_string);
1100 cls->log_writer = NULL;
1105 static const char *set_transfer_log(cmd_parms *cmd, void *dummy,
1108 return add_custom_log(cmd, dummy, fn, NULL, NULL);
1111 static const char *set_cookie_log(cmd_parms *cmd, void *dummy, const char *fn)
1113 return add_custom_log(cmd, dummy, fn, "%{Cookie}n \"%r\" %t", NULL);
1116 static const char *set_buffered_logs_on(cmd_parms *parms, void *dummy, int flag)
1118 buffered_logs = flag;
1119 if (buffered_logs) {
1120 ap_log_set_writer_init(ap_buffered_log_writer_init);
1121 ap_log_set_writer(ap_buffered_log_writer);
1125 static const command_rec config_log_cmds[] =
1127 AP_INIT_TAKE23("CustomLog", add_custom_log, NULL, RSRC_CONF,
1128 "a file name, a custom log format string or format name, "
1129 "and an optional \"env=\" clause (see docs)"),
1130 AP_INIT_TAKE1("TransferLog", set_transfer_log, NULL, RSRC_CONF,
1131 "the filename of the access log"),
1132 AP_INIT_TAKE12("LogFormat", log_format, NULL, RSRC_CONF,
1133 "a log format string (see docs) and an optional format name"),
1134 AP_INIT_TAKE1("CookieLog", set_cookie_log, NULL, RSRC_CONF,
1135 "the filename of the cookie log"),
1136 AP_INIT_FLAG("BufferedLogs", set_buffered_logs_on, NULL, RSRC_CONF,
1137 "Enable Buffered Logging (experimental)"),
1141 static config_log_state *open_config_log(server_rec *s, apr_pool_t *p,
1142 config_log_state *cls,
1143 apr_array_header_t *default_format)
1145 if (cls->log_writer != NULL) {
1146 return cls; /* virtual config shared w/main server */
1149 if (cls->fname == NULL) {
1150 return cls; /* Leave it NULL to decline. */
1153 cls->log_writer = log_writer_init(p, s, cls->fname);
1154 if (cls->log_writer == NULL)
1160 static int open_multi_logs(server_rec *s, apr_pool_t *p)
1163 multi_log_state *mls = ap_get_module_config(s->module_config,
1164 &log_config_module);
1165 config_log_state *clsarray;
1169 if (mls->default_format_string) {
1170 format = apr_table_get(mls->formats, mls->default_format_string);
1172 mls->default_format = parse_log_string(p, format, &dummy);
1176 if (!mls->default_format) {
1177 mls->default_format = parse_log_string(p, DEFAULT_LOG_FORMAT, &dummy);
1180 if (mls->config_logs->nelts) {
1181 clsarray = (config_log_state *) mls->config_logs->elts;
1182 for (i = 0; i < mls->config_logs->nelts; ++i) {
1183 config_log_state *cls = &clsarray[i];
1185 if (cls->format_string) {
1186 format = apr_table_get(mls->formats, cls->format_string);
1188 cls->format = parse_log_string(p, format, &dummy);
1192 if (!open_config_log(s, p, cls, mls->default_format)) {
1193 /* Failure already logged by open_config_log */
1198 else if (mls->server_config_logs) {
1199 clsarray = (config_log_state *) mls->server_config_logs->elts;
1200 for (i = 0; i < mls->server_config_logs->nelts; ++i) {
1201 config_log_state *cls = &clsarray[i];
1203 if (cls->format_string) {
1204 format = apr_table_get(mls->formats, cls->format_string);
1206 cls->format = parse_log_string(p, format, &dummy);
1210 if (!open_config_log(s, p, cls, mls->default_format)) {
1211 /* Failure already logged by open_config_log */
1221 static apr_status_t flush_all_logs(void *data)
1223 server_rec *s = data;
1224 multi_log_state *mls;
1225 apr_array_header_t *log_list;
1226 config_log_state *clsarray;
1233 for (; s; s = s->next) {
1234 mls = ap_get_module_config(s->module_config, &log_config_module);
1236 if (mls->config_logs->nelts) {
1237 log_list = mls->config_logs;
1239 else if (mls->server_config_logs) {
1240 log_list = mls->server_config_logs;
1243 clsarray = (config_log_state *) log_list->elts;
1244 for (i = 0; i < log_list->nelts; ++i) {
1245 buf = clsarray[i].log_writer;
1254 static int init_config_log(apr_pool_t *pc, apr_pool_t *p, apr_pool_t *pt, server_rec *s)
1258 /* First init the buffered logs array, which is needed when opening the logs. */
1259 if (buffered_logs) {
1260 all_buffered_logs = apr_array_make(p, 5, sizeof(buffered_log *));
1263 /* Next, do "physical" server, which gets default log fd and format
1264 * for the virtual servers, if they don't override...
1266 res = open_multi_logs(s, p);
1268 /* Then, virtual servers */
1270 for (s = s->next; (res == OK) && s; s = s->next) {
1271 res = open_multi_logs(s, p);
1277 static void init_child(apr_pool_t *p, server_rec *s)
1281 ap_mpm_query(AP_MPMQ_MAX_THREADS, &mpm_threads);
1283 /* Now register the last buffer flush with the cleanup engine */
1284 if (buffered_logs) {
1286 buffered_log **array = (buffered_log **)all_buffered_logs->elts;
1288 apr_pool_cleanup_register(p, s, flush_all_logs, flush_all_logs);
1290 for (i = 0; i < all_buffered_logs->nelts; i++) {
1291 buffered_log *this = array[i];
1294 if (mpm_threads > 1) {
1297 this->mutex.type = apr_anylock_threadmutex;
1298 rv = apr_thread_mutex_create(&this->mutex.lock.tm,
1299 APR_THREAD_MUTEX_DEFAULT,
1301 if (rv != APR_SUCCESS) {
1302 ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s,
1303 "could not initialize buffered log mutex, "
1304 "transfer log may become corrupted");
1305 this->mutex.type = apr_anylock_none;
1311 this->mutex.type = apr_anylock_none;
1317 static void ap_register_log_handler(apr_pool_t *p, char *tag,
1318 ap_log_handler_fn_t *handler, int def)
1320 ap_log_handler *log_struct = apr_palloc(p, sizeof(*log_struct));
1321 log_struct->func = handler;
1322 log_struct->want_orig_default = def;
1324 apr_hash_set(log_hash, tag, 1, (const void *)log_struct);
1326 static void ap_log_set_writer_init(ap_log_writer_init *handle)
1328 log_writer_init = handle;
1331 static void ap_log_set_writer(ap_log_writer *handle)
1333 log_writer = handle;
1336 static apr_status_t ap_default_log_writer( request_rec *r,
1349 str = apr_palloc(r->pool, len + 1);
1351 for (i = 0, s = str; i < nelts; ++i) {
1352 memcpy(s, strs[i], strl[i]);
1356 rv = apr_file_write((apr_file_t*)handle, str, &len);
1360 static void *ap_default_log_writer_init(apr_pool_t *p, server_rec *s,
1366 pl = ap_open_piped_log(p, name + 1);
1370 return ap_piped_log_write_fd(pl);
1373 const char *fname = ap_server_root_relative(p, name);
1378 ap_log_error(APLOG_MARK, APLOG_ERR, APR_EBADPATH, s,
1379 "invalid transfer log path %s.", name);
1382 rv = apr_file_open(&fd, fname, xfer_flags, xfer_perms, p);
1383 if (rv != APR_SUCCESS) {
1384 ap_log_error(APLOG_MARK, APLOG_ERR, rv, s,
1385 "could not open transfer log file %s.", fname);
1391 static void *ap_buffered_log_writer_init(apr_pool_t *p, server_rec *s,
1395 b = apr_pcalloc(p, sizeof(buffered_log));
1396 b->handle = ap_default_log_writer_init(p, s, name);
1399 *(buffered_log **)apr_array_push(all_buffered_logs) = b;
1405 static apr_status_t ap_buffered_log_writer(request_rec *r,
1417 buffered_log *buf = (buffered_log*)handle;
1419 if ((rv = APR_ANYLOCK_LOCK(&buf->mutex)) != APR_SUCCESS) {
1423 if (len + buf->outcnt > LOG_BUFSIZE) {
1426 if (len >= LOG_BUFSIZE) {
1429 str = apr_palloc(r->pool, len + 1);
1430 for (i = 0, s = str; i < nelts; ++i) {
1431 memcpy(s, strs[i], strl[i]);
1435 rv = apr_file_write(buf->handle, str, &w);
1439 for (i = 0, s = &buf->outbuf[buf->outcnt]; i < nelts; ++i) {
1440 memcpy(s, strs[i], strl[i]);
1447 APR_ANYLOCK_UNLOCK(&buf->mutex);
1451 static int log_pre_config(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp)
1453 static APR_OPTIONAL_FN_TYPE(ap_register_log_handler) *log_pfn_register;
1455 log_pfn_register = APR_RETRIEVE_OPTIONAL_FN(ap_register_log_handler);
1457 if (log_pfn_register) {
1458 log_pfn_register(p, "h", log_remote_host, 0);
1459 log_pfn_register(p, "a", log_remote_address, 0 );
1460 log_pfn_register(p, "A", log_local_address, 0 );
1461 log_pfn_register(p, "l", log_remote_logname, 0);
1462 log_pfn_register(p, "u", log_remote_user, 0);
1463 log_pfn_register(p, "t", log_request_time, 0);
1464 log_pfn_register(p, "f", log_request_file, 0);
1465 log_pfn_register(p, "b", clf_log_bytes_sent, 0);
1466 log_pfn_register(p, "B", log_bytes_sent, 0);
1467 log_pfn_register(p, "i", log_header_in, 0);
1468 log_pfn_register(p, "o", log_header_out, 0);
1469 log_pfn_register(p, "n", log_note, 0);
1470 log_pfn_register(p, "e", log_env_var, 0);
1471 log_pfn_register(p, "V", log_server_name, 0);
1472 log_pfn_register(p, "v", log_virtual_host, 0);
1473 log_pfn_register(p, "p", log_server_port, 0);
1474 log_pfn_register(p, "P", log_pid_tid, 0);
1475 log_pfn_register(p, "H", log_request_protocol, 0);
1476 log_pfn_register(p, "m", log_request_method, 0);
1477 log_pfn_register(p, "q", log_request_query, 0);
1478 log_pfn_register(p, "X", log_connection_status, 0);
1479 log_pfn_register(p, "C", log_cookie, 0);
1480 log_pfn_register(p, "r", log_request_line, 1);
1481 log_pfn_register(p, "D", log_request_duration_microseconds, 1);
1482 log_pfn_register(p, "T", log_request_duration, 1);
1483 log_pfn_register(p, "U", log_request_uri, 1);
1484 log_pfn_register(p, "s", log_status, 1);
1490 static void register_hooks(apr_pool_t *p)
1492 ap_hook_pre_config(log_pre_config,NULL,NULL,APR_HOOK_REALLY_FIRST);
1493 ap_hook_child_init(init_child,NULL,NULL,APR_HOOK_MIDDLE);
1494 ap_hook_open_logs(init_config_log,NULL,NULL,APR_HOOK_MIDDLE);
1495 ap_hook_log_transaction(multi_log_transaction,NULL,NULL,APR_HOOK_MIDDLE);
1497 /* Init log_hash before we register the optional function. It is
1498 * possible for the optional function, ap_register_log_handler,
1499 * to be called before any other mod_log_config hooks are called.
1500 * As a policy, we should init everything required by an optional function
1501 * before calling APR_REGISTER_OPTIONAL_FN.
1503 log_hash = apr_hash_make(p);
1504 APR_REGISTER_OPTIONAL_FN(ap_register_log_handler);
1505 APR_REGISTER_OPTIONAL_FN(ap_log_set_writer_init);
1506 APR_REGISTER_OPTIONAL_FN(ap_log_set_writer);
1509 module AP_MODULE_DECLARE_DATA log_config_module =
1511 STANDARD20_MODULE_STUFF,
1512 NULL, /* create per-dir config */
1513 NULL, /* merge per-dir config */
1514 make_config_log_state, /* server config */
1515 merge_config_log_state, /* merge server config */
1516 config_log_cmds, /* command apr_table_t */
1517 register_hooks /* register hooks */