mod_log_config.c revision 5c05c1f29be5bc37b22794737ee63a5f567053b5
f743002678eb67b99bbc29fee116b65d9530fec0wrowe/* Licensed to the Apache Software Foundation (ASF) under one or more
80833bb9a1bf25dcf19e814438a4b311d2e1f4cffuankg * contributor license agreements. See the NOTICE file distributed with
09c87c777bed1655621bb20e1c46cb6b1a63279dcovener * this work for additional information regarding copyright ownership.
3060ce7f798fbda7999cd4ddf89b525d2b294185covener * The ASF licenses this file to You under the Apache License, Version 2.0
3060ce7f798fbda7999cd4ddf89b525d2b294185covener * (the "License"); you may not use this file except in compliance with
3060ce7f798fbda7999cd4ddf89b525d2b294185covener * the License. You may obtain a copy of the License at
09c87c777bed1655621bb20e1c46cb6b1a63279dcovener * Unless required by applicable law or agreed to in writing, software
c85eff31536e6bfef1537b2435564d48665435d3rpluem * distributed under the License is distributed on an "AS IS" BASIS,
c85eff31536e6bfef1537b2435564d48665435d3rpluem * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
c85eff31536e6bfef1537b2435564d48665435d3rpluem * See the License for the specific language governing permissions and
c85eff31536e6bfef1537b2435564d48665435d3rpluem * limitations under the License.
c1a63b8fad09c419c1a64f75993feb8a343a6801ylavic * Modified by djm@va.pubnix.com:
c1a63b8fad09c419c1a64f75993feb8a343a6801ylavic * If no TransferLog is given explicitly, decline to log.
8eb78a55c83fee3383fd2862f66a3ab20d059283rjung * This is module implements the TransferLog directive (same as the
8eb78a55c83fee3383fd2862f66a3ab20d059283rjung * common log module), and additional directives, LogFormat and CustomLog.
393e1bb47b60cf97d521c49cf929740f32b95758kbrand * TransferLog fn Logs transfers to fn in standard log format, unless
393e1bb47b60cf97d521c49cf929740f32b95758kbrand * a custom format is set with LogFormat
393e1bb47b60cf97d521c49cf929740f32b95758kbrand * LogFormat format Set a log format from TransferLog files
8af5a3bd941a25b28ff9c84c513d6aa9f48f2cdcrjung * CustomLog fn format
8af5a3bd941a25b28ff9c84c513d6aa9f48f2cdcrjung * Log to file fn with format given by the format
42b6ba421855a65673ad46844a0be899e4ad9405rjung * CookieLog fn For backwards compatability with old Cookie
d41624899afd4656a24fa839431ade65da56c4a5rjung * logging module - now deprecated.
d41624899afd4656a24fa839431ade65da56c4a5rjung * There can be any number of TransferLog and CustomLog
e6b4bd1113567627ab6bb6c6a7105e1e01a7d889jailletc * commands. Each request will be logged to _ALL_ the
e6b4bd1113567627ab6bb6c6a7105e1e01a7d889jailletc * named files, in the appropriate format.
e466c40e1801982602ee0200c9e8b61cc148742djailletc * If no TransferLog or CustomLog directive appears in a VirtualHost,
457468b82e59d01eba00dd9d0817309c8f5e414ejim * the request will be logged to the log file(s) defined outside
457468b82e59d01eba00dd9d0817309c8f5e414ejim * the virtual host section. If a TransferLog or CustomLog directive
457468b82e59d01eba00dd9d0817309c8f5e414ejim * appears in the VirtualHost section, the log files defined outside
04983e3bd1754764eec7d6bb772fe3b0bf391771jorton * the VirtualHost will _not_ be used. This makes this module compatable
04983e3bd1754764eec7d6bb772fe3b0bf391771jorton * with the CLF and config log modules, where the use of TransferLog
15890c9306ba98f6fc243e15a3c4778ddc7d773erpluem * inside the VirtualHost section overrides its use outside.
15660979a30d251681463de2e0584853890082accovener * Examples:
15660979a30d251681463de2e0584853890082accovener * TransferLog logs/access_log
cfd9415521847b2f9394fad04fb701cfb955f503rjung * <VirtualHost>
cfd9415521847b2f9394fad04fb701cfb955f503rjung * LogFormat "... custom format ..."
cfd9415521847b2f9394fad04fb701cfb955f503rjung * TransferLog log/virtual_only
28c31fb73c1264bd1d0ff932573677030b024c7dwrowe * CustomLog log/virtual_useragents "%t %{user-agent}i"
28c31fb73c1264bd1d0ff932573677030b024c7dwrowe * </VirtualHost>
28c31fb73c1264bd1d0ff932573677030b024c7dwrowe * This will log using CLF to access_log any requests handled by the
28c31fb73c1264bd1d0ff932573677030b024c7dwrowe * main server, while any requests to the virtual host will be logged
8491e0600f69b0405e156ea8a419653c065c645bcovener * with the "... custom format..." to virtual_only _AND_ using
63b9f1f5880391261705f696d7d65507bbe9ace3covener * the custom user-agent log to virtual_useragents.
63b9f1f5880391261705f696d7d65507bbe9ace3covener * Note that the NCSA referer and user-agent logs are easily added with
87a26948305eab2bab8a4fb3f2a21f6725055790covener * CustomLog:
87a26948305eab2bab8a4fb3f2a21f6725055790covener * CustomLog logs/referer "%{referer}i -> %U"
87a26948305eab2bab8a4fb3f2a21f6725055790covener * CustomLog logs/agent "%{user-agent}i"
4efd27d2bd53a819a194f8a942f8881c1927755eylavic * RefererIgnore functionality can be obtained with conditional
4efd27d2bd53a819a194f8a942f8881c1927755eylavic * logging (SetEnvIf and CustomLog ... env=!VAR).
983528026996668ea295be95aedb9c7a346af470ylavic * But using this method allows much easier modification of the
983528026996668ea295be95aedb9c7a346af470ylavic * log format, e.g. to log hosts along with UA:
983528026996668ea295be95aedb9c7a346af470ylavic * CustomLog logs/referer "%{referer}i %U %h"
249ab52ef73a2b33446ae07904e3526b57251411ylavic * The argument to LogFormat and CustomLog is a string, which can include
249ab52ef73a2b33446ae07904e3526b57251411ylavic * literal characters copied into the log files, and '%' directives as
1f0836d4b1a203c7b375daae691beb95f6036205ylavic * %...B: bytes sent, excluding HTTP headers.
3b11e6ec1c5273d6a8968460db650e7ca99c49c0ylavic * %...b: bytes sent, excluding HTTP headers in CLF format, i.e. a '-'
3b11e6ec1c5273d6a8968460db650e7ca99c49c0ylavic * when no bytes where sent (rather than a '0'.
3b11e6ec1c5273d6a8968460db650e7ca99c49c0ylavic * %...{FOOBAR}C: The contents of the HTTP cookie FOOBAR
01402a0fbec8bd11f6c10d8ef9c9cceac68bb787ylavic * %...{FOOBAR}e: The contents of the environment variable FOOBAR
01402a0fbec8bd11f6c10d8ef9c9cceac68bb787ylavic * %...f: filename
01402a0fbec8bd11f6c10d8ef9c9cceac68bb787ylavic * %...h: remote host
49dacedb6c387b786b7911082ff35121a45f414bcovener * %...a: remote IP-address
49dacedb6c387b786b7911082ff35121a45f414bcovener * %...A: local IP-address
49dacedb6c387b786b7911082ff35121a45f414bcovener * %...{Foobar}i: The contents of Foobar: header line(s) in the request
49dacedb6c387b786b7911082ff35121a45f414bcovener * sent to the client.
3c990331fc6702119e4f5b8ba9eae3021aea5265jim * %...k: number of requests served over this connection
3c990331fc6702119e4f5b8ba9eae3021aea5265jim * %...l: remote logname (from identd, if supplied)
3c990331fc6702119e4f5b8ba9eae3021aea5265jim * %...{Foobar}n: The contents of note "Foobar" from another module.
3c990331fc6702119e4f5b8ba9eae3021aea5265jim * %...{Foobar}o: The contents of Foobar: header line(s) in the reply.
fc42512879dd0504532f52fe5d0d0383dda96a1eniq * %...p: the canonical port for the server
fc42512879dd0504532f52fe5d0d0383dda96a1eniq * %...{format}p: the canonical port for the server, or the actual local
fc42512879dd0504532f52fe5d0d0383dda96a1eniq * or remote port
0451df5dc50fa5d8b3e07d92ee6a92e36a1181a5niq * %...P: the process ID of the child that serviced the request.
0451df5dc50fa5d8b3e07d92ee6a92e36a1181a5niq * %...{format}P: the process ID or thread ID of the child/thread that
0451df5dc50fa5d8b3e07d92ee6a92e36a1181a5niq * serviced the request
da0442c0440caef34706e2c2f3af05cb65921cc0jailletc * %...r: first line of request
983528026996668ea295be95aedb9c7a346af470ylavic * %...s: status. For requests that got internally redirected, this
da0442c0440caef34706e2c2f3af05cb65921cc0jailletc * is status of the *original* request --- %...>s for the last.
da0442c0440caef34706e2c2f3af05cb65921cc0jailletc * %...t: time, in common log format time format
06b8f183140c8e02e0974e938a05078b511d1603covener * %...{format}t: The time, in the form given by format, which should
06b8f183140c8e02e0974e938a05078b511d1603covener * be in strftime(3) format.
06b8f183140c8e02e0974e938a05078b511d1603covener * %...T: the time taken to serve the request, in seconds.
15890c9306ba98f6fc243e15a3c4778ddc7d773erpluem * %...D: the time taken to serve the request, in micro seconds.
259878293a997ff49f5ddfc53d3739cbdc25444ecovener * %...u: remote user (from auth; may be bogus if return status (%s) is 401)
259878293a997ff49f5ddfc53d3739cbdc25444ecovener * %...U: the URL path requested.
259878293a997ff49f5ddfc53d3739cbdc25444ecovener * %...v: the configured name of the server (i.e. which virtual host?)
259878293a997ff49f5ddfc53d3739cbdc25444ecovener * %...V: the server name according to the UseCanonicalName setting
15890c9306ba98f6fc243e15a3c4778ddc7d773erpluem * %...m: the request method
b54b024c06a19926832d77d40ba35ad8c41e4d3dminfrin * %...H: the request protocol
b54b024c06a19926832d77d40ba35ad8c41e4d3dminfrin * %...q: the query string prepended by "?", or empty if no query string
b54b024c06a19926832d77d40ba35ad8c41e4d3dminfrin * %...X: Status of the connection.
65967d05f839dbf27cf91d91fa79585eeae19660minfrin * 'X' = connection aborted before the response completed.
65967d05f839dbf27cf91d91fa79585eeae19660minfrin * '+' = connection may be kept alive after the response is sent.
65967d05f839dbf27cf91d91fa79585eeae19660minfrin * '-' = connection will be closed after the response is sent.
65967d05f839dbf27cf91d91fa79585eeae19660minfrin (This directive was %...c in late versions of Apache 1.3, but
8152945ae46857b170cb227e79bb799f4fc7710dminfrin this conflicted with the historical ssl %...{var}c syntax.)
8152945ae46857b170cb227e79bb799f4fc7710dminfrin * The '...' can be nothing at all (e.g. "%h %u %r %s %b"), or it can
8152945ae46857b170cb227e79bb799f4fc7710dminfrin * indicate conditions for inclusion of the item (which will cause it
75f5c2db254c0167a0e396254460de09b775d203trawick * to be replaced with '-' if the condition is not met). Note that
75f5c2db254c0167a0e396254460de09b775d203trawick * there is no escaping performed on the strings from %r, %...i and
75f5c2db254c0167a0e396254460de09b775d203trawick * %...o; some with long memories may remember that I thought this was
11f1871b90149f8af3bf4e884dcc404436686967ylavic * a bad idea, once upon a time, and I'm still not comfortable with
11f1871b90149f8af3bf4e884dcc404436686967ylavic * it, but it is difficult to see how to "do the right thing" with all
11f1871b90149f8af3bf4e884dcc404436686967ylavic * of '%..i', unless we URL-escape everything and break with CLF.
4f0358189bfa57b8e75bd6b94db264302a8f336amrumph * The forms of condition are a list of HTTP status codes, which may
4f0358189bfa57b8e75bd6b94db264302a8f336amrumph * or may not be preceded by '!'. Thus, '%400,501{User-agent}i' logs
4f0358189bfa57b8e75bd6b94db264302a8f336amrumph * User-agent: on 400 errors and 501 errors (Bad Request, Not
5716f9c6daa92dde5f2f9d11ed63f7c9549c223atrawick * Implemented) only; '%!200,304,302{Referer}i' logs Referer: on all
5716f9c6daa92dde5f2f9d11ed63f7c9549c223atrawick * requests which did *not* return some sort of normal status.
5716f9c6daa92dde5f2f9d11ed63f7c9549c223atrawick * The default LogFormat reproduces CLF; see below.
54d750a84a175d8e338880514d440773eb986b50covener * The way this is supposed to work with virtual hosts is as follows:
54d750a84a175d8e338880514d440773eb986b50covener * a virtual host can have its own LogFormat, or its own TransferLog.
54d750a84a175d8e338880514d440773eb986b50covener * If it doesn't have its own LogFormat, it inherits from the main
54d750a84a175d8e338880514d440773eb986b50covener * server. If it doesn't have its own TransferLog, it writes to the
54d750a84a175d8e338880514d440773eb986b50covener * same descriptor (meaning the same process for "| ...").
54d750a84a175d8e338880514d440773eb986b50covener * --- rst */
fce4949fb0b309a5744afcd503c6ed2d35621ee2covener#define DEFAULT_LOG_FORMAT "%h %l %u %t \"%r\" %>s %b"
7b7430e701e9a31ce809da7c220bb8dfcf68c86etrawickstatic int xfer_flags = (APR_WRITE | APR_APPEND | APR_CREATE | APR_LARGEFILE);
ccc20788c1e5fc973f36df634399c89acb70deaejerenkrantzstatic apr_status_t ap_default_log_writer(request_rec *r,
273e512f20f262e5e2aa8e0e83371d1929fb76adjkaluza const char **strs,
fe83f60b41477b14a37edcfcd1f7f5c5a1ebfe44minfrinstatic apr_status_t ap_buffered_log_writer(request_rec *r,
fe83f60b41477b14a37edcfcd1f7f5c5a1ebfe44minfrin const char **strs,
ba050a6f942b9fa0e81ed73437588005c569655ccovenerstatic void *ap_default_log_writer_init(apr_pool_t *p, server_rec *s,
ba050a6f942b9fa0e81ed73437588005c569655ccovener const char* name);
ba050a6f942b9fa0e81ed73437588005c569655ccovenerstatic void *ap_buffered_log_writer_init(apr_pool_t *p, server_rec *s,
ba050a6f942b9fa0e81ed73437588005c569655ccovener const char* name);
135ddda3a989215d2bedbcf1529bfb269c3eda23niqstatic ap_log_writer_init* ap_log_set_writer_init(ap_log_writer_init *handle);
135ddda3a989215d2bedbcf1529bfb269c3eda23niqstatic ap_log_writer* ap_log_set_writer(ap_log_writer *handle);
001a44c352f89c9ec332ffd3e0a6927dcd19432chumbedoohstatic ap_log_writer *log_writer = ap_default_log_writer;
001a44c352f89c9ec332ffd3e0a6927dcd19432chumbedoohstatic ap_log_writer_init *log_writer_init = ap_default_log_writer_init;
001a44c352f89c9ec332ffd3e0a6927dcd19432chumbedoohstatic int buffered_logs = 0; /* default unbuffered */
cc5a4a08dc9783fcbc52ce86f11e01c281a43810minfrin/* POSIX.1 defines PIPE_BUF as the maximum number of bytes that is
33124689065ade0dfc8c54d8ebb734f9439cb89btrawick * guaranteed to be atomic when writing a pipe. And PIPE_BUF >= 512
33124689065ade0dfc8c54d8ebb734f9439cb89btrawick * is guaranteed. So we'll just guess 512 in the event the system
33124689065ade0dfc8c54d8ebb734f9439cb89btrawick * doesn't have this. Now, for file writes there is actually no limit,
9b0076ddd1103e5fa9c1f9bafde4b06ce244fbaecovener * the entire write is atomic. Whether all systems implement this
9b0076ddd1103e5fa9c1f9bafde4b06ce244fbaecovener * correctly is another question entirely ... so we'll just use PIPE_BUF
9b0076ddd1103e5fa9c1f9bafde4b06ce244fbaecovener * because it's probably a good guess as to what is implemented correctly
249d09d51808cb7981af99762c3b3736ca126cd5jkaluza * everywhere.
77ca16c5676da23155311e13cee61e7eaba9fa3ejailletc * multi_log_state is our per-(virtual)-server configuration. We store
77ca16c5676da23155311e13cee61e7eaba9fa3ejailletc * an array of the logs we are going to use, each of type config_log_state.
f87299dab99bc04b51a6b8cad51b6795db862c0atrawick * If a default log format is given by LogFormat, store in default_format
f87299dab99bc04b51a6b8cad51b6795db862c0atrawick * (backward compat. with mod_log_config). We also store for each virtual
f87299dab99bc04b51a6b8cad51b6795db862c0atrawick * server a pointer to the logs specified for the main server, so that if this
4d12805e6c18253040223ea637acd6b3b3c18f60jorton * vhost has no logs defined, we can use the main server's logs instead.
4d12805e6c18253040223ea637acd6b3b3c18f60jorton * So, for the main server, config_logs contains a list of the log files
4d12805e6c18253040223ea637acd6b3b3c18f60jorton * and server_config_logs is empty. For a vhost, server_config_logs
4d12805e6c18253040223ea637acd6b3b3c18f60jorton * points to the same array as config_logs in the main server, and
e5d909f2b06bd880fb3675cd49363df981caa631trawick * config_logs points to the array of logs defined inside this vhost,
a4df2cd1e1391575a327c2a90ba4315f805a0a78covener * which might be empty.
cb666b29f81df1d11d65002250153353568021fccovenertypedef struct {
1f50dc34ae069adeed20b2986e5ffdefa5c410e0covener * config_log_state holds the status of a single log file. fname might
1f50dc34ae069adeed20b2986e5ffdefa5c410e0covener * be NULL, which means this module does no logging for this
1f50dc34ae069adeed20b2986e5ffdefa5c410e0covener * request. format might be NULL, in which case the default_format
63a5ea80bddcc84a462e40f402b4f330e0e05411covener * from the multi_log_state should be used, or if that is NULL as
63a5ea80bddcc84a462e40f402b4f330e0e05411covener * well, use the CLF.
63a5ea80bddcc84a462e40f402b4f330e0e05411covener * log_writer is NULL before the log file is opened and is
63a5ea80bddcc84a462e40f402b4f330e0e05411covener * set to a opaque structure (usually a fd) after it is opened.
65a4e663b82f8bce28ac22ab2edfd7502de36998sftypedef struct {
a511a29faf2ff7ead3b67680154a624effb31aafminfrintypedef struct {
a511a29faf2ff7ead3b67680154a624effb31aafminfrin const char *fname;
6d601599d3d65df0410eae6e573e75b2dbfb1fb4minfrin * Format items...
6d601599d3d65df0410eae6e573e75b2dbfb1fb4minfrin * Note that many of these could have ap_sprintfs replaced with static buffers.
684e0cfc200f66287a93bbd1708d1dd8a92a7eefcovenertypedef struct {
ef82e8fa164e0a1f8b813f7deb6b7ead96018c94niq if (i <= 0) {
ef82e8fa164e0a1f8b813f7deb6b7ead96018c94niq return "-";
c12917da693bae4028a1d5a5e8224bceed8c739dsf return apr_itoa(p, i);
eafcc0ebf263d0ba69855b6e10958c4c1a2361bdsfstatic const char *constant_item(request_rec *dummy, char *stuff)
d7ffd2da16d58b1a0de212e4d56f7aebb72bef26sfstatic const char *log_remote_host(request_rec *r, char *a)
4576c1a9ef54cd1e5555ee07d016a7f559f80338sf return ap_escape_logitem(r->pool, ap_get_remote_host(r->connection,
88fac54d9d64f85bbdab5d7010816f4377f95bd7rjungstatic const char *log_remote_address(request_rec *r, char *a)
bd3f5647b96d378d9c75c954e3f13582af32c643sfstatic const char *log_local_address(request_rec *r, char *a)
2a7beea91d46beb41f043a84eaad060047ee04aafabienstatic const char *log_remote_logname(request_rec *r, char *a)
584a85dd4047e38d3ed3a29b6662fcc9d100ae4csf return ap_escape_logitem(r->pool, ap_get_remote_logname(r));
f21e9e3d0bfb7a507ecc5bc963f2159d693503d1sfstatic const char *log_remote_user(request_rec *r, char *a)
79c5787b92ac5f0e1cc82393816c77a006399316trawickstatic const char *log_request_line(request_rec *r, char *a)
c967bf3bc89e8aa60dbd30d9da388e448ddc1cc4trawick /* NOTE: If the original request contained a password, we
79c5787b92ac5f0e1cc82393816c77a006399316trawick * re-write the request line here to contain XXXXXX instead:
79c5787b92ac5f0e1cc82393816c77a006399316trawick * (note the truncation before the protocol string for HTTP/0.9 requests)
79c5787b92ac5f0e1cc82393816c77a006399316trawick * (note also that r->the_request contains the unmodified request)
3e4e54d4e3fc0123c63d57aa84ac7ad7a8c73ff8jortonstatic const char *log_request_file(request_rec *r, char *a)
53e9b27aba029b18be814df40bcf6f0428771d1efuankgstatic const char *log_request_uri(request_rec *r, char *a)
6bb524f1895f30265a1431afc460977d391cb36bsfstatic const char *log_request_method(request_rec *r, char *a)
e6dd71992459d05a676b98b7963423dc5dc1e24aminfrinstatic const char *log_request_protocol(request_rec *r, char *a)
23f1535d6a60817d2846bac0aea230ea475d7dccminfrinstatic const char *log_request_query(request_rec *r, char *a)
6249dfa569d3b4f1f539665b979a80c6e335d93etrawickstatic const char *clf_log_bytes_sent(request_rec *r, char *a)
6249dfa569d3b4f1f539665b979a80c6e335d93etrawick return "-";
cfa64348224b66dd1c9979b809406c4d15b1c137fieldingstatic const char *log_bytes_sent(request_rec *r, char *a)
74499a117b3b2cd9666715a14f90c0e5d1a4ee8ajim return "0";
const char *key)
struct sle {
const char *value;
return NULL;
if (!result_list) {
++t_elt;
if (result_list) {
while (rp) {
return result;
return NULL;
const char *cookies;
const char *start_cookie;
if (end_cookie) {
return NULL;
unsigned t_validate;
* See the comments in server/util_time.c for more information.
sizeof(*cached_time));
char sign;
int timz;
if (timz < 0) {
#if APR_HAS_THREADS
&tid);
const char **sa)
s = *sa;
s = *sa;
*sa = s;
return NULL;
const char *s = *sa;
*sa = ++s;
return NULL;
while (apr_isdigit(*++s)) {
if (!handler) {
*sa = s;
return NULL;
char *res;
return NULL;
s = APR_EOL_STR;
const char *cp;
int in_list = 0;
const char **strs;
int *strl;
char *envar;
return DECLINED;
return DECLINED;
return DECLINED;
orig = r;
while (r->next) {
r = r->next;
if (!log_writer) {
return HTTP_INTERNAL_SERVER_ERROR;
return OK;
return OK;
return mls;
return add;
const char *name)
return err_string;
return err_string;
const char *fn)
if (buffered_logs) {
return NULL;
{NULL}
return NULL;
return cls;
const char *dummy;
const char *format;
if (format) {
if (format) {
return DONE;
if (format) {
return DONE;
return OK;
if (!buffered_logs)
return APR_SUCCESS;
for (; s; s = s->next) {
if (log_list) {
return APR_SUCCESS;
int res;
if (buffered_logs) {
return res;
int mpm_threads;
if (buffered_logs) {
#if APR_HAS_THREADS
return old;
return old;
void *handle,
const char **strs,
int *strl,
int nelts,
char *str;
s += strl[i];
return rv;
const char* name)
return NULL;;
if (!fname) {
return NULL;
return NULL;
return fd;
const char* name)
buffered_log *b;
if (b->handle) {
return NULL;
void *handle,
const char **strs,
int *strl,
int nelts,
char *str;
return rv;
apr_size_t w;
s += strl[i];
w = len;
s += strl[i];
return rv;
if (log_pfn_register) {
return OK;