Apache HTTPD
mod_log_config.c
Go to the documentation of this file.
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
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
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.
15 */
16
17/*
18 * Modified by [email protected]:
19 * If no TransferLog is given explicitly, decline to log.
20 *
21 * This is module implements the TransferLog directive (same as the
22 * common log module), and additional directives, LogFormat and CustomLog.
23 *
24 *
25 * Syntax:
26 *
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
30 * CustomLog fn format
31 * Log to file fn with format given by the format
32 * argument
33 *
34 * There can be any number of TransferLog and CustomLog
35 * commands. Each request will be logged to _ALL_ the
36 * named files, in the appropriate format.
37 *
38 * If no TransferLog or CustomLog directive appears in a VirtualHost,
39 * the request will be logged to the log file(s) defined outside
40 * the virtual host section. If a TransferLog or CustomLog directive
41 * appears in the VirtualHost section, the log files defined outside
42 * the VirtualHost will _not_ be used. This makes this module compatible
43 * with the CLF and config log modules, where the use of TransferLog
44 * inside the VirtualHost section overrides its use outside.
45 *
46 * Examples:
47 *
48 * TransferLog logs/access_log
49 * <VirtualHost>
50 * LogFormat "... custom format ..."
51 * TransferLog log/virtual_only
52 * CustomLog log/virtual_useragents "%t %{user-agent}i"
53 * </VirtualHost>
54 *
55 * This will log using CLF to access_log any requests handled by the
56 * main server, while any requests to the virtual host will be logged
57 * with the "... custom format..." to virtual_only _AND_ using
58 * the custom user-agent log to virtual_useragents.
59 *
60 * Note that the NCSA referer and user-agent logs are easily added with
61 * CustomLog:
62 * CustomLog logs/referer "%{referer}i -> %U"
63 * CustomLog logs/agent "%{user-agent}i"
64 *
65 * RefererIgnore functionality can be obtained with conditional
66 * logging (SetEnvIf and CustomLog ... env=!VAR).
67 *
68 * But using this method allows much easier modification of the
69 * log format, e.g. to log hosts along with UA:
70 * CustomLog logs/referer "%{referer}i %U %h"
71 *
72 * The argument to LogFormat and CustomLog is a string, which can include
73 * literal characters copied into the log files, and '%' directives as
74 * follows:
75 *
76 * %...B: bytes sent, excluding HTTP headers.
77 * %...b: bytes sent, excluding HTTP headers in CLF format, i.e. a '-'
78 * when no bytes where sent (rather than a '0'.
79 * %...{FOOBAR}C: The contents of the HTTP cookie FOOBAR
80 * %...{FOOBAR}e: The contents of the environment variable FOOBAR
81 * %...f: filename
82 * %...h: remote host
83 * %...a: remote IP-address
84 * %...A: local IP-address
85 * %...{Foobar}i: The contents of Foobar: header line(s) in the request
86 * sent to the client.
87 * %...k: number of keepalive requests served over this connection
88 * %...l: remote logname (from identd, if supplied)
89 * %...{Foobar}n: The contents of note "Foobar" from another module.
90 * %...{Foobar}o: The contents of Foobar: header line(s) in the reply.
91 * %...p: the canonical port for the server
92 * %...{format}p: the canonical port for the server, or the actual local
93 * or remote port
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 * %...{s}T: the time taken to serve the request, in seconds, same as %T.
105 * %...{us}T: the time taken to serve the request, in micro seconds, same as %D.
106 * %...{ms}T: the time taken to serve the request, in milliseconds.
107 * %...D: the time taken to serve the request, in micro seconds.
108 * %...u: remote user (from auth; may be bogus if return status (%s) is 401)
109 * %...U: the URL path requested.
110 * %...v: the configured name of the server (i.e. which virtual host?)
111 * %...V: the server name according to the UseCanonicalName setting
112 * %...m: the request method
113 * %...H: the request protocol
114 * %...q: the query string prepended by "?", or empty if no query string
115 * %...X: Status of the connection.
116 * 'X' = connection aborted before the response completed.
117 * '+' = connection may be kept alive after the response is sent.
118 * '-' = connection will be closed after the response is sent.
119 * (This directive was %...c in late versions of Apache 1.3, but
120 * this conflicted with the historical ssl %...{var}c syntax.)
121 * %...L: Log-Id of the Request (or '-' if none)
122 * %...{c}L: Log-Id of the Connection (or '-' if none)
123 *
124 * The '...' can be nothing at all (e.g. "%h %u %r %s %b"), or it can
125 * indicate conditions for inclusion of the item (which will cause it
126 * to be replaced with '-' if the condition is not met). Note that
127 * there is no escaping performed on the strings from %r, %...i and
128 * %...o; some with long memories may remember that I thought this was
129 * a bad idea, once upon a time, and I'm still not comfortable with
130 * it, but it is difficult to see how to "do the right thing" with all
131 * of '%..i', unless we URL-escape everything and break with CLF.
132 *
133 * The forms of condition are a list of HTTP status codes, which may
134 * or may not be preceded by '!'. Thus, '%400,501{User-agent}i' logs
135 * User-agent: on 400 errors and 501 errors (Bad Request, Not
136 * Implemented) only; '%!200,304,302{Referer}i' logs Referer: on all
137 * requests which did *not* return some sort of normal status.
138 *
139 * The default LogFormat reproduces CLF; see below.
140 *
141 * The way this is supposed to work with virtual hosts is as follows:
142 * a virtual host can have its own LogFormat, or its own TransferLog.
143 * If it doesn't have its own LogFormat, it inherits from the main
144 * server. If it doesn't have its own TransferLog, it writes to the
145 * same descriptor (meaning the same process for "| ...").
146 *
147 * --- rst */
148
149#include "apr_strings.h"
150#include "apr_lib.h"
151#include "apr_hash.h"
152#include "apr_optional.h"
153#include "apr_anylock.h"
154
155#define APR_WANT_STRFUNC
156#include "apr_want.h"
157
158#include "ap_config.h"
159#include "mod_log_config.h"
160#include "httpd.h"
161#include "http_config.h"
162#include "http_core.h" /* For REMOTE_NAME */
163#include "http_log.h"
164#include "http_protocol.h"
165#include "util_time.h"
166#include "ap_mpm.h"
167
168#if APR_HAVE_UNISTD_H
169#include <unistd.h>
170#endif
171#ifdef HAVE_LIMITS_H
172#include <limits.h>
173#endif
174
175#define DEFAULT_LOG_FORMAT "%h %l %u %t \"%r\" %>s %b"
176
177module AP_MODULE_DECLARE_DATA log_config_module;
178
179
184 void *handle,
185 const char **strs,
186 int *strl,
187 int nelts,
190 void *handle,
191 const char **strs,
192 int *strl,
193 int nelts,
196 const char* name);
198 const char* name);
199
204static int buffered_logs = 0; /* default unbuffered */
206
207/* POSIX.1 defines PIPE_BUF as the maximum number of bytes that is
208 * guaranteed to be atomic when writing a pipe. And PIPE_BUF >= 512
209 * is guaranteed. So we'll just guess 512 in the event the system
210 * doesn't have this. Now, for file writes there is actually no limit,
211 * the entire write is atomic. Whether all systems implement this
212 * correctly is another question entirely ... so we'll just use PIPE_BUF
213 * because it's probably a good guess as to what is implemented correctly
214 * everywhere.
215 */
216#ifdef PIPE_BUF
217#define LOG_BUFSIZE PIPE_BUF
218#else
219#define LOG_BUFSIZE (512)
220#endif
221
222/*
223 * multi_log_state is our per-(virtual)-server configuration. We store
224 * an array of the logs we are going to use, each of type config_log_state.
225 * If a default log format is given by LogFormat, store in default_format
226 * (backward compat. with mod_log_config). We also store for each virtual
227 * server a pointer to the logs specified for the main server, so that if this
228 * vhost has no logs defined, we can use the main server's logs instead.
229 *
230 * So, for the main server, config_logs contains a list of the log files
231 * and server_config_logs is empty. For a vhost, server_config_logs
232 * points to the same array as config_logs in the main server, and
233 * config_logs points to the array of logs defined inside this vhost,
234 * which might be empty.
235 */
236
244
245/*
246 * config_log_state holds the status of a single log file. fname might
247 * be NULL, which means this module does no logging for this
248 * request. format might be NULL, in which case the default_format
249 * from the multi_log_state should be used, or if that is NULL as
250 * well, use the CLF.
251 * log_writer is NULL before the log file is opened and is
252 * set to a opaque structure (usually a fd) after it is opened.
253
254 */
261
273
274/*
275 * log_request_state holds request specific log data that is not
276 * part of the request_rec.
277 */
281
282/*
283 * Format items...
284 * Note that many of these could have ap_sprintfs replaced with static buffers.
285 */
286
294
295static char *pfmt(apr_pool_t *p, int i)
296{
297 if (i <= 0) {
298 return "-";
299 }
300 else {
301 return apr_itoa(p, i);
302 }
303}
304
305static const char *constant_item(request_rec *dummy, char *stuff)
306{
307 return stuff;
308}
309
310static const char *log_remote_host(request_rec *r, char *a)
311{
312 const char *remote_host;
313 if (a && !strcmp(a, "c")) {
316 }
317 else {
318 remote_host = ap_get_useragent_host(r, REMOTE_NAME, NULL);
319 }
320 return ap_escape_logitem(r->pool, remote_host);
321}
322
323static const char *log_remote_address(request_rec *r, char *a)
324{
325 if (a && !strcmp(a, "c")) {
326 return r->connection->client_ip;
327 }
328 else {
329 return r->useragent_ip;
330 }
331}
332
333static const char *log_local_address(request_rec *r, char *a)
334{
335 return r->connection->local_ip;
336}
337
338static const char *log_remote_logname(request_rec *r, char *a)
339{
341}
342
343static const char *log_remote_user(request_rec *r, char *a)
344{
345 char *rvalue = r->user;
346
347 if (rvalue == NULL) {
348 rvalue = "-";
349 }
350 else if (strlen(rvalue) == 0) {
351 rvalue = "\"\"";
352 }
353 else {
355 }
356
357 return rvalue;
358}
359
360static const char *log_request_line(request_rec *r, char *a)
361{
362 /* NOTE: If the original request contained a password, we
363 * re-write the request line here to contain XXXXXX instead:
364 * (note the truncation before the protocol string for HTTP/0.9 requests)
365 * (note also that r->the_request contains the unmodified request)
366 */
367 return ap_escape_logitem(r->pool,
369 ? apr_pstrcat(r->pool, r->method, " ",
371 &r->parsed_uri, 0),
372 r->assbackwards ? NULL : " ",
373 r->protocol, NULL)
374 : r->the_request);
375}
376
377static const char *log_request_file(request_rec *r, char *a)
378{
379 return ap_escape_logitem(r->pool, r->filename);
380}
381static const char *log_request_uri(request_rec *r, char *a)
382{
383 return ap_escape_logitem(r->pool, r->uri);
384}
385static const char *log_request_method(request_rec *r, char *a)
386{
387 return ap_escape_logitem(r->pool, r->method);
388}
389static const char *log_log_id(request_rec *r, char *a)
390{
391 if (a && !strcmp(a, "c")) {
392 return r->connection->log_id ? r->connection->log_id : "-";
393 }
394 else {
395 return r->log_id ? r->log_id : "-";
396 }
397}
398static const char *log_request_protocol(request_rec *r, char *a)
399{
400 return ap_escape_logitem(r->pool, r->protocol);
401}
402static const char *log_request_query(request_rec *r, char *a)
403{
404 return (r->args) ? apr_pstrcat(r->pool, "?",
406 : "";
407}
408static const char *log_status(request_rec *r, char *a)
409{
410 return pfmt(r->pool, r->status);
411}
412
413static const char *log_handler(request_rec *r, char *a)
414{
415 return ap_escape_logitem(r->pool, r->handler);
416}
417
418static const char *clf_log_bytes_sent(request_rec *r, char *a)
419{
420 if (!r->sent_bodyct || !r->bytes_sent) {
421 return "-";
422 }
423 else {
424 return apr_off_t_toa(r->pool, r->bytes_sent);
425 }
426}
427
428static const char *log_bytes_sent(request_rec *r, char *a)
429{
430 if (!r->sent_bodyct || !r->bytes_sent) {
431 return "0";
432 }
433 else {
434 return apr_off_t_toa(r->pool, r->bytes_sent);
435 }
436}
437
438
439static const char *log_header_in(request_rec *r, char *a)
440{
442}
443
444static const char *log_trailer_in(request_rec *r, char *a)
445{
447}
448
449
451 const apr_table_t *table,
452 const char *key)
453{
454 const apr_array_header_t *elts;
458 struct sle {
459 struct sle *next;
460 const char *value;
462 } *result_list, *rp;
463
464 elts = apr_table_elts(table);
465
466 if (!elts->nelts) {
467 return NULL;
468 }
469
470 t_elt = (const apr_table_entry_t *)elts->elts;
471 t_end = t_elt + elts->nelts;
472 len = 1; /* \0 */
473 result_list = rp = NULL;
474
475 do {
476 if (!ap_cstr_casecmp(t_elt->key, key)) {
477 if (!result_list) {
478 result_list = rp = apr_palloc(pool, sizeof(*rp));
479 }
480 else {
481 rp = rp->next = apr_palloc(pool, sizeof(*rp));
482 len += 2; /* ", " */
483 }
484
485 rp->next = NULL;
486 rp->value = t_elt->val;
487 rp->len = strlen(rp->value);
488
489 len += rp->len;
490 }
491 ++t_elt;
492 } while (t_elt < t_end);
493
494 if (result_list) {
495 char *result = apr_palloc(pool, len);
496 char *cp = result;
497
498 rp = result_list;
499 while (rp) {
500 if (rp != result_list) {
501 *cp++ = ',';
502 *cp++ = ' ';
503 }
504 memcpy(cp, rp->value, rp->len);
505 cp += rp->len;
506 rp = rp->next;
507 }
508 *cp = '\0';
509
510 return result;
511 }
512
513 return NULL;
514}
515
516static const char *log_header_out(request_rec *r, char *a)
517{
518 const char *cp = NULL;
519
520 if (!ap_cstr_casecmp(a, "Content-type") && r->content_type) {
522 }
523 else if (!ap_cstr_casecmp(a, "Set-Cookie")) {
525 }
526 else {
528 }
529
530 return ap_escape_logitem(r->pool, cp);
531}
532
533static const char *log_trailer_out(request_rec *r, char *a)
534{
536}
537
538static const char *log_note(request_rec *r, char *a)
539{
541}
542static const char *log_env_var(request_rec *r, char *a)
543{
545}
546
547static const char *log_cookie(request_rec *r, char *a)
548{
549 const char *cookies_entry;
550
551 /*
552 * This supports Netscape version 0 cookies while being tolerant to
553 * some properties of RFC2109/2965 version 1 cookies:
554 * - case-insensitive match of cookie names
555 * - white space between the tokens
556 * It does not support the following version 1 features:
557 * - quoted strings as cookie values
558 * - commas to separate cookies
559 */
560
561 if ((cookies_entry = apr_table_get(r->headers_in, "Cookie"))) {
562 char *cookie, *last1, *last2;
564
565 while ((cookie = apr_strtok(cookies, ";", &last1))) {
566 char *name = apr_strtok(cookie, "=", &last2);
567 /* last2 points to the next char following an '=' delim,
568 or the trailing NUL char of the string */
569 char *value = last2;
570 if (name && *name && value && *value) {
571 char *last = value - 2;
572 /* Move past leading WS */
573 name += strspn(name, " \t");
574 while (last >= name && apr_isspace(*last)) {
575 *last = '\0';
576 --last;
577 }
578
579 if (!ap_cstr_casecmp(name, a)) {
580 /* last1 points to the next char following the ';' delim,
581 or the trailing NUL char of the string */
582 last = last1 - (*last1 ? 2 : 1);
583 /* Move past leading WS */
584 value += strspn(value, " \t");
585 while (last >= value && apr_isspace(*last)) {
586 *last = '\0';
587 --last;
588 }
589
590 return ap_escape_logitem(r->pool, value);
591 }
592 }
593 /* Iterate the remaining tokens using apr_strtok(NULL, ...) */
594 cookies = NULL;
595 }
596 }
597 return NULL;
598}
599
600static const char *log_request_time_custom(request_rec *r, char *a,
601 apr_time_exp_t *xt)
602{
604 char tstr[MAX_STRING_LEN];
605 apr_strftime(tstr, &retcode, sizeof(tstr), a, xt);
606 return apr_pstrdup(r->pool, tstr);
607}
608
609#define DEFAULT_REQUEST_TIME_SIZE 32
610typedef struct {
611 unsigned t;
613 unsigned t_validate;
615
616#define TIME_FMT_CUSTOM 0
617#define TIME_FMT_CLF 1
618#define TIME_FMT_ABS_SEC 2
619#define TIME_FMT_ABS_MSEC 3
620#define TIME_FMT_ABS_USEC 4
621#define TIME_FMT_ABS_MSEC_FRAC 5
622#define TIME_FMT_ABS_USEC_FRAC 6
623
624#define TIME_CACHE_SIZE 4
625#define TIME_CACHE_MASK 3
627
629{
631 &log_config_module);
632 if (!state) {
633 state = apr_pcalloc(r->pool, sizeof(log_request_state));
634 ap_set_module_config(r->request_config, &log_config_module, state);
635 }
636 if (state->request_end_time == 0) {
638 }
639 return state->request_end_time;
640}
641
642
643static const char *log_request_time(request_rec *r, char *a)
644{
646 apr_time_t request_time = r->request_time;
648 char *fmt = a;
649
650 if (fmt && *fmt) {
651 if (!strncmp(fmt, "begin", 5)) {
652 fmt += 5;
653 if (!*fmt) {
655 }
656 else if (*fmt == ':') {
657 fmt++;
658 a = fmt;
659 }
660 }
661 else if (!strncmp(fmt, "end", 3)) {
662 fmt += 3;
663 if (!*fmt) {
664 request_time = get_request_end_time(r);
666 }
667 else if (*fmt == ':') {
668 fmt++;
669 a = fmt;
670 request_time = get_request_end_time(r);
671 }
672 }
673 if (!strncmp(fmt, "msec", 4)) {
674 fmt += 4;
675 if (!*fmt) {
677 }
678 else if (!strcmp(fmt, "_frac")) {
680 }
681 }
682 else if (!strncmp(fmt, "usec", 4)) {
683 fmt += 4;
684 if (!*fmt) {
686 }
687 else if (!strcmp(fmt, "_frac")) {
689 }
690 }
691 else if (!strcmp(fmt, "sec")) {
693 }
694 else if (!*fmt) {
696 }
697 }
698 else {
700 }
701
702 if (fmt_type >= TIME_FMT_ABS_SEC) { /* Absolute (micro-/milli-)second time
703 * or msec/usec fraction
704 */
705 char* buf = apr_palloc(r->pool, 20);
706 switch (fmt_type) {
707 case TIME_FMT_ABS_SEC:
708 apr_snprintf(buf, 20, "%" APR_TIME_T_FMT, apr_time_sec(request_time));
709 break;
711 apr_snprintf(buf, 20, "%" APR_TIME_T_FMT, apr_time_as_msec(request_time));
712 break;
714 apr_snprintf(buf, 20, "%" APR_TIME_T_FMT, request_time);
715 break;
717 apr_snprintf(buf, 20, "%03" APR_TIME_T_FMT, apr_time_msec(request_time));
718 break;
720 apr_snprintf(buf, 20, "%06" APR_TIME_T_FMT, apr_time_usec(request_time));
721 break;
722 default:
723 return "-";
724 }
725 return buf;
726 }
727 else if (fmt_type == TIME_FMT_CUSTOM) { /* Custom format */
728 /* The custom time formatting uses a very large temp buffer
729 * on the stack. To avoid using so much stack space in the
730 * common case where we're not using a custom format, the code
731 * for the custom format in a separate function. (That's why
732 * log_request_time_custom is not inlined right here.)
733 */
734 ap_explode_recent_localtime(&xt, request_time);
735 return log_request_time_custom(r, a, &xt);
736 }
737 else { /* CLF format */
738 /* This code uses the same technique as ap_explode_recent_localtime():
739 * optimistic caching with logic to detect and correct race conditions.
740 * See the comments in server/util_time.c for more information.
741 */
743 sizeof(*cached_time));
744 unsigned t_seconds = (unsigned)apr_time_sec(request_time);
745 unsigned i = t_seconds & TIME_CACHE_MASK;
747 if ((t_seconds != cached_time->t) ||
748 (t_seconds != cached_time->t_validate)) {
749
750 /* Invalid or old snapshot, so compute the proper time string
751 * and store it in the cache
752 */
753 char sign;
754 int timz;
755
756 ap_explode_recent_localtime(&xt, request_time);
757 timz = xt.tm_gmtoff;
758 if (timz < 0) {
759 timz = -timz;
760 sign = '-';
761 }
762 else {
763 sign = '+';
764 }
767 "[%02d/%s/%d:%02d:%02d:%02d %c%.2d%.2d]",
769 xt.tm_year+1900, xt.tm_hour, xt.tm_min, xt.tm_sec,
770 sign, timz / (60*60), (timz % (60*60)) / 60);
771 cached_time->t_validate = t_seconds;
773 }
774 return cached_time->timestr;
775 }
776}
777
779{
780 return apr_psprintf(r->pool, "%" APR_TIME_T_FMT,
782}
783
784static const char *log_request_duration_scaled(request_rec *r, char *a)
785{
787 if (*a == '\0' || !strcasecmp(a, "s")) {
788 duration = apr_time_sec(duration);
789 }
790 else if (!strcasecmp(a, "ms")) {
791 duration = apr_time_as_msec(duration);
792 }
793 else if (!strcasecmp(a, "us")) {
794 }
795 else {
796 /* bogus format */
797 return a;
798 }
799 return apr_psprintf(r->pool, "%" APR_TIME_T_FMT, duration);
800}
801
802/* These next two routines use the canonical name:port so that log
803 * parsers don't need to duplicate all the vhost parsing crud.
804 */
805static const char *log_virtual_host(request_rec *r, char *a)
806{
808}
809
810static const char *log_server_port(request_rec *r, char *a)
811{
813
814 if (*a == '\0' || !strcasecmp(a, "canonical")) {
816 }
817 else if (!strcasecmp(a, "remote")) {
819 }
820 else if (!strcasecmp(a, "local")) {
822 }
823 else {
824 /* bogus format */
825 return a;
826 }
827 return apr_itoa(r->pool, (int)port);
828}
829
830/* This respects the setting of UseCanonicalName so that
831 * the dynamic mass virtual hosting trick works better.
832 */
833static const char *log_server_name(request_rec *r, char *a)
834{
836}
837
838static const char *log_pid_tid(request_rec *r, char *a)
839{
840 if (*a == '\0' || !strcasecmp(a, "pid")) {
841 return ap_append_pid(r->pool, "", "");
842 }
843 else if (!strcasecmp(a, "tid") || !strcasecmp(a, "hextid")) {
844#if APR_HAS_THREADS
846#else
847 int tid = 0; /* APR will format "0" anyway but an arg is needed */
848#endif
849 return apr_psprintf(r->pool,
850 /* APR can format a thread id in hex */
851 *a == 'h' ? "%pt" : "%pT", &tid);
852 }
853 /* bogus format */
854 return a;
855}
856
857static const char *log_connection_status(request_rec *r, char *a)
858{
859 if (r->connection->aborted)
860 return "X";
861
863 (!r->server->keep_alive_max ||
865 return "+";
866 }
867 return "-";
868}
869
870static const char *log_requests_on_connection(request_rec *r, char *a)
871{
872 int num = r->connection->keepalives ? r->connection->keepalives - 1 : 0;
873 return apr_itoa(r->pool, num);
874}
875
876/*****************************************************************
877 *
878 * Parsing the log format string
879 */
880
882 const char **sa)
883{
884 const char *s;
885 char *d;
886
887 it->func = constant_item;
888 it->conditions = NULL;
889
890 s = *sa;
891 while (*s && *s != '%') {
892 s++;
893 }
894 /*
895 * This might allocate a few chars extra if there's a backslash
896 * escape in the format string.
897 */
898 it->arg = apr_palloc(p, s - *sa + 1);
899
900 d = it->arg;
901 s = *sa;
902 while (*s && *s != '%') {
903 if (*s != '\\') {
904 *d++ = *s++;
905 }
906 else {
907 s++;
908 switch (*s) {
909 case '\\':
910 *d++ = '\\';
911 s++;
912 break;
913 case 'r':
914 *d++ = '\r';
915 s++;
916 break;
917 case 'n':
918 *d++ = '\n';
919 s++;
920 break;
921 case 't':
922 *d++ = '\t';
923 s++;
924 break;
925 default:
926 /* copy verbatim */
927 *d++ = '\\';
928 /*
929 * Allow the loop to deal with this *s in the normal
930 * fashion so that it handles end of string etc.
931 * properly.
932 */
933 break;
934 }
935 }
936 }
937 *d = '\0';
938
939 *sa = s;
940 return NULL;
941}
942
943static char *parse_log_item(apr_pool_t *p, log_format_item *it, const char **sa)
944{
945 const char *s = *sa;
946 ap_log_handler *handler = NULL;
947
948 if (*s != '%') {
949 return parse_log_misc_string(p, it, sa);
950 }
951
952 ++s;
953 it->condition_sense = 0;
954 it->conditions = NULL;
955
956 if (*s == '%') {
957 it->arg = "%";
958 it->func = constant_item;
959 *sa = ++s;
960
961 return NULL;
962 }
963
964 it->want_orig = -1;
965 it->arg = ""; /* For safety's sake... */
966
967 while (*s) {
968 int i;
969
970 switch (*s) {
971 case '!':
972 ++s;
973 it->condition_sense = !it->condition_sense;
974 break;
975
976 case '<':
977 ++s;
978 it->want_orig = 1;
979 break;
980
981 case '>':
982 ++s;
983 it->want_orig = 0;
984 break;
985
986 case ',':
987 ++s;
988 break;
989
990 case '{':
991 ++s;
992 it->arg = ap_getword(p, &s, '}');
993 break;
994
995 case '0':
996 case '1':
997 case '2':
998 case '3':
999 case '4':
1000 case '5':
1001 case '6':
1002 case '7':
1003 case '8':
1004 case '9':
1005 i = *s - '0';
1006 while (apr_isdigit(*++s)) {
1007 i = i * 10 + (*s) - '0';
1008 }
1009 if (!it->conditions) {
1010 it->conditions = apr_array_make(p, 4, sizeof(int));
1011 }
1012 *(int *) apr_array_push(it->conditions) = i;
1013 break;
1014
1015 default:
1016 /* check for '^' + two character format first */
1017 if (*s == '^' && *(s+1) && *(s+2)) {
1018 handler = (ap_log_handler *)apr_hash_get(log_hash, s, 3);
1019 if (handler) {
1020 s += 3;
1021 }
1022 }
1023 if (!handler) {
1024 handler = (ap_log_handler *)apr_hash_get(log_hash, s++, 1);
1025 }
1026 if (!handler) {
1027 char dummy[2];
1028
1029 dummy[0] = s[-1];
1030 dummy[1] = '\0';
1031 return apr_pstrcat(p, "Unrecognized LogFormat directive %",
1032 dummy, NULL);
1033 }
1034 it->func = handler->func;
1035 if (it->want_orig == -1) {
1036 it->want_orig = handler->want_orig_default;
1037 }
1038 *sa = s;
1039 return NULL;
1040 }
1041 }
1042
1043 return "Ran off end of LogFormat parsing args to some directive";
1044}
1045
1046static apr_array_header_t *parse_log_string(apr_pool_t *p, const char *s, const char **err)
1047{
1049 char *res;
1050
1051 while (*s) {
1053 *err = res;
1054 return NULL;
1055 }
1056 }
1057
1058 s = APR_EOL_STR;
1060 return a;
1061}
1062
1063/*****************************************************************
1064 *
1065 * Actually logging.
1066 */
1067
1070{
1071 const char *cp;
1072
1073 /* First, see if we need to process this thing at all... */
1074
1075 if (item->conditions && item->conditions->nelts != 0) {
1076 int i;
1077 int *conds = (int *) item->conditions->elts;
1078 int in_list = 0;
1079
1080 for (i = 0; i < item->conditions->nelts; ++i) {
1081 if (r->status == conds[i]) {
1082 in_list = 1;
1083 break;
1084 }
1085 }
1086
1087 if ((item->condition_sense && in_list)
1088 || (!item->condition_sense && !in_list)) {
1089 return "-";
1090 }
1091 }
1092
1093 /* We do. Do it... */
1094
1095 cp = (*item->func) (item->want_orig ? orig : r, item->arg);
1096 return cp ? cp : "-";
1097}
1098
1100{
1101 if (buf->outcnt && buf->handle != NULL) {
1102 /* XXX: error handling */
1103 apr_file_write_full(buf->handle, buf->outbuf, buf->outcnt, NULL);
1104 buf->outcnt = 0;
1105 }
1106}
1107
1108
1110 apr_array_header_t *default_format)
1111{
1113 const char **strs;
1114 int *strl;
1116 int i;
1117 apr_size_t len = 0;
1119 char *envar;
1120 apr_status_t rv;
1121
1122 if (cls->fname == NULL) {
1123 return DECLINED;
1124 }
1125
1126 /*
1127 * See if we've got any conditional envariable-controlled logging decisions
1128 * to make.
1129 */
1130 if (cls->condition_var != NULL) {
1131 envar = cls->condition_var;
1132 if (*envar != '!') {
1134 return DECLINED;
1135 }
1136 }
1137 else {
1138 if (apr_table_get(r->subprocess_env, &envar[1]) != NULL) {
1139 return DECLINED;
1140 }
1141 }
1142 }
1143 else if (cls->condition_expr != NULL) {
1144 const char *err;
1145 int rc = ap_expr_exec(r, cls->condition_expr, &err);
1146 if (rc < 0)
1148 "Error evaluating log condition: %s", err);
1149 if (rc <= 0)
1150 return DECLINED;
1151 }
1152
1153 format = cls->format ? cls->format : default_format;
1154
1155 strs = apr_palloc(r->pool, sizeof(char *) * (format->nelts));
1156 strl = apr_palloc(r->pool, sizeof(int) * (format->nelts));
1157 items = (log_format_item *) format->elts;
1158
1159 orig = r;
1160 while (orig->prev) {
1161 orig = orig->prev;
1162 }
1163 while (r->next) {
1164 r = r->next;
1165 }
1166
1167 for (i = 0; i < format->nelts; ++i) {
1168 strs[i] = process_item(r, orig, &items[i]);
1169 len += strl[i] = strlen(strs[i]);
1170 }
1171
1172 if (!log_writer) {
1174 "log writer isn't correctly setup");
1176 }
1177 rv = log_writer(r, cls->log_writer, strs, strl, format->nelts, len);
1178 if (rv != APR_SUCCESS) {
1180 "Error writing to %s", cls->fname);
1181 }
1182 return OK;
1183}
1184
1186{
1188 &log_config_module);
1190 int i;
1191
1192 /*
1193 * Initialize per request state
1194 */
1196 ap_set_module_config(r->request_config, &log_config_module, state);
1197
1198 /*
1199 * Log this transaction..
1200 */
1201 if (mls->config_logs->nelts) {
1202 clsarray = (config_log_state *) mls->config_logs->elts;
1203 for (i = 0; i < mls->config_logs->nelts; ++i) {
1205
1206 config_log_transaction(r, cls, mls->default_format);
1207 }
1208 }
1209
1210 if (mls->server_config_logs) {
1211 clsarray = (config_log_state *) mls->server_config_logs->elts;
1212 for (i = 0; i < mls->server_config_logs->nelts; ++i) {
1214
1215 if (cls->inherit || !mls->config_logs->nelts) {
1216 config_log_transaction(r, cls, mls->default_format);
1217 }
1218 }
1219 }
1220
1221 return OK;
1222}
1223
1224/*****************************************************************
1225 *
1226 * Module glue...
1227 */
1228
1230{
1232
1235 mls->default_format_string = NULL;
1236 mls->default_format = NULL;
1237 mls->server_config_logs = NULL;
1238 mls->formats = apr_table_make(p, 4);
1239 apr_table_setn(mls->formats, "CLF", DEFAULT_LOG_FORMAT);
1240
1241 return mls;
1242}
1243
1244/*
1245 * Use the merger to simply add a pointer from the vhost log state
1246 * to the log of logs specified for the non-vhost configuration. Make sure
1247 * vhosts inherit any globally-defined format names.
1248 */
1249
1250static void *merge_config_log_state(apr_pool_t *p, void *basev, void *addv)
1251{
1254
1255 add->server_config_logs = base->config_logs;
1256 if (!add->default_format) {
1257 add->default_format_string = base->default_format_string;
1258 add->default_format = base->default_format;
1259 }
1260 add->formats = apr_table_overlay(p, base->formats, add->formats);
1261
1262 return add;
1263}
1264
1265/*
1266 * Set the default logfile format, or define a nickname for a format string.
1267 */
1268static const char *log_format(cmd_parms *cmd, void *dummy, const char *fmt,
1269 const char *name)
1270{
1271 const char *err_string = NULL;
1272 multi_log_state *mls = ap_get_module_config(cmd->server->module_config,
1273 &log_config_module);
1274
1275 /*
1276 * If we were given two arguments, the second is a name to be given to the
1277 * format. This syntax just defines the nickname - it doesn't actually
1278 * make the format the default.
1279 */
1280 if (name != NULL) {
1282 if (err_string == NULL) {
1283 apr_table_setn(mls->formats, name, fmt);
1284 }
1285 }
1286 else {
1287 mls->default_format_string = fmt;
1288 mls->default_format = parse_log_string(cmd->pool, fmt, &err_string);
1289 }
1290 return err_string;
1291}
1292
1293
1294static const char *add_custom_log(cmd_parms *cmd, void *dummy, const char *fn,
1295 const char *fmt, const char *envclause)
1296{
1297 const char *err_string = NULL;
1298 multi_log_state *mls = ap_get_module_config(cmd->server->module_config,
1299 &log_config_module);
1301
1302 cls = (config_log_state *) apr_array_push(mls->config_logs);
1304 cls->condition_expr = NULL;
1305 if (envclause != NULL) {
1306 if (strncasecmp(envclause, "env=", 4) == 0) {
1307 if ((envclause[4] == '\0')
1308 || ((envclause[4] == '!') && (envclause[5] == '\0'))) {
1309 return "missing environment variable name";
1310 }
1311 cls->condition_var = apr_pstrdup(cmd->pool, &envclause[4]);
1312 }
1313 else if (strncasecmp(envclause, "expr=", 5) == 0) {
1314 const char *err;
1315 if ((envclause[5] == '\0'))
1316 return "missing condition";
1317 cls->condition_expr = ap_expr_parse_cmd(cmd, &envclause[5],
1319 &err, NULL);
1320 if (err)
1321 return err;
1322 }
1323 else {
1324 return "error in condition clause";
1325 }
1326 }
1327
1328 cls->fname = fn;
1329 cls->format_string = fmt;
1330 cls->directive = cmd->directive;
1331 if (fmt == NULL) {
1332 cls->format = NULL;
1333 }
1334 else {
1335 cls->format = parse_log_string(cmd->pool, fmt, &err_string);
1336 }
1337 cls->log_writer = NULL;
1338
1339 return err_string;
1340}
1341
1342static const char *add_global_log(cmd_parms *cmd, void *dummy, const char *fn,
1343 const char *fmt, const char *envclause) {
1344 multi_log_state *mls = ap_get_module_config(cmd->server->module_config,
1345 &log_config_module);
1348 const char *ret;
1349
1350 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
1351
1352 if (err) {
1353 return err;
1354 }
1355
1356 /* Add a custom log through the normal channel */
1358
1359 /* Set the inherit flag unless there was some error */
1360 if (ret == NULL) {
1361 clsarray = (config_log_state*)mls->config_logs->elts;
1362 cls = &clsarray[mls->config_logs->nelts-1];
1363 cls->inherit = 1;
1364 }
1365
1366 return ret;
1367}
1368
1369static const char *set_transfer_log(cmd_parms *cmd, void *dummy,
1370 const char *fn)
1371{
1372 return add_custom_log(cmd, dummy, fn, NULL, NULL);
1373}
1374
1389{
1391 "a file name, a custom log format string or format name, "
1392 "and an optional \"env=\" or \"expr=\" clause (see docs)"),
1394 "Same as CustomLog, but forces virtualhosts to inherit the log"),
1396 "the filename of the access log"),
1398 "a log format string (see docs) and an optional format name"),
1400 "Enable Buffered Logging (experimental)"),
1401 {NULL}
1402};
1403
1406 apr_array_header_t *default_format)
1407{
1408 if (cls->log_writer != NULL) {
1409 return cls; /* virtual config shared w/main server */
1410 }
1411
1412 if (cls->fname == NULL) {
1413 return cls; /* Leave it NULL to decline. */
1414 }
1415
1416 cls->log_writer = log_writer_init(p, s, cls->fname);
1417 if (cls->log_writer == NULL)
1418 return NULL;
1419
1420 return cls;
1421}
1422
1424{
1425 int i;
1426 multi_log_state *mls = ap_get_module_config(s->module_config,
1427 &log_config_module);
1429 const char *dummy;
1430 const char *format;
1431
1432 if (mls->default_format_string) {
1433 format = apr_table_get(mls->formats, mls->default_format_string);
1434 if (format) {
1435 mls->default_format = parse_log_string(p, format, &dummy);
1436 }
1437 }
1438
1439 if (!mls->default_format) {
1440 mls->default_format = parse_log_string(p, DEFAULT_LOG_FORMAT, &dummy);
1441 }
1442
1443 if (mls->config_logs->nelts) {
1444 clsarray = (config_log_state *) mls->config_logs->elts;
1445 for (i = 0; i < mls->config_logs->nelts; ++i) {
1447
1448 if (cls->format_string) {
1449 format = apr_table_get(mls->formats, cls->format_string);
1450 if (format) {
1451 cls->format = parse_log_string(p, format, &dummy);
1452 }
1453 }
1454
1455 if (!open_config_log(s, p, cls, mls->default_format)) {
1456 /* Failure already logged by open_config_log */
1457 return DONE;
1458 }
1459 }
1460 }
1461 else if (mls->server_config_logs) {
1462 clsarray = (config_log_state *) mls->server_config_logs->elts;
1463 for (i = 0; i < mls->server_config_logs->nelts; ++i) {
1465
1466 if (cls->format_string) {
1467 format = apr_table_get(mls->formats, cls->format_string);
1468 if (format) {
1469 cls->format = parse_log_string(p, format, &dummy);
1470 }
1471 }
1472
1473 if (!open_config_log(s, p, cls, mls->default_format)) {
1474 /* Failure already logged by open_config_log */
1475 return DONE;
1476 }
1477 }
1478 }
1479
1480 return OK;
1481}
1482
1483
1485{
1486 server_rec *s = data;
1491 int i;
1492
1493 if (!buffered_logs)
1494 return APR_SUCCESS;
1495
1496 for (; s; s = s->next) {
1497 mls = ap_get_module_config(s->module_config, &log_config_module);
1498 log_list = NULL;
1499 if (mls->config_logs->nelts) {
1500 log_list = mls->config_logs;
1501 }
1502 else if (mls->server_config_logs) {
1503 log_list = mls->server_config_logs;
1504 }
1505 if (log_list) {
1507 for (i = 0; i < log_list->nelts; ++i) {
1508 buf = clsarray[i].log_writer;
1509 flush_log(buf);
1510 }
1511 }
1512 }
1513 return APR_SUCCESS;
1514}
1515
1516
1518{
1519 int res;
1520
1521 /* First init the buffered logs array, which is needed when opening the logs. */
1522 if (buffered_logs) {
1524 }
1525
1526 /* Next, do "physical" server, which gets default log fd and format
1527 * for the virtual servers, if they don't override...
1528 */
1529 res = open_multi_logs(s, p);
1530
1531 /* Then, virtual servers */
1532
1533 for (s = s->next; (res == OK) && s; s = s->next) {
1534 res = open_multi_logs(s, p);
1535 }
1536
1537 return res;
1538}
1539
1541{
1542 int mpm_threads;
1543
1545
1546 /* Now register the last buffer flush with the cleanup engine */
1547 if (buffered_logs) {
1548 int i;
1550
1552
1553 for (i = 0; i < all_buffered_logs->nelts; i++) {
1554 buffered_log *this = array[i];
1555
1556#if APR_HAS_THREADS
1557 if (mpm_threads > 1) {
1558 apr_status_t rv;
1559
1560 this->mutex.type = apr_anylock_threadmutex;
1561 rv = apr_thread_mutex_create(&this->mutex.lock.tm,
1563 p);
1564 if (rv != APR_SUCCESS) {
1566 "could not initialize buffered log mutex, "
1567 "transfer log may become corrupted");
1568 this->mutex.type = apr_anylock_none;
1569 }
1570 }
1571 else
1572#endif
1573 {
1574 this->mutex.type = apr_anylock_none;
1575 }
1576 }
1577 }
1578}
1579
1581 ap_log_handler_fn_t *handler, int def)
1582{
1584 log_struct->func = handler;
1585 log_struct->want_orig_default = def;
1586
1587 apr_hash_set(log_hash, tag, strlen(tag), (const void *)log_struct);
1588}
1598{
1601
1602 return old;
1603}
1604
1606 void *handle,
1607 const char **strs,
1608 int *strl,
1609 int nelts,
1611
1612{
1613 char *str;
1614 char *s;
1615 int i;
1616 apr_status_t rv;
1617
1618 /*
1619 * We do this memcpy dance because write() is atomic for len < PIPE_BUF,
1620 * while writev() need not be.
1621 */
1622 str = apr_palloc(r->pool, len + 1);
1623
1624 for (i = 0, s = str; i < nelts; ++i) {
1625 memcpy(s, strs[i], strl[i]);
1626 s += strl[i];
1627 }
1628
1630
1631 return rv;
1632}
1634 const char* name)
1635{
1636 if (*name == '|') {
1637 piped_log *pl;
1638
1639 pl = ap_open_piped_log(p, name + 1);
1640 if (pl == NULL) {
1641 return NULL;
1642 }
1643 return ap_piped_log_write_fd(pl);
1644 }
1645 else {
1646 const char *fname = ap_server_root_relative(p, name);
1647 apr_file_t *fd;
1648 apr_status_t rv;
1649
1650 if (!fname) {
1652 "invalid transfer log path %s.", name);
1653 return NULL;
1654 }
1656 if (rv != APR_SUCCESS) {
1658 "could not open transfer log file %s.", fname);
1659 return NULL;
1660 }
1661 return fd;
1662 }
1663}
1665 const char* name)
1666{
1667 buffered_log *b;
1668 b = apr_pcalloc(p, sizeof(buffered_log));
1669 b->handle = ap_default_log_writer_init(p, s, name);
1670
1671 if (b->handle) {
1673 return b;
1674 }
1675 else
1676 return NULL;
1677}
1679 void *handle,
1680 const char **strs,
1681 int *strl,
1682 int nelts,
1684
1685{
1686 char *str;
1687 char *s;
1688 int i;
1689 apr_status_t rv;
1691
1692 if ((rv = APR_ANYLOCK_LOCK(&buf->mutex)) != APR_SUCCESS) {
1693 return rv;
1694 }
1695
1696 if (len + buf->outcnt > LOG_BUFSIZE) {
1697 flush_log(buf);
1698 }
1699 if (len >= LOG_BUFSIZE) {
1700 apr_size_t w;
1701
1702 /*
1703 * We do this memcpy dance because write() is atomic for
1704 * len < PIPE_BUF, while writev() need not be.
1705 */
1706 str = apr_palloc(r->pool, len + 1);
1707 for (i = 0, s = str; i < nelts; ++i) {
1708 memcpy(s, strs[i], strl[i]);
1709 s += strl[i];
1710 }
1711 w = len;
1712 rv = apr_file_write_full(buf->handle, str, w, NULL);
1713
1714 }
1715 else {
1716 for (i = 0, s = &buf->outbuf[buf->outcnt]; i < nelts; ++i) {
1717 memcpy(s, strs[i], strl[i]);
1718 s += strl[i];
1719 }
1720 buf->outcnt += len;
1721 rv = APR_SUCCESS;
1722 }
1723
1724 APR_ANYLOCK_UNLOCK(&buf->mutex);
1725 return rv;
1726}
1727
1729{
1731
1733
1734 if (log_pfn_register) {
1746 log_pfn_register(p, "n", log_note, 0);
1747 log_pfn_register(p, "L", log_log_id, 1);
1748 log_pfn_register(p, "e", log_env_var, 0);
1752 log_pfn_register(p, "P", log_pid_tid, 0);
1757 log_pfn_register(p, "C", log_cookie, 0);
1763 log_pfn_register(p, "s", log_status, 1);
1764 log_pfn_register(p, "R", log_handler, 1);
1765
1766 log_pfn_register(p, "^ti", log_trailer_in, 0);
1768 }
1769
1770 /* reset to default conditions */
1773 buffered_logs = 0;
1774
1775 return OK;
1776}
1777
1779{
1780 if (!cls->fname || cls->fname[0] == '|' || !cls->directive) {
1781 return OK;
1782 }
1783 else {
1784 char *abs = ap_server_root_relative(p, cls->fname);
1785 char *dir = ap_make_dirstr_parent(p, abs);
1786 apr_finfo_t finfo;
1787 const ap_directive_t *directive = cls->directive;
1788 apr_status_t rv = apr_stat(&finfo, dir, APR_FINFO_TYPE, p);
1789 cls->directive = NULL; /* Don't check this config_log_state again */
1790 if (rv == APR_SUCCESS && finfo.filetype != APR_DIR)
1791 rv = APR_ENOTDIR;
1792 if (rv != APR_SUCCESS) {
1794 APLOGNO(02297)
1795 "Cannot access directory '%s' for log file '%s' "
1796 "defined at %s:%d", dir, cls->fname,
1797 directive->filename, directive->line_num);
1798 return !OK;
1799 }
1800 }
1801 return OK;
1802}
1803
1805{
1806 int rv = OK;
1807 while (s) {
1808 multi_log_state *mls = ap_get_module_config(s->module_config,
1809 &log_config_module);
1810 /*
1811 * We don't need to check mls->server_config_logs because it just
1812 * points to the parent server's mls->config_logs.
1813 */
1814 apr_array_header_t *log_list = mls->config_logs;
1816 int i;
1817 for (i = 0; i < log_list->nelts; ++i) {
1818 if (check_log_dir(ptemp, s, &clsarray[i]) != OK)
1819 rv = !OK;
1820 }
1821
1822 s = s->next;
1823 }
1824 return rv;
1825}
1826
1828{
1834
1835 /* Init log_hash before we register the optional function. It is
1836 * possible for the optional function, ap_register_log_handler,
1837 * to be called before any other mod_log_config hooks are called.
1838 * As a policy, we should init everything required by an optional function
1839 * before calling APR_REGISTER_OPTIONAL_FN.
1840 */
1845}
1846
1848{
1850 NULL, /* create per-dir config */
1851 NULL, /* merge per-dir config */
1852 make_config_log_state, /* server config */
1853 merge_config_log_state, /* merge server config */
1854 config_log_cmds, /* command apr_table_t */
1855 register_hooks /* register hooks */
1856};
1857
Symbol export macros and hook functions.
Apache Multi-Processing Module library.
const char apr_size_t len
Definition ap_regex.h:187
APR-Util transparent any lock flavor wrapper.
#define APR_ANYLOCK_UNLOCK(lck)
#define APR_ANYLOCK_LOCK(lck)
Definition apr_anylock.h:66
APR Hash Tables.
APR general purpose library routines.
APR-UTIL registration of functions exported by modules.
apr_size_t const unsigned char unsigned int unsigned int d
Definition apr_siphash.h:72
APR Strings library.
APR Standard Headers Support.
static apr_pool_t * pconf
Definition event.c:441
#define AP_INIT_TAKE1(directive, func, mconfig, where, help)
#define ap_get_module_config(v, m)
#define AP_DECLARE_MODULE(foo)
#define AP_INIT_FLAG(directive, func, mconfig, where, help)
void ap_hook_open_logs(ap_HOOK_open_logs_t *pf, const char *const *aszPre, const char *const *aszSucc, int nOrder)
Definition config.c:163
ap_conf_vector_t * base
void ap_hook_check_config(ap_HOOK_check_config_t *pf, const char *const *aszPre, const char *const *aszSucc, int nOrder)
Definition config.c:96
char * ap_server_root_relative(apr_pool_t *p, const char *fname)
Definition config.c:1594
#define ap_set_module_config(v, m, val)
void ap_hook_pre_config(ap_HOOK_pre_config_t *pf, const char *const *aszPre, const char *const *aszSucc, int nOrder)
Definition config.c:91
#define AP_INIT_TAKE12(directive, func, mconfig, where, help)
request_rec * r
void ap_hook_child_init(ap_HOOK_child_init_t *pf, const char *const *aszPre, const char *const *aszSucc, int nOrder)
Definition config.c:167
#define AP_INIT_TAKE23(directive, func, mconfig, where, help)
#define ap_default_port(r)
Definition httpd.h:292
#define MAX_STRING_LEN
Definition httpd.h:300
#define DECLINED
Definition httpd.h:457
#define OK
Definition httpd.h:456
#define DONE
Definition httpd.h:458
const char * ap_get_server_name(request_rec *r)
Definition core.c:1145
const char * ap_get_remote_logname(request_rec *r)
Definition core.c:1121
#define APLOGNO(n)
Definition http_log.h:117
#define APLOG_STARTUP
Definition http_log.h:105
#define ap_log_rerror
Definition http_log.h:454
apr_file_t * ap_piped_log_write_fd(piped_log *pl)
Definition log.c:206
#define APLOG_ERR
Definition http_log.h:67
#define ap_log_error
Definition http_log.h:370
#define APLOG_MARK
Definition http_log.h:283
#define APLOG_WARNING
Definition http_log.h:68
piped_log * ap_open_piped_log(apr_pool_t *p, const char *program)
Definition log.c:1958
#define APLOG_CRIT
Definition http_log.h:66
#define APLOG_EMERG
Definition http_log.h:64
const unsigned char * buf
Definition util_md5.h:50
void ap_hook_log_transaction(ap_HOOK_log_transaction_t *pf, const char *const *aszPre, const char *const *aszSucc, int nOrder)
Definition protocol.c:2587
apr_status_t ap_explode_recent_localtime(apr_time_exp_t *tm, apr_time_t t)
Definition util_time.c:146
const char apr_port_t port
Definition http_vhost.h:125
void * dummy
Definition http_vhost.h:62
#define APR_EBADPATH
Definition apr_errno.h:332
#define APR_ENOTDIR
Definition apr_errno.h:669
apr_bucket apr_bucket_brigade * a
apr_file_t * fd
apr_pool_t apr_dbd_t apr_dbd_results_t ** res
Definition apr_dbd.h:287
apr_pool_t const char apr_dbd_t ** handle
Definition apr_dbd.h:142
#define APR_HOOK_REALLY_FIRST
Definition apr_hooks.h:299
#define APR_HOOK_MIDDLE
Definition apr_hooks.h:303
#define APR_RETRIEVE_OPTIONAL_FN(name)
#define APR_OPTIONAL_FN_TYPE(name)
#define APR_REGISTER_OPTIONAL_FN(name)
apr_redis_t * rc
Definition apr_redis.h:173
const char apr_size_t char * outbuf
Definition apr_xlate.h:120
#define AP_EXPR_FLAG_DONT_VARY
Definition ap_expr.h:61
#define ap_expr_parse_cmd(cmd, expr, flags, err, lookup_fn)
Definition ap_expr.h:340
int ap_expr_exec(request_rec *r, const ap_expr_info_t *expr, const char **err)
#define RSRC_CONF
#define HTTP_INTERNAL_SERVER_ERROR
Definition httpd.h:535
void * ap_log_writer_init(apr_pool_t *p, server_rec *s, const char *name)
const char * ap_log_handler_fn_t(request_rec *r, char *a)
apr_status_t ap_log_writer(request_rec *r, void *handle, const char **portions, int *lengths, int nelts, apr_size_t len)
#define STANDARD20_MODULE_STUFF
char * ap_append_pid(apr_pool_t *p, const char *string, const char *delim)
Definition util.c:2595
int ap_cstr_casecmp(const char *s1, const char *s2)
Definition util.c:3542
char * ap_getword(apr_pool_t *p, const char **line, char stop)
Definition util.c:723
char * ap_escape_logitem(apr_pool_t *p, const char *str)
Definition util.c:2183
char * ap_make_dirstr_parent(apr_pool_t *p, const char *s)
Definition util.c:692
char * ap_field_noparam(apr_pool_t *p, const char *intype)
Definition util.c:91
@ AP_CONN_KEEPALIVE
Definition httpd.h:1146
#define GLOBAL_ONLY
const char * ap_check_cmd_context(cmd_parms *cmd, unsigned forbidden)
Definition core.c:1301
apr_size_t size
const char int apr_pool_t * pool
Definition apr_cstr.h:84
#define apr_isspace(c)
Definition apr_lib.h:225
#define apr_isdigit(c)
Definition apr_lib.h:209
const char * value
Definition apr_env.h:51
#define APR_SUCCESS
Definition apr_errno.h:225
int apr_status_t
Definition apr_errno.h:44
apr_int32_t apr_fileperms_t
@ APR_DIR
const char * key
const char apr_int32_t flag
const char * format
void * data
#define APR_APPEND
Definition apr_file_io.h:96
#define APR_WRITE
Definition apr_file_io.h:94
#define APR_LARGEFILE
#define APR_CREATE
Definition apr_file_io.h:95
#define APR_OS_DEFAULT
const char * fname
#define APR_FINFO_TYPE
apr_array_header_t ** result
int strcasecmp(const char *a, const char *b)
int strncasecmp(const char *a, const char *b, size_t n)
apr_vformatter_buff_t const char * fmt
Definition apr_lib.h:175
apr_sockaddr_t * sa
apr_uint16_t apr_port_t
apr_interval_time_t apr_int32_t * num
Definition apr_poll.h:273
apr_pool_t * b
Definition apr_pools.h:529
#define apr_pcalloc(p, size)
Definition apr_pools.h:465
apr_dir_t * dir
const char char ** last
const char * s
Definition apr_strings.h:95
int nelts
Definition apr_tables.h:122
apr_int32_t apr_int32_t apr_int32_t err
apr_cmdtype_e cmd
#define apr_time_msec(time)
Definition apr_time.h:69
#define apr_time_as_msec(time)
Definition apr_time.h:72
APR_DECLARE_DATA const char apr_month_snames[12][4]
Definition timestr.c:33
#define APR_TIME_T_FMT
Definition apr_time.h:52
apr_int64_t apr_time_t
Definition apr_time.h:45
#define apr_time_sec(time)
Definition apr_time.h:63
#define apr_time_usec(time)
Definition apr_time.h:66
const char * ap_get_remote_host(conn_rec *conn, void *dir_config, int type, int *str_is_ip)
Definition core.c:957
const char * ap_get_useragent_host(request_rec *req, int type, int *str_is_ip)
Definition core.c:1036
#define REMOTE_NAME
Definition http_core.h:106
apr_status_t ap_mpm_query(int query_code, int *result)
Definition mpm_common.c:421
#define AP_MPMQ_MAX_THREADS
Definition ap_mpm.h:160
Apache Configuration.
CORE HTTP Daemon.
Apache Logging library.
HTTP protocol handling.
HTTP Daemon routines.
apr_pool_t * p
Definition md_event.c:32
#define TIME_CACHE_MASK
static void * merge_config_log_state(apr_pool_t *p, void *basev, void *addv)
static void ap_register_log_handler(apr_pool_t *p, char *tag, ap_log_handler_fn_t *handler, int def)
static const char * log_remote_logname(request_rec *r, char *a)
static const char * log_virtual_host(request_rec *r, char *a)
#define DEFAULT_LOG_FORMAT
static const char * log_format(cmd_parms *cmd, void *dummy, const char *fmt, const char *name)
static const char * log_server_port(request_rec *r, char *a)
static const char * set_transfer_log(cmd_parms *cmd, void *dummy, const char *fn)
static void * ap_default_log_writer_init(apr_pool_t *p, server_rec *s, const char *name)
static int buffered_logs
static const char * log_requests_on_connection(request_rec *r, char *a)
static const char * log_request_protocol(request_rec *r, char *a)
static const char * log_request_duration_microseconds(request_rec *r, char *a)
static const char * log_pid_tid(request_rec *r, char *a)
static const char * log_handler(request_rec *r, char *a)
static const char * log_header_out(request_rec *r, char *a)
static const char * log_connection_status(request_rec *r, char *a)
static int multi_log_transaction(request_rec *r)
static char * parse_log_misc_string(apr_pool_t *p, log_format_item *it, const char **sa)
static int open_multi_logs(server_rec *s, apr_pool_t *p)
static const char * log_remote_address(request_rec *r, char *a)
static int log_pre_config(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp)
static const char * constant_item(request_rec *dummy, char *stuff)
static char * parse_log_item(apr_pool_t *p, log_format_item *it, const char **sa)
static const command_rec config_log_cmds[]
static apr_status_t flush_all_logs(void *data)
static int config_log_transaction(request_rec *r, config_log_state *cls, apr_array_header_t *default_format)
static ap_log_writer * ap_log_set_writer(ap_log_writer *handle)
static char * pfmt(apr_pool_t *p, int i)
static int check_log_dir(apr_pool_t *p, server_rec *s, config_log_state *cls)
static const char * log_request_file(request_rec *r, char *a)
static const char * log_cookie(request_rec *r, char *a)
#define TIME_FMT_ABS_SEC
#define LOG_BUFSIZE
static const char * log_request_query(request_rec *r, char *a)
#define TIME_CACHE_SIZE
static const char * log_request_uri(request_rec *r, char *a)
static const char * log_remote_host(request_rec *r, char *a)
static ap_log_writer_init * ap_log_set_writer_init(ap_log_writer_init *handle)
static const char * set_buffered_logs_on(cmd_parms *parms, void *dummy, int flag)
static const char * log_server_name(request_rec *r, char *a)
static apr_array_header_t * parse_log_string(apr_pool_t *p, const char *s, const char **err)
static const char * log_status(request_rec *r, char *a)
static const char * clf_log_bytes_sent(request_rec *r, char *a)
static apr_fileperms_t xfer_perms
static const char * log_request_time(request_rec *r, char *a)
static void flush_log(buffered_log *buf)
static const char * log_request_time_custom(request_rec *r, char *a, apr_time_exp_t *xt)
static void register_hooks(apr_pool_t *p)
static void * ap_buffered_log_writer_init(apr_pool_t *p, server_rec *s, const char *name)
static int init_config_log(apr_pool_t *pc, apr_pool_t *p, apr_pool_t *pt, server_rec *s)
static const char * log_request_line(request_rec *r, char *a)
static void * make_config_log_state(apr_pool_t *p, server_rec *s)
static apr_status_t ap_default_log_writer(request_rec *r, void *handle, const char **strs, int *strl, int nelts, apr_size_t len)
#define DEFAULT_REQUEST_TIME_SIZE
static const char * log_header_in(request_rec *r, char *a)
static const char * log_local_address(request_rec *r, char *a)
static const char * process_item(request_rec *r, request_rec *orig, log_format_item *item)
static apr_status_t ap_buffered_log_writer(request_rec *r, void *handle, const char **strs, int *strl, int nelts, apr_size_t len)
static const char * add_global_log(cmd_parms *cmd, void *dummy, const char *fn, const char *fmt, const char *envclause)
static const char * log_request_duration_scaled(request_rec *r, char *a)
#define TIME_FMT_ABS_USEC_FRAC
static const char * log_log_id(request_rec *r, char *a)
static ap_log_writer * log_writer
static const char * log_trailer_in(request_rec *r, char *a)
static ap_log_writer_init * log_writer_init
#define TIME_FMT_ABS_MSEC_FRAC
static const char * log_bytes_sent(request_rec *r, char *a)
static cached_request_time request_time_cache[4]
static config_log_state * open_config_log(server_rec *s, apr_pool_t *p, config_log_state *cls, apr_array_header_t *default_format)
static const char * add_custom_log(cmd_parms *cmd, void *dummy, const char *fn, const char *fmt, const char *envclause)
static apr_time_t get_request_end_time(request_rec *r)
#define TIME_FMT_ABS_USEC
static const char * log_remote_user(request_rec *r, char *a)
static APR_INLINE char * find_multiple_headers(apr_pool_t *pool, const apr_table_t *table, const char *key)
static int log_check_config(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s)
#define TIME_FMT_CUSTOM
static apr_hash_t * log_hash
static void init_child(apr_pool_t *p, server_rec *s)
static const char * log_note(request_rec *r, char *a)
static const char * log_trailer_out(request_rec *r, char *a)
static const char * log_env_var(request_rec *r, char *a)
static int xfer_flags
static apr_array_header_t * all_buffered_logs
#define TIME_FMT_ABS_MSEC
#define TIME_FMT_CLF
static const char * log_request_method(request_rec *r, char *a)
Logging Configuration Extension Module for Apache.
return NULL
Definition mod_so.c:359
int i
Definition mod_so.c:347
apr_os_thread_t apr_os_thread_current()
Definition thread.c:142
char * name
Structure used to build the config tree.
const char * filename
const char * directive
ap_log_handler_fn_t * func
apr_filetype_e filetype
Definition apr_tables.h:81
apr_int32_t tm_gmtoff
Definition apr_time.h:119
apr_int32_t tm_sec
Definition apr_time.h:101
apr_int32_t tm_hour
Definition apr_time.h:105
apr_int32_t tm_year
Definition apr_time.h:111
apr_int32_t tm_min
Definition apr_time.h:103
apr_int32_t tm_mday
Definition apr_time.h:107
apr_int32_t tm_mon
Definition apr_time.h:109
char * password
Definition apr_uri.h:93
apr_size_t outcnt
apr_anylock_t mutex
apr_file_t * handle
const ap_directive_t * directive
const char * fname
const char * format_string
ap_expr_info_t * condition_expr
apr_array_header_t * format
ap_conn_keepalive_e keepalive
Definition httpd.h:1223
apr_sockaddr_t * local_addr
Definition httpd.h:1162
char * client_ip
Definition httpd.h:1171
const char * log_id
Definition httpd.h:1235
int keepalives
Definition httpd.h:1226
char * local_ip
Definition httpd.h:1181
unsigned aborted
Definition httpd.h:1219
apr_array_header_t * conditions
ap_log_handler_fn_t * func
apr_time_t request_end_time
apr_array_header_t * server_config_logs
const char * default_format_string
apr_table_t * formats
apr_array_header_t * default_format
apr_array_header_t * config_logs
The piped logging structure.
Definition log.c:186
A structure that represents the current request.
Definition httpd.h:845
char * user
Definition httpd.h:1005
int status
Definition httpd.h:891
apr_off_t bytes_sent
Definition httpd.h:931
char * uri
Definition httpd.h:1016
const char * content_type
Definition httpd.h:992
apr_table_t * trailers_in
Definition httpd.h:1104
char * useragent_ip
Definition httpd.h:1101
request_rec * prev
Definition httpd.h:856
int assbackwards
Definition httpd.h:868
const char * handler
Definition httpd.h:994
apr_table_t * notes
Definition httpd.h:985
char * the_request
Definition httpd.h:866
apr_pool_t * pool
Definition httpd.h:847
apr_sockaddr_t * useragent_addr
Definition httpd.h:1100
char * filename
Definition httpd.h:1018
apr_time_t request_time
Definition httpd.h:886
apr_uri_t parsed_uri
Definition httpd.h:1092
conn_rec * connection
Definition httpd.h:849
const char * log_id
Definition httpd.h:1059
struct ap_conf_vector_t * request_config
Definition httpd.h:1049
apr_table_t * headers_in
Definition httpd.h:976
char * protocol
Definition httpd.h:879
apr_table_t * subprocess_env
Definition httpd.h:983
apr_off_t sent_bodyct
Definition httpd.h:929
server_rec * server
Definition httpd.h:851
struct ap_conf_vector_t * per_dir_config
Definition httpd.h:1047
const char * method
Definition httpd.h:900
request_rec * next
Definition httpd.h:854
char * args
Definition httpd.h:1026
apr_table_t * trailers_out
Definition httpd.h:1106
apr_table_t * headers_out
Definition httpd.h:978
A structure to store information for each virtual server.
Definition httpd.h:1322
int keep_alive_max
Definition httpd.h:1376
char * server_hostname
Definition httpd.h:1365
struct ap_conf_vector_t * module_config
Definition httpd.h:1341
apr_port_t port
Definition httpd.h:1356
apr_status_t apr_strftime(char *s, apr_size_t *retsize, apr_size_t max, const char *format, apr_time_exp_t *xt)
Definition timestr.c:132
#define str
Apache date-time handling functions.