mod_log_config.c revision 144806982c1764b6bdd45caab786fcd620e9f3b5
842ae4bd224140319ae7feec1872b93dfd491143fielding/* Licensed to the Apache Software Foundation (ASF) under one or more
842ae4bd224140319ae7feec1872b93dfd491143fielding * contributor license agreements. See the NOTICE file distributed with
842ae4bd224140319ae7feec1872b93dfd491143fielding * this work for additional information regarding copyright ownership.
842ae4bd224140319ae7feec1872b93dfd491143fielding * The ASF licenses this file to You under the Apache License, Version 2.0
842ae4bd224140319ae7feec1872b93dfd491143fielding * (the "License"); you may not use this file except in compliance with
842ae4bd224140319ae7feec1872b93dfd491143fielding * the License. You may obtain a copy of the License at
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * Unless required by applicable law or agreed to in writing, software
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * distributed under the License is distributed on an "AS IS" BASIS,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * See the License for the specific language governing permissions and
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * limitations under the License.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * Modified by djm@va.pubnix.com:
e8f95a682820a599fe41b22977010636be5c2717jim * If no TransferLog is given explicitly, decline to log.
e8f95a682820a599fe41b22977010636be5c2717jim * This is module implements the TransferLog directive (same as the
1747d30b98aa1bdbc43994c02cd46ab4cb9319e4fielding * common log module), and additional directives, LogFormat and CustomLog.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * TransferLog fn Logs transfers to fn in standard log format, unless
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * a custom format is set with LogFormat
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * LogFormat format Set a log format from TransferLog files
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * CustomLog fn format
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick * Log to file fn with format given by the format
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * CookieLog fn For backwards compatability with old Cookie
5c0419d51818eb02045cf923a9fe456127a44c60wrowe * logging module - now deprecated.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * There can be any number of TransferLog and CustomLog
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * commands. Each request will be logged to _ALL_ the
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * named files, in the appropriate format.
ab86c68ce36c715e93f403dde41d0b9c1522c8b0sf * If no TransferLog or CustomLog directive appears in a VirtualHost,
ab86c68ce36c715e93f403dde41d0b9c1522c8b0sf * the request will be logged to the log file(s) defined outside
cd3bbd6d2df78d6c75e5d159a81ef8bdd5f70df9trawick * the virtual host section. If a TransferLog or CustomLog directive
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * appears in the VirtualHost section, the log files defined outside
ab86c68ce36c715e93f403dde41d0b9c1522c8b0sf * the VirtualHost will _not_ be used. This makes this module compatable
ab86c68ce36c715e93f403dde41d0b9c1522c8b0sf * with the CLF and config log modules, where the use of TransferLog
ab86c68ce36c715e93f403dde41d0b9c1522c8b0sf * inside the VirtualHost section overrides its use outside.
ab86c68ce36c715e93f403dde41d0b9c1522c8b0sf * Examples:
ab86c68ce36c715e93f403dde41d0b9c1522c8b0sf * TransferLog logs/access_log
ab86c68ce36c715e93f403dde41d0b9c1522c8b0sf * <VirtualHost>
bede2929837dfd23863ad4b39199c63126566d61jorton * LogFormat "... custom format ..."
0f60998368b493f90120180a93fc2e1e74490872covener * TransferLog log/virtual_only
0f60998368b493f90120180a93fc2e1e74490872covener * CustomLog log/virtual_useragents "%t %{user-agent}i"
0f60998368b493f90120180a93fc2e1e74490872covener * </VirtualHost>
0f60998368b493f90120180a93fc2e1e74490872covener * This will log using CLF to access_log any requests handled by the
0f60998368b493f90120180a93fc2e1e74490872covener * main server, while any requests to the virtual host will be logged
0f60998368b493f90120180a93fc2e1e74490872covener * with the "... custom format..." to virtual_only _AND_ using
0f60998368b493f90120180a93fc2e1e74490872covener * the custom user-agent log to virtual_useragents.
87587593f1a53030e840acc0dec6cc881022ea40covener * Note that the NCSA referer and user-agent logs are easily added with
87587593f1a53030e840acc0dec6cc881022ea40covener * CustomLog:
87587593f1a53030e840acc0dec6cc881022ea40covener * CustomLog logs/referer "%{referer}i -> %U"
a81c0c1ae464b2063a21b45f80c9da8d89bb840ecovener * CustomLog logs/agent "%{user-agent}i"
a81c0c1ae464b2063a21b45f80c9da8d89bb840ecovener * RefererIgnore functionality can be obtained with conditional
97cd2f98ad4abe68aaaba96b5bfc9ebf7109a2c1covener * logging (SetEnvIf and CustomLog ... env=!VAR).
97cd2f98ad4abe68aaaba96b5bfc9ebf7109a2c1covener * But using this method allows much easier modification of the
97cd2f98ad4abe68aaaba96b5bfc9ebf7109a2c1covener * log format, e.g. to log hosts along with UA:
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * CustomLog logs/referer "%{referer}i %U %h"
fa123db15501821e36e513afa78e839775ad2800covener * The argument to LogFormat and CustomLog is a string, which can include
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * literal characters copied into the log files, and '%' directives as
0568280364eb026393be492ebc732795c4934643jorton * %...B: bytes sent, excluding HTTP headers.
0568280364eb026393be492ebc732795c4934643jorton * %...b: bytes sent, excluding HTTP headers in CLF format, i.e. a '-'
0568280364eb026393be492ebc732795c4934643jorton * when no bytes where sent (rather than a '0'.
0568280364eb026393be492ebc732795c4934643jorton * %...{FOOBAR}C: The contents of the HTTP cookie FOOBAR
0568280364eb026393be492ebc732795c4934643jorton * %...{FOOBAR}e: The contents of the environment variable FOOBAR
0568280364eb026393be492ebc732795c4934643jorton * %...f: filename
0568280364eb026393be492ebc732795c4934643jorton * %...h: remote host
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * %...a: remote IP-address
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * %...A: local IP-address
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * %...{Foobar}i: The contents of Foobar: header line(s) in the request
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * sent to the client.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * %...k: number of keepalive requests served over this connection
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * %...l: remote logname (from identd, if supplied)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * %...{Foobar}n: The contents of note "Foobar" from another module.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * %...{Foobar}o: The contents of Foobar: header line(s) in the reply.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * %...p: the canonical port for the server
796e4a7141265d8ed7036e4628161c6eafb2a789jorton * %...{format}p: the canonical port for the server, or the actual local
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * or remote port
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * %...P: the process ID of the child that serviced the request.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * %...{format}P: the process ID or thread ID of the child/thread that
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * serviced the request
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * %...r: first line of request
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * %...s: status. For requests that got internally redirected, this
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * is status of the *original* request --- %...>s for the last.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * %...t: time, in common log format time format
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * %...{format}t: The time, in the form given by format, which should
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * be in strftime(3) format.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * %...T: the time taken to serve the request, in seconds.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * %...D: the time taken to serve the request, in micro seconds.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * %...u: remote user (from auth; may be bogus if return status (%s) is 401)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * %...U: the URL path requested.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * %...v: the configured name of the server (i.e. which virtual host?)
8113dac419143273351446c3ad653f3fe5ba5cfdwrowe * %...V: the server name according to the UseCanonicalName setting
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * %...m: the request method
95b6fe1346805e1731e6e97c15d569c73be22cf7minfrin * %...H: the request protocol
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * %...q: the query string prepended by "?", or empty if no query string
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * %...X: Status of the connection.
95b6fe1346805e1731e6e97c15d569c73be22cf7minfrin * 'X' = connection aborted before the response completed.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * '+' = connection may be kept alive after the response is sent.
95b6fe1346805e1731e6e97c15d569c73be22cf7minfrin * '-' = connection will be closed after the response is sent.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * (This directive was %...c in late versions of Apache 1.3, but
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * this conflicted with the historical ssl %...{var}c syntax.)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * %...L: Log-Id of the Request (or '-' if none)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * %...{c}L: Log-Id of the Connection (or '-' if none)
95b6fe1346805e1731e6e97c15d569c73be22cf7minfrin * The '...' can be nothing at all (e.g. "%h %u %r %s %b"), or it can
95b6fe1346805e1731e6e97c15d569c73be22cf7minfrin * indicate conditions for inclusion of the item (which will cause it
95b6fe1346805e1731e6e97c15d569c73be22cf7minfrin * to be replaced with '-' if the condition is not met). Note that
a1790fb35c4b352dab721370985c623a9f8f5062rpluem * there is no escaping performed on the strings from %r, %...i and
713a2b68bac4aeb1e9c48785006c0732451039depquerna * %...o; some with long memories may remember that I thought this was
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * a bad idea, once upon a time, and I'm still not comfortable with
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * it, but it is difficult to see how to "do the right thing" with all
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * of '%..i', unless we URL-escape everything and break with CLF.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * The forms of condition are a list of HTTP status codes, which may
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe * or may not be preceded by '!'. Thus, '%400,501{User-agent}i' logs
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe * User-agent: on 400 errors and 501 errors (Bad Request, Not
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * Implemented) only; '%!200,304,302{Referer}i' logs Referer: on all
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * requests which did *not* return some sort of normal status.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * The default LogFormat reproduces CLF; see below.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * The way this is supposed to work with virtual hosts is as follows:
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * a virtual host can have its own LogFormat, or its own TransferLog.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * If it doesn't have its own LogFormat, it inherits from the main
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener * server. If it doesn't have its own TransferLog, it writes to the
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * same descriptor (meaning the same process for "| ...").
f43b67c5a9d29b572eac916f8335cedc80c908bebnicholes * --- rst */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholesstatic int xfer_flags = (APR_WRITE | APR_APPEND | APR_CREATE | APR_LARGEFILE);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholesstatic apr_fileperms_t xfer_perms = APR_OS_DEFAULT;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholesstatic apr_status_t ap_default_log_writer(request_rec *r,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes const char **strs,
fa123db15501821e36e513afa78e839775ad2800covenerstatic apr_status_t ap_buffered_log_writer(request_rec *r,
f2be127030aa4190033084f0a6add531c9bc41desf const char **strs,
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovenerstatic void *ap_default_log_writer_init(apr_pool_t *p, server_rec *s,
60215f303c7e1ce8b6d272acb5bfa5b3d99dfd34covener const char* name);
60215f303c7e1ce8b6d272acb5bfa5b3d99dfd34covenerstatic void *ap_buffered_log_writer_init(apr_pool_t *p, server_rec *s,
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener const char* name);
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovenerstatic ap_log_writer_init* ap_log_set_writer_init(ap_log_writer_init *handle);
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovenerstatic ap_log_writer* ap_log_set_writer(ap_log_writer *handle);
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovenerstatic ap_log_writer *log_writer = ap_default_log_writer;
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovenerstatic ap_log_writer_init *log_writer_init = ap_default_log_writer_init;
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovenerstatic int buffered_logs = 0; /* default unbuffered */
6683642c1e0032eeeed5f99e8c14880692ef84c5sf/* POSIX.1 defines PIPE_BUF as the maximum number of bytes that is
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener * guaranteed to be atomic when writing a pipe. And PIPE_BUF >= 512
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener * is guaranteed. So we'll just guess 512 in the event the system
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener * doesn't have this. Now, for file writes there is actually no limit,
6683642c1e0032eeeed5f99e8c14880692ef84c5sf * the entire write is atomic. Whether all systems implement this
6683642c1e0032eeeed5f99e8c14880692ef84c5sf * correctly is another question entirely ... so we'll just use PIPE_BUF
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener * because it's probably a good guess as to what is implemented correctly
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener * everywhere.
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener * multi_log_state is our per-(virtual)-server configuration. We store
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener * an array of the logs we are going to use, each of type config_log_state.
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener * If a default log format is given by LogFormat, store in default_format
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener * (backward compat. with mod_log_config). We also store for each virtual
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener * server a pointer to the logs specified for the main server, so that if this
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener * vhost has no logs defined, we can use the main server's logs instead.
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener * So, for the main server, config_logs contains a list of the log files
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * and server_config_logs is empty. For a vhost, server_config_logs
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * points to the same array as config_logs in the main server, and
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener * config_logs points to the array of logs defined inside this vhost,
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener * which might be empty.
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovenertypedef struct {
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener * config_log_state holds the status of a single log file. fname might
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener * be NULL, which means this module does no logging for this
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener * request. format might be NULL, in which case the default_format
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * from the multi_log_state should be used, or if that is NULL as
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * well, use the CLF.
60215f303c7e1ce8b6d272acb5bfa5b3d99dfd34covener * log_writer is NULL before the log file is opened and is
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * set to a opaque structure (usually a fd) after it is opened.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholestypedef struct {
e8f95a682820a599fe41b22977010636be5c2717jimtypedef struct {
3dfeb02cfb853d8717ca0cc259b59fea610173f5bnicholes const char *fname;
ab86c68ce36c715e93f403dde41d0b9c1522c8b0sf * log_request_state holds request specific log data that is not
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes * part of the request_rec.
ab86c68ce36c715e93f403dde41d0b9c1522c8b0sftypedef struct {
513b324e774c559b579896df131fd7c8471ed529rederpj * Format items...
513b324e774c559b579896df131fd7c8471ed529rederpj * Note that many of these could have ap_sprintfs replaced with static buffers.
513b324e774c559b579896df131fd7c8471ed529rederpjtypedef struct {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (i <= 0) {
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes return apr_itoa(p, i);
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholesstatic const char *constant_item(request_rec *dummy, char *stuff)
ab86c68ce36c715e93f403dde41d0b9c1522c8b0sfstatic const char *log_remote_host(request_rec *r, char *a)
707f6d077f73cc948deead8df5b40ea42c1eaa78covener return ap_escape_logitem(r->pool, ap_get_remote_host(r->connection,
707f6d077f73cc948deead8df5b40ea42c1eaa78covenerstatic const char *log_remote_address(request_rec *r, char *a)
54d22ed1c429b903b029bbd62621f11a9e286137minfrinstatic const char *log_local_address(request_rec *r, char *a)
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholesstatic const char *log_remote_logname(request_rec *r, char *a)
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes return ap_escape_logitem(r->pool, ap_get_remote_logname(r));
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholesstatic const char *log_remote_user(request_rec *r, char *a)
707f6d077f73cc948deead8df5b40ea42c1eaa78covenerstatic const char *log_request_line(request_rec *r, char *a)
9ad7b260be233be7d7b5576979825cac72e15498rederpj /* NOTE: If the original request contained a password, we
707f6d077f73cc948deead8df5b40ea42c1eaa78covener * re-write the request line here to contain XXXXXX instead:
707f6d077f73cc948deead8df5b40ea42c1eaa78covener * (note the truncation before the protocol string for HTTP/0.9 requests)
ab86c68ce36c715e93f403dde41d0b9c1522c8b0sf * (note also that r->the_request contains the unmodified request)
707f6d077f73cc948deead8df5b40ea42c1eaa78covenerstatic const char *log_request_file(request_rec *r, char *a)
707f6d077f73cc948deead8df5b40ea42c1eaa78covenerstatic const char *log_request_uri(request_rec *r, char *a)
707f6d077f73cc948deead8df5b40ea42c1eaa78covenerstatic const char *log_request_method(request_rec *r, char *a)
707f6d077f73cc948deead8df5b40ea42c1eaa78covenerstatic const char *log_log_id(request_rec *r, char *a)
707f6d077f73cc948deead8df5b40ea42c1eaa78covener return r->connection->log_id ? r->connection->log_id : "-";
707f6d077f73cc948deead8df5b40ea42c1eaa78covenerstatic const char *log_request_protocol(request_rec *r, char *a)
9ad7b260be233be7d7b5576979825cac72e15498rederpjstatic const char *log_request_query(request_rec *r, char *a)
ab86c68ce36c715e93f403dde41d0b9c1522c8b0sfstatic const char *clf_log_bytes_sent(request_rec *r, char *a)
ab86c68ce36c715e93f403dde41d0b9c1522c8b0sf return "-";
141e1368614dc7564e1627671361b01b4869b491bnicholesstatic const char *log_bytes_sent(request_rec *r, char *a)
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf return "0";
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholesstatic const char *log_header_in(request_rec *r, char *a)
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes return ap_escape_logitem(r->pool, apr_table_get(r->headers_in, a));
4be9c459920a7c1cfe62d654327dae5c4bb6b284sfstatic APR_INLINE char *find_multiple_headers(apr_pool_t *pool,
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf const char *key)
ab86c68ce36c715e93f403dde41d0b9c1522c8b0sf const char *value;
7dbf29be626018bc389ef94c1846aeac4b72633bsfstatic const char *log_header_out(request_rec *r, char *a)
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes if (!strcasecmp(a, "Content-type") && r->content_type) {
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes cp = find_multiple_headers(r->pool, r->headers_out, a);
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholesstatic const char *log_note(request_rec *r, char *a)
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes return ap_escape_logitem(r->pool, apr_table_get(r->notes, a));
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholesstatic const char *log_env_var(request_rec *r, char *a)
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes return ap_escape_logitem(r->pool, apr_table_get(r->subprocess_env, a));
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholesstatic const char *log_cookie(request_rec *r, char *a)
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes * This supports Netscape version 0 cookies while being tolerant to
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes * some properties of RFC2109/2965 version 1 cookies:
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf * - case-insensitive match of cookie names
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes * - white space between the tokens
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes * It does not support the following version 1 features:
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes * - quoted strings as cookie values
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes * - commas to separate cookies
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if ((cookies_entry = apr_table_get(r->headers_in, "Cookie"))) {
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf if (!strcasecmp(name, a) && (value = apr_strtok(NULL, "=", &last2))) {
e8f95a682820a599fe41b22977010636be5c2717jim value += strspn(value, " \t"); /* Move past leading WS */
60d81cab99dccfbb0c8d378cf6aa7338be0fdb74covenerstatic const char *log_request_time_custom(request_rec *r, char *a,
60d81cab99dccfbb0c8d378cf6aa7338be0fdb74covenertypedef struct {
60d81cab99dccfbb0c8d378cf6aa7338be0fdb74covener unsigned t;
4be9c459920a7c1cfe62d654327dae5c4bb6b284sfstatic cached_request_time request_time_cache[TIME_CACHE_SIZE];
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholesstatic apr_time_t get_request_end_time(request_rec *r)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes log_request_state *state = (log_request_state *)ap_get_module_config(r->request_config,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholesstatic const char *log_request_time(request_rec *r, char *a)
e8f95a682820a599fe41b22977010636be5c2717jim else if (!*fmt) {
f0f6f1b90ab582896f8a7d56d85bd62a55e57d90covener if (fmt_type >= TIME_FMT_ABS_SEC) { /* Absolute (micro-/milli-)second time
8113dac419143273351446c3ad653f3fe5ba5cfdwrowe * or msec/usec fraction
e8f95a682820a599fe41b22977010636be5c2717jim apr_snprintf(buf, 20, "%" APR_TIME_T_FMT, apr_time_sec(request_time));
9ad7b260be233be7d7b5576979825cac72e15498rederpj apr_snprintf(buf, 20, "%" APR_TIME_T_FMT, apr_time_as_msec(request_time));
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes apr_snprintf(buf, 20, "%" APR_TIME_T_FMT, request_time);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes apr_snprintf(buf, 20, "%03" APR_TIME_T_FMT, apr_time_msec(request_time));
560fd0658902ab57754616c172d8953e69fc4722bnicholes apr_snprintf(buf, 20, "%06" APR_TIME_T_FMT, apr_time_usec(request_time));
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes else if (fmt_type == TIME_FMT_CUSTOM) { /* Custom format */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* The custom time formatting uses a very large temp buffer
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * on the stack. To avoid using so much stack space in the
e8f95a682820a599fe41b22977010636be5c2717jim * common case where we're not using a custom format, the code
e8f95a682820a599fe41b22977010636be5c2717jim * for the custom format in a separate function. (That's why
e8f95a682820a599fe41b22977010636be5c2717jim * log_request_time_custom is not inlined right here.)
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe else { /* CLF format */
7a55c294da84865fe13262ed66ffd0c5841a9da5covener /* This code uses the same technique as ap_explode_recent_localtime():
7a55c294da84865fe13262ed66ffd0c5841a9da5covener * optimistic caching with logic to detect and correct race conditions.
a81c0c1ae464b2063a21b45f80c9da8d89bb840ecovener * See the comments in server/util_time.c for more information.
a81c0c1ae464b2063a21b45f80c9da8d89bb840ecovener cached_request_time* cached_time = apr_palloc(r->pool,
54091ac5c596337658fc568231ca1a900abdc5fecovener unsigned t_seconds = (unsigned)apr_time_sec(request_time);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* Invalid or old snapshot, so compute the proper time string
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * and store it in the cache
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes apr_snprintf(cached_time->timestr, DEFAULT_REQUEST_TIME_SIZE,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "[%02d/%s/%d:%02d:%02d:%02d %c%.2d%.2d]",
560fd0658902ab57754616c172d8953e69fc4722bnicholes xt.tm_year+1900, xt.tm_hour, xt.tm_min, xt.tm_sec,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholesstatic const char *log_request_duration(request_rec *r, char *a)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes apr_time_t duration = get_request_end_time(r) - r->request_time;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes return apr_psprintf(r->pool, "%" APR_TIME_T_FMT, apr_time_sec(duration));
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholesstatic const char *log_request_duration_microseconds(request_rec *r, char *a)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes/* These next two routines use the canonical name:port so that log
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * parsers don't need to duplicate all the vhost parsing crud.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholesstatic const char *log_virtual_host(request_rec *r, char *a)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes return ap_escape_logitem(r->pool, r->server->server_hostname);
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovenerstatic const char *log_server_port(request_rec *r, char *a)
ebe5305f8b22507374358f32b74d12fb50c05a25covener port = r->server->port ? r->server->port : ap_default_port(r);
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener /* bogus format */
0e05808dc59a321566303084c84b9826a4353cefrederpj/* This respects the setting of UseCanonicalName so that
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * the dynamic mass virtual hosting trick works better.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholesstatic const char *log_server_name(request_rec *r, char *a)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes return ap_escape_logitem(r->pool, ap_get_server_name(r));
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholesstatic const char *log_pid_tid(request_rec *r, char *a)
54d22ed1c429b903b029bbd62621f11a9e286137minfrin else if (!strcasecmp(a, "tid") || !strcasecmp(a, "hextid")) {
54d22ed1c429b903b029bbd62621f11a9e286137minfrin int tid = 0; /* APR will format "0" anyway but an arg is needed */
54d22ed1c429b903b029bbd62621f11a9e286137minfrin#if APR_MAJOR_VERSION > 1 || (APR_MAJOR_VERSION == 1 && APR_MINOR_VERSION >= 2)
54d22ed1c429b903b029bbd62621f11a9e286137minfrin /* APR can format a thread id in hex */
a81c0c1ae464b2063a21b45f80c9da8d89bb840ecovener /* APR is missing the feature, so always use decimal */
fa123db15501821e36e513afa78e839775ad2800covener /* bogus format */
fa123db15501821e36e513afa78e839775ad2800covenerstatic const char *log_connection_status(request_rec *r, char *a)
fa123db15501821e36e513afa78e839775ad2800covener return "X";
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (r->connection->keepalive == AP_CONN_KEEPALIVE &&
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes (r->server->keep_alive_max - r->connection->keepalives) > 0)) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholesstatic const char *log_requests_on_connection(request_rec *r, char *a)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes int num = r->connection->keepalives ? r->connection->keepalives - 1 : 0;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes/*****************************************************************
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * Parsing the log format string
e8f95a682820a599fe41b22977010636be5c2717jimstatic char *parse_log_misc_string(apr_pool_t *p, log_format_item *it,
e8f95a682820a599fe41b22977010636be5c2717jim const char **sa)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes const char *s;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes while (*s && *s != '%') {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * This might allocate a few chars extra if there's a backslash
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * escape in the format string.
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe while (*s && *s != '%') {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (*s != '\\') {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes *d++ = *s++;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes switch (*s) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes *d++ = '\\';
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes *d++ = '\r';
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes *d++ = '\n';
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes *d++ = '\t';
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* copy verbatim */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes *d++ = '\\';
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * Allow the loop to deal with this *s in the normal
e8f95a682820a599fe41b22977010636be5c2717jim * fashion so that it handles end of string etc.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholesstatic char *parse_log_item(apr_pool_t *p, log_format_item *it, const char **sa)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes const char *s = *sa;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (*s != '%') {
f43b67c5a9d29b572eac916f8335cedc80c908bebnicholes if (*s == '%') {
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe while (*s) {
60d81cab99dccfbb0c8d378cf6aa7338be0fdb74covener switch (*s) {
e8f95a682820a599fe41b22977010636be5c2717jim i = *s - '0';
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes while (apr_isdigit(*++s)) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes handler = (ap_log_handler *)apr_hash_get(log_hash, s++, 1);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes return apr_pstrcat(p, "Unrecognized LogFormat directive %",
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes return "Ran off end of LogFormat parsing args to some directive";
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholesstatic apr_array_header_t *parse_log_string(apr_pool_t *p, const char *s, const char **err)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes apr_array_header_t *a = apr_array_make(p, 30, sizeof(log_format_item));
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes while (*s) {
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe if ((res = parse_log_item(p, (log_format_item *) apr_array_push(a), &s))) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes parse_log_item(p, (log_format_item *) apr_array_push(a), &s);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes/*****************************************************************
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * Actually logging.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholesstatic const char *process_item(request_rec *r, request_rec *orig,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes const char *cp;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* First, see if we need to process this thing at all... */
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpj if (item->conditions && item->conditions->nelts != 0) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* We do. Do it... */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes cp = (*item->func) (item->want_orig ? orig : r, item->arg);
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpj apr_file_write(buf->handle, buf->outbuf, &buf->outcnt);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholesstatic int config_log_transaction(request_rec *r, config_log_state *cls,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes const char **strs;
37af4b0cf648275b68ff41c866c665b4ccf4667dcovener * See if we've got any conditional envariable-controlled logging decisions
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (apr_table_get(r->subprocess_env, envar) == NULL) {
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf if (apr_table_get(r->subprocess_env, &envar[1]) != NULL) {
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf const char *err;
60d81cab99dccfbb0c8d378cf6aa7338be0fdb74covener int rc = ap_expr_exec(r, cls->condition_expr, &err);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes format = cls->format ? cls->format : default_format;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes strs = apr_palloc(r->pool, sizeof(char *) * (format->nelts));
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes strl = apr_palloc(r->pool, sizeof(int) * (format->nelts));
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe while (r->next) {
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem "log writer isn't correctly setup");
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes rv = log_writer(r, cls->log_writer, strs, strl, format->nelts, len);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* xxx: do we return an error on log_writer? */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes multi_log_state *mls = ap_get_module_config(r->server->module_config,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * Initialize per request state
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes log_request_state *state = apr_pcalloc(r->pool, sizeof(log_request_state));
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes ap_set_module_config(r->request_config, &log_config_module, state);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * Log this transaction..
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes clsarray = (config_log_state *) mls->config_logs->elts;
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem clsarray = (config_log_state *) mls->server_config_logs->elts;
8869662bb1a4078297020e94ae5e928626d877c6rederpj for (i = 0; i < mls->server_config_logs->nelts; ++i) {
8869662bb1a4078297020e94ae5e928626d877c6rederpj config_log_transaction(r, cls, mls->default_format);
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem/*****************************************************************
8869662bb1a4078297020e94ae5e928626d877c6rederpj * Module glue...
8869662bb1a4078297020e94ae5e928626d877c6rederpjstatic void *make_config_log_state(apr_pool_t *p, server_rec *s)
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem mls = (multi_log_state *) apr_palloc(p, sizeof(multi_log_state));
60d81cab99dccfbb0c8d378cf6aa7338be0fdb74covener mls->config_logs = apr_array_make(p, 1, sizeof(config_log_state));
60d81cab99dccfbb0c8d378cf6aa7338be0fdb74covener apr_table_setn(mls->formats, "CLF", DEFAULT_LOG_FORMAT);
8869662bb1a4078297020e94ae5e928626d877c6rederpj * Use the merger to simply add a pointer from the vhost log state
8869662bb1a4078297020e94ae5e928626d877c6rederpj * to the log of logs specified for the non-vhost configuration. Make sure
8869662bb1a4078297020e94ae5e928626d877c6rederpj * vhosts inherit any globally-defined format names.
8869662bb1a4078297020e94ae5e928626d877c6rederpjstatic void *merge_config_log_state(apr_pool_t *p, void *basev, void *addv)
8869662bb1a4078297020e94ae5e928626d877c6rederpj add->default_format_string = base->default_format_string;
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf add->formats = apr_table_overlay(p, base->formats, add->formats);
60d81cab99dccfbb0c8d378cf6aa7338be0fdb74covener * Set the default logfile format, or define a nickname for a format string.
4be9c459920a7c1cfe62d654327dae5c4bb6b284sfstatic const char *log_format(cmd_parms *cmd, void *dummy, const char *fmt,
8869662bb1a4078297020e94ae5e928626d877c6rederpj const char *name)
8869662bb1a4078297020e94ae5e928626d877c6rederpj multi_log_state *mls = ap_get_module_config(cmd->server->module_config,
8869662bb1a4078297020e94ae5e928626d877c6rederpj * If we were given two arguments, the second is a name to be given to the
8869662bb1a4078297020e94ae5e928626d877c6rederpj * format. This syntax just defines the nickname - it doesn't actually
8869662bb1a4078297020e94ae5e928626d877c6rederpj * make the format the default.
8869662bb1a4078297020e94ae5e928626d877c6rederpj mls->default_format = parse_log_string(cmd->pool, fmt, &err_string);
8445dae5cc606ba8ba04efc341cc1e081d95920drpluemstatic const char *add_custom_log(cmd_parms *cmd, void *dummy, const char *fn,
8869662bb1a4078297020e94ae5e928626d877c6rederpj multi_log_state *mls = ap_get_module_config(cmd->server->module_config,
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem cls = (config_log_state *) apr_array_push(mls->config_logs);
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem || ((envclause[4] == '!') && (envclause[5] == '\0'))) {
8869662bb1a4078297020e94ae5e928626d877c6rederpj return "missing environment variable name";
8869662bb1a4078297020e94ae5e928626d877c6rederpj cls->condition_var = apr_pstrdup(cmd->pool, &envclause[4]);
8869662bb1a4078297020e94ae5e928626d877c6rederpj const char *err;
8869662bb1a4078297020e94ae5e928626d877c6rederpj return "missing condition";
8869662bb1a4078297020e94ae5e928626d877c6rederpj cls->condition_expr = ap_expr_parse_cmd(cmd, &envclause[5], &err,
8869662bb1a4078297020e94ae5e928626d877c6rederpj cls->condition_expr->module_index = APLOG_MODULE_INDEX;
8869662bb1a4078297020e94ae5e928626d877c6rederpj cls->condition_expr->flags |= AP_EXPR_FLAGS_DONT_VARY;
8869662bb1a4078297020e94ae5e928626d877c6rederpj return "error in condition clause";
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem cls->format = parse_log_string(cmd->pool, fmt, &err_string);
8869662bb1a4078297020e94ae5e928626d877c6rederpjstatic const char *set_transfer_log(cmd_parms *cmd, void *dummy,
8869662bb1a4078297020e94ae5e928626d877c6rederpj const char *fn)
8445dae5cc606ba8ba04efc341cc1e081d95920drpluemstatic const char *set_cookie_log(cmd_parms *cmd, void *dummy, const char *fn)
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem return add_custom_log(cmd, dummy, fn, "%{Cookie}n \"%r\" %t", NULL);
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpjstatic const char *set_buffered_logs_on(cmd_parms *parms, void *dummy, int flag)
8445dae5cc606ba8ba04efc341cc1e081d95920drpluemAP_INIT_TAKE23("CustomLog", add_custom_log, NULL, RSRC_CONF,
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem "a file name, a custom log format string or format name, "
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem "and an optional \"env=\" or \"expr=\" clause (see docs)"),
8445dae5cc606ba8ba04efc341cc1e081d95920drpluemAP_INIT_TAKE1("TransferLog", set_transfer_log, NULL, RSRC_CONF,
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem "the filename of the access log"),
8445dae5cc606ba8ba04efc341cc1e081d95920drpluemAP_INIT_TAKE12("LogFormat", log_format, NULL, RSRC_CONF,
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem "a log format string (see docs) and an optional format name"),
8445dae5cc606ba8ba04efc341cc1e081d95920drpluemAP_INIT_TAKE1("CookieLog", set_cookie_log, NULL, RSRC_CONF,
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem "the filename of the cookie log"),
8445dae5cc606ba8ba04efc341cc1e081d95920drpluemAP_INIT_FLAG("BufferedLogs", set_buffered_logs_on, NULL, RSRC_CONF,
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem "Enable Buffered Logging (experimental)"),
8445dae5cc606ba8ba04efc341cc1e081d95920drpluemstatic config_log_state *open_config_log(server_rec *s, apr_pool_t *p,
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem return cls; /* virtual config shared w/main server */
11ca38a20ab9b2d00258f745620e2724838e7e21rederpjstatic int open_multi_logs(server_rec *s, apr_pool_t *p)
11ca38a20ab9b2d00258f745620e2724838e7e21rederpj multi_log_state *mls = ap_get_module_config(s->module_config,
a9c4332dc6241dc11dd104826bd179d42ccc0f12fuankg const char *dummy;
11ca38a20ab9b2d00258f745620e2724838e7e21rederpj const char *format;
11ca38a20ab9b2d00258f745620e2724838e7e21rederpj format = apr_table_get(mls->formats, mls->default_format_string);
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem mls->default_format = parse_log_string(p, format, &dummy);
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem mls->default_format = parse_log_string(p, DEFAULT_LOG_FORMAT, &dummy);
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj clsarray = (config_log_state *) mls->config_logs->elts;
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem format = apr_table_get(mls->formats, cls->format_string);
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpj if (!open_config_log(s, p, cls, mls->default_format)) {
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj /* Failure already logged by open_config_log */
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj clsarray = (config_log_state *) mls->server_config_logs->elts;
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj for (i = 0; i < mls->server_config_logs->nelts; ++i) {
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem format = apr_table_get(mls->formats, cls->format_string);
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpj if (!open_config_log(s, p, cls, mls->default_format)) {
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj /* Failure already logged by open_config_log */
0e05808dc59a321566303084c84b9826a4353cefrederpj for (; s; s = s->next) {
0e05808dc59a321566303084c84b9826a4353cefrederpj mls = ap_get_module_config(s->module_config, &log_config_module);
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpjstatic int init_config_log(apr_pool_t *pc, apr_pool_t *p, apr_pool_t *pt, server_rec *s)
0e05808dc59a321566303084c84b9826a4353cefrederpj /* First init the buffered logs array, which is needed when opening the logs. */
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem all_buffered_logs = apr_array_make(p, 5, sizeof(buffered_log *));
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem /* Next, do "physical" server, which gets default log fd and format
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj * for the virtual servers, if they don't override...
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj /* Then, virtual servers */
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem /* Now register the last buffer flush with the cleanup engine */
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj buffered_log **array = (buffered_log **)all_buffered_logs->elts;
0e05808dc59a321566303084c84b9826a4353cefrederpj apr_pool_cleanup_register(p, s, flush_all_logs, flush_all_logs);
9efd5708f6f0ab1992f6a5233eb622ad5e4eae18sf "could not initialize buffered log mutex, "
0e05808dc59a321566303084c84b9826a4353cefrederpj "transfer log may become corrupted");
0e05808dc59a321566303084c84b9826a4353cefrederpjstatic void ap_register_log_handler(apr_pool_t *p, char *tag,
0e05808dc59a321566303084c84b9826a4353cefrederpj ap_log_handler *log_struct = apr_palloc(p, sizeof(*log_struct));
0e05808dc59a321566303084c84b9826a4353cefrederpj apr_hash_set(log_hash, tag, 1, (const void *)log_struct);
0e05808dc59a321566303084c84b9826a4353cefrederpjstatic ap_log_writer_init* ap_log_set_writer_init(ap_log_writer_init *handle)
0e05808dc59a321566303084c84b9826a4353cefrederpjstatic ap_log_writer *ap_log_set_writer(ap_log_writer *handle)
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpjstatic apr_status_t ap_default_log_writer( request_rec *r,
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem const char **strs,
9efd5708f6f0ab1992f6a5233eb622ad5e4eae18sfstatic void *ap_default_log_writer_init(apr_pool_t *p, server_rec *s,
9efd5708f6f0ab1992f6a5233eb622ad5e4eae18sf const char* name)
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpj rv = apr_file_open(&fd, fname, xfer_flags, xfer_perms, p);
8113dac419143273351446c3ad653f3fe5ba5cfdwrowestatic void *ap_buffered_log_writer_init(apr_pool_t *p, server_rec *s,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes const char* name)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes b->handle = ap_default_log_writer_init(p, s, name);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes *(buffered_log **)apr_array_push(all_buffered_logs) = b;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholesstatic apr_status_t ap_buffered_log_writer(request_rec *r,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes const char **strs,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if ((rv = APR_ANYLOCK_LOCK(&buf->mutex)) != APR_SUCCESS) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes for (i = 0, s = &buf->outbuf[buf->outcnt]; i < nelts; ++i) {
c4f16f709c79bb7e2ddffb532bc7708eab9a9691covenerstatic int log_pre_config(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes static APR_OPTIONAL_FN_TYPE(ap_register_log_handler) *log_pfn_register;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes log_pfn_register = APR_RETRIEVE_OPTIONAL_FN(ap_register_log_handler);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes log_pfn_register(p, "X", log_connection_status, 0);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes log_pfn_register(p, "k", log_requests_on_connection, 0);
37af4b0cf648275b68ff41c866c665b4ccf4667dcovener log_pfn_register(p, "D", log_request_duration_microseconds, 1);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes ap_hook_pre_config(log_pre_config,NULL,NULL,APR_HOOK_REALLY_FIRST);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes ap_hook_child_init(init_child,NULL,NULL,APR_HOOK_MIDDLE);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes ap_hook_open_logs(init_config_log,NULL,NULL,APR_HOOK_MIDDLE);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes ap_hook_log_transaction(multi_log_transaction,NULL,NULL,APR_HOOK_MIDDLE);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* Init log_hash before we register the optional function. It is
e8f95a682820a599fe41b22977010636be5c2717jim * possible for the optional function, ap_register_log_handler,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * to be called before any other mod_log_config hooks are called.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * As a policy, we should init everything required by an optional function
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * before calling APR_REGISTER_OPTIONAL_FN.