log.c revision 4bb7ba7c1f9972b443562faf99151ccec854446f
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding/* Copyright 1999-2004 The Apache Software Foundation
ab2c1c1c83ec91415565da5a71fbc15d9685caa6fielding * Licensed under the Apache License, Version 2.0 (the "License");
33bdcae1f7a1a65e351dda2a766a0cf28b1e695dnd * you may not use this file except in compliance with the License.
ab2c1c1c83ec91415565da5a71fbc15d9685caa6fielding * You may obtain a copy of the License at
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * Unless required by applicable law or agreed to in writing, software
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * distributed under the License is distributed on an "AS IS" BASIS,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
ab2c1c1c83ec91415565da5a71fbc15d9685caa6fielding * See the License for the specific language governing permissions and
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * limitations under the License.
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * http_log.c: Dealing with the logs and errors
ab2c1c1c83ec91415565da5a71fbc15d9685caa6fielding * Rob McCool
0f081398cf0eef8cc7c66a535d450110a92dc8aefieldingtypedef struct {
0f081398cf0eef8cc7c66a535d450110a92dc8aefieldingint AP_DECLARE_DATA ap_default_loglevel = DEFAULT_LOGLEVEL;
fd0075570654d8f3473f12c47f507c8b3c59a8e4stoddardAP_DECLARE(apr_status_t) ap_replace_stderr_log(apr_pool_t *p,
fd0075570654d8f3473f12c47f507c8b3c59a8e4stoddard const char *fname)
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding char *filename = ap_server_root_relative(p, fname);
fd0075570654d8f3473f12c47f507c8b3c59a8e4stoddard APR_EBADPATH, NULL, "Invalid -E error log file %s",
fd0075570654d8f3473f12c47f507c8b3c59a8e4stoddard APR_APPEND | APR_WRITE | APR_CREATE | APR_LARGEFILE,
3bc407b46a67691f3e5fd4f5f5ead4e1eff09998stoddard "%s: could not open error log file %s.",
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if ((rc = apr_file_open_stderr(&stderr_log, p)) == APR_SUCCESS) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if ((rc = apr_file_dup2(stderr_log, stderr_file, p)) == APR_SUCCESS) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding "unable to replace stderr with error_log");
fd0075570654d8f3473f12c47f507c8b3c59a8e4stoddardstatic void log_child_errfn(apr_pool_t *pool, apr_status_t err,
0329db7881b698897213e816552b0ab31f8d4d56trawickstatic int log_child(apr_pool_t *p, const char *progname,
fd0075570654d8f3473f12c47f507c8b3c59a8e4stoddard /* Child process code for 'ErrorLog "|..."';
fd0075570654d8f3473f12c47f507c8b3c59a8e4stoddard * may want a common framework for this, since I expect it will
0329db7881b698897213e816552b0ab31f8d4d56trawick * be common for other foo-loggers to want this sort of thing...
ed4b039edaff2a734bd8da9c33e43e2fb8dd0db9ianh if (((rc = apr_procattr_create(&procattr, p)) == APR_SUCCESS)
fd0075570654d8f3473f12c47f507c8b3c59a8e4stoddard && ((rc = apr_procattr_error_check_set(procattr, 1)) == APR_SUCCESS)
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm && ((rc = apr_procattr_child_errfn_set(procattr, log_child_errfn)) == APR_SUCCESS)) {
a6b9ed64fdf548c61de9714e2cfb999ec59d149cgstein const char *pname;
71f3601de4983bc2a6aaffcf37dc1d35c8674a34coar procnew = (apr_proc_t *)apr_pcalloc(p, sizeof(*procnew));
a6b9ed64fdf548c61de9714e2cfb999ec59d149cgstein rc = apr_proc_create(procnew, pname, (const char * const *)args,
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm apr_pool_note_subprocess(p, procnew, APR_KILL_AFTER_TIMEOUT);
a6b9ed64fdf548c61de9714e2cfb999ec59d149cgsteinstatic int open_error_log(server_rec *s, apr_pool_t *p)
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding const char *fname;
a6b9ed64fdf548c61de9714e2cfb999ec59d149cgstein /* This starts a new process... */
fd0075570654d8f3473f12c47f507c8b3c59a8e4stoddard "Couldn't start ErrorLog process");
a47a28784ca46876076471d2a0b45c11f800bffestoddard else if (!strncasecmp(s->error_fname, "syslog", 6)) {
fd0075570654d8f3473f12c47f507c8b3c59a8e4stoddard openlog(ap_server_argv0, LOG_NDELAY|LOG_CONS|LOG_PID,
a47a28784ca46876076471d2a0b45c11f800bffestoddard openlog(ap_server_argv0, LOG_NDELAY|LOG_CONS|LOG_PID, LOG_LOCAL7);
a47a28784ca46876076471d2a0b45c11f800bffestoddard fname = ap_server_root_relative(p, s->error_fname);
a47a28784ca46876076471d2a0b45c11f800bffestoddard ap_log_error(APLOG_MARK, APLOG_STARTUP, APR_EBADPATH, NULL,
a47a28784ca46876076471d2a0b45c11f800bffestoddard "%s: Invalid error log path %s.",
a47a28784ca46876076471d2a0b45c11f800bffestoddard APR_APPEND | APR_WRITE | APR_CREATE | APR_LARGEFILE,
a47a28784ca46876076471d2a0b45c11f800bffestoddard "%s: could not open error log file %s.",
a47a28784ca46876076471d2a0b45c11f800bffestoddardint ap_open_logs(apr_pool_t *pconf, apr_pool_t *p /* plog */,
fd0075570654d8f3473f12c47f507c8b3c59a8e4stoddard /* replace stderr with this new log */
fd0075570654d8f3473f12c47f507c8b3c59a8e4stoddard if ((rc = apr_file_open_stderr(&errfile, p)) == APR_SUCCESS) {
ed4b039edaff2a734bd8da9c33e43e2fb8dd0db9ianh "unable to replace stderr with error_log");
fd0075570654d8f3473f12c47f507c8b3c59a8e4stoddard /* note that stderr may still need to be replaced with something
fd0075570654d8f3473f12c47f507c8b3c59a8e4stoddard * because it points to the old error log, or back to the tty
fd0075570654d8f3473f12c47f507c8b3c59a8e4stoddard * of the submitter.
fd0075570654d8f3473f12c47f507c8b3c59a8e4stoddard * XXX: This is BS - /dev/null is non-portable
fd0075570654d8f3473f12c47f507c8b3c59a8e4stoddard if (replace_stderr && freopen("/dev/null", "w", stderr) == NULL) {
fd0075570654d8f3473f12c47f507c8b3c59a8e4stoddard ap_log_error(APLOG_MARK, APLOG_CRIT, errno, s_main,
fd0075570654d8f3473f12c47f507c8b3c59a8e4stoddard "unable to replace stderr with /dev/null");
fd0075570654d8f3473f12c47f507c8b3c59a8e4stoddard for (virt = s_main->next; virt; virt = virt->next) {
fd0075570654d8f3473f12c47f507c8b3c59a8e4stoddard && strcmp(q->error_fname, virt->error_fname) == 0) {
fd0075570654d8f3473f12c47f507c8b3c59a8e4stoddard if (q == virt) {
fd0075570654d8f3473f12c47f507c8b3c59a8e4stoddardAP_DECLARE(void) ap_error_log2stderr(server_rec *s) {
fd0075570654d8f3473f12c47f507c8b3c59a8e4stoddard apr_file_dup2(s->error_log, errfile, s->process->pool);
ba4c566c200c2436dae841b7c811807c80cd712afieldingstatic void log_error_core(const char *file, int line, int level,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding const char *referer;
71f3601de4983bc2a6aaffcf37dc1d35c8674a34coar if (s == NULL) {
71f3601de4983bc2a6aaffcf37dc1d35c8674a34coar * If we are doing stderr logging (startup), don't log messages that are
71f3601de4983bc2a6aaffcf37dc1d35c8674a34coar * above the default server log level unless it is a startup/shutdown
71f3601de4983bc2a6aaffcf37dc1d35c8674a34coar else if (s->error_log) {
71f3601de4983bc2a6aaffcf37dc1d35c8674a34coar * If we are doing normal logging, don't log messages that are
71f3601de4983bc2a6aaffcf37dc1d35c8674a34coar * above the server log level unless it is a startup/shutdown notice
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * If we are doing normal logging, don't log messages that are
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * above the server log level unless it is a startup/shutdown notice
3bc407b46a67691f3e5fd4f5f5ead4e1eff09998stoddard#endif /* TPF */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * If we are doing syslog logging, don't log messages that are
ba4c566c200c2436dae841b7c811807c80cd712afielding * above the server log level (including a startup/shutdown notice)
3bc407b46a67691f3e5fd4f5f5ead4e1eff09998stoddard if (logf && ((level & APLOG_STARTUP) != APLOG_STARTUP)) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding len += apr_snprintf(errstr + len, MAX_STRING_LEN - len,
a47a28784ca46876076471d2a0b45c11f800bffestoddard /* In OSD/POSIX, the compiler returns for __FILE__
fd709745f1226d683c57ad9bbcdd05971d214d0cstoddard * a string like: __FILE__="*POSIX(/usr/include/stdio.h)"
fd709745f1226d683c57ad9bbcdd05971d214d0cstoddard * (it even returns an absolute path for sources in
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * the current directory). Here we try to strip this
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * down to the basename.
fd0075570654d8f3473f12c47f507c8b3c59a8e4stoddard if (*e == ')') {
fd709745f1226d683c57ad9bbcdd05971d214d0cstoddard#endif /*_OSD_POSIX*/
ea92d0ffcb30b186010a2c8ca2c80d2ac09e34dastoddard len += apr_snprintf(errstr + len, MAX_STRING_LEN - len,
fd709745f1226d683c57ad9bbcdd05971d214d0cstoddard#endif /* TPF */
fd709745f1226d683c57ad9bbcdd05971d214d0cstoddard if (r && r->connection) {
71f3601de4983bc2a6aaffcf37dc1d35c8674a34coar /* XXX: TODO: add a method of selecting whether logged client
fd709745f1226d683c57ad9bbcdd05971d214d0cstoddard * addresses are in dotted quad or resolved form... dotted
fd709745f1226d683c57ad9bbcdd05971d214d0cstoddard * quad is the most secure, which is why I'm implementing it
fd709745f1226d683c57ad9bbcdd05971d214d0cstoddard * first. -djg
fd709745f1226d683c57ad9bbcdd05971d214d0cstoddard len += apr_snprintf(errstr + len, MAX_STRING_LEN - len,
ea92d0ffcb30b186010a2c8ca2c80d2ac09e34dastoddard len += apr_snprintf(errstr + len, MAX_STRING_LEN - len,
ea92d0ffcb30b186010a2c8ca2c80d2ac09e34dastoddard len += apr_snprintf(errstr + len, MAX_STRING_LEN - len,
ea92d0ffcb30b186010a2c8ca2c80d2ac09e34dastoddard len += apr_snprintf(errstr + len, MAX_STRING_LEN - len,
fd0075570654d8f3473f12c47f507c8b3c59a8e4stoddard len += apr_snprintf(errstr + len, MAX_STRING_LEN - len,
fd0075570654d8f3473f12c47f507c8b3c59a8e4stoddard apr_strerror(status, errstr + len, MAX_STRING_LEN - len);
fd0075570654d8f3473f12c47f507c8b3c59a8e4stoddard if (apr_vsnprintf(scratch, MAX_STRING_LEN - len, fmt, args)) {
fd0075570654d8f3473f12c47f507c8b3c59a8e4stoddard len += ap_escape_errorlog_item(errstr + len, scratch,
fd0075570654d8f3473f12c47f507c8b3c59a8e4stoddard len += apr_vsnprintf(errstr + len, MAX_STRING_LEN - len, fmt, args);
fd0075570654d8f3473f12c47f507c8b3c59a8e4stoddard if ( r && (referer = apr_table_get(r->headers_in, "Referer"))
3bc407b46a67691f3e5fd4f5f5ead4e1eff09998stoddard && ap_escape_errorlog_item(scratch, referer, MAX_STRING_LEN - len)
3bc407b46a67691f3e5fd4f5f5ead4e1eff09998stoddard len += apr_snprintf(errstr + len, MAX_STRING_LEN - len,
3bc407b46a67691f3e5fd4f5f5ead4e1eff09998stoddard ", referer: %s",
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* NULL if we are logging to syslog */
71f3601de4983bc2a6aaffcf37dc1d35c8674a34coar /* Truncate for the terminator (as apr_snprintf does) */
ea92d0ffcb30b186010a2c8ca2c80d2ac09e34dastoddard ap_run_error_log(file, line, level, status, s, r, pool, errstr + errstrlen);
fd709745f1226d683c57ad9bbcdd05971d214d0cstoddardAP_DECLARE(void) ap_log_error(const char *file, int line, int level,
fd709745f1226d683c57ad9bbcdd05971d214d0cstoddard const char *fmt, ...)
fd709745f1226d683c57ad9bbcdd05971d214d0cstoddard log_error_core(file, line, level, status, s, NULL, NULL, fmt, args);
fd709745f1226d683c57ad9bbcdd05971d214d0cstoddardAP_DECLARE(void) ap_log_perror(const char *file, int line, int level,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding const char *fmt, ...)
fd0075570654d8f3473f12c47f507c8b3c59a8e4stoddard log_error_core(file, line, level, status, NULL, NULL, p, fmt, args);
0f081398cf0eef8cc7c66a535d450110a92dc8aefieldingAP_DECLARE(void) ap_log_rerror(const char *file, int line, int level,
ea92d0ffcb30b186010a2c8ca2c80d2ac09e34dastoddard const char *fmt, ...)
3bc407b46a67691f3e5fd4f5f5ead4e1eff09998stoddard log_error_core(file, line, level, status, r->server, r, NULL, fmt, args);
3bc407b46a67691f3e5fd4f5f5ead4e1eff09998stoddard * IF APLOG_TOCLIENT is set,
3bc407b46a67691f3e5fd4f5f5ead4e1eff09998stoddard * AND the error level is 'warning' or more severe,
3bc407b46a67691f3e5fd4f5f5ead4e1eff09998stoddard * AND there isn't already error text associated with this request,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * THEN make the message text available to ErrorDocument and
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * other error processors.
ea92d0ffcb30b186010a2c8ca2c80d2ac09e34dastoddard && (apr_table_get(r->notes, "error-notes") == NULL)) {
ea92d0ffcb30b186010a2c8ca2c80d2ac09e34dastoddard ap_escape_html(r->pool, apr_pvsprintf(r->pool, fmt,
ea92d0ffcb30b186010a2c8ca2c80d2ac09e34dastoddardAP_DECLARE(void) ap_log_pid(apr_pool_t *p, const char *filename)
71f3601de4983bc2a6aaffcf37dc1d35c8674a34coar const char *fname;
71f3601de4983bc2a6aaffcf37dc1d35c8674a34coar ap_log_error(APLOG_MARK, APLOG_STARTUP|APLOG_CRIT, APR_EBADPATH,
71f3601de4983bc2a6aaffcf37dc1d35c8674a34coar NULL, "Invalid PID file path %s, ignoring.", filename);
ea92d0ffcb30b186010a2c8ca2c80d2ac09e34dastoddard && apr_stat(&finfo, fname, APR_FINFO_MTIME, p) == APR_SUCCESS) {
ea92d0ffcb30b186010a2c8ca2c80d2ac09e34dastoddard /* AP_SIG_GRACEFUL and HUP call this on each restart.
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * Only warn on first time through for this pid.
a47a28784ca46876076471d2a0b45c11f800bffestoddard * XXX: Could just write first time through too, although
ea92d0ffcb30b186010a2c8ca2c80d2ac09e34dastoddard * that may screw up scripts written to do something
ea92d0ffcb30b186010a2c8ca2c80d2ac09e34dastoddard * based on the last modification time of the pid file.
71f3601de4983bc2a6aaffcf37dc1d35c8674a34coar "pid file %s overwritten -- Unclean "
3bc407b46a67691f3e5fd4f5f5ead4e1eff09998stoddard "shutdown of previous Apache run?",
ea92d0ffcb30b186010a2c8ca2c80d2ac09e34dastoddard APR_UREAD | APR_UWRITE | APR_GREAD | APR_WREAD, p))
71f3601de4983bc2a6aaffcf37dc1d35c8674a34coar "%s: could not log pid to file %s",
71f3601de4983bc2a6aaffcf37dc1d35c8674a34coar apr_file_printf(pid_file, "%ld" APR_EOL_STR, (long)mypid);
71f3601de4983bc2a6aaffcf37dc1d35c8674a34coarAP_DECLARE(apr_status_t) ap_read_pid(apr_pool_t *p, const char *filename,
71f3601de4983bc2a6aaffcf37dc1d35c8674a34coar const apr_size_t BUFFER_SIZE = sizeof(long) * 3 + 2; /* see apr_ltoa */
71f3601de4983bc2a6aaffcf37dc1d35c8674a34coar const char *fname;
71f3601de4983bc2a6aaffcf37dc1d35c8674a34coar ap_log_error(APLOG_MARK, APLOG_STARTUP|APLOG_CRIT, APR_EBADPATH,
71f3601de4983bc2a6aaffcf37dc1d35c8674a34coar NULL, "Invalid PID file path %s, ignoring.", filename);
71f3601de4983bc2a6aaffcf37dc1d35c8674a34coar rv = apr_file_open(&pid_file, fname, APR_READ, APR_OS_DEFAULT, p);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* Ensure null-termination, so that strtol doesn't go crazy. */
a6b9ed64fdf548c61de9714e2cfb999ec59d149cgstein rv = apr_file_read_full(pid_file, buf, BUFFER_SIZE - 1, &bytes_read);
3bc407b46a67691f3e5fd4f5f5ead4e1eff09998stoddard /* If we fill the buffer, we're probably reading a corrupt pid file.
ea92d0ffcb30b186010a2c8ca2c80d2ac09e34dastoddard * To be nice, let's also ensure the first char is a digit. */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if (bytes_read == BUFFER_SIZE - 1 || !apr_isdigit(*buf)) {
71f3601de4983bc2a6aaffcf37dc1d35c8674a34coarAP_DECLARE(void) ap_log_assert(const char *szExp, const char *szFile,
fd0075570654d8f3473f12c47f507c8b3c59a8e4stoddard "[%s] file %s, line %d, assertion \"%s\" failed",
417f504d4d11631c0d062be85347f82a26c88677aaron /* unix assert does an abort leading to a core dump */
ed4b039edaff2a734bd8da9c33e43e2fb8dd0db9ianh/* piped log support */
fd0075570654d8f3473f12c47f507c8b3c59a8e4stoddard/* forward declaration */
fd0075570654d8f3473f12c47f507c8b3c59a8e4stoddardstatic void piped_log_maintenance(int reason, void *data, apr_wait_t status);
71f3601de4983bc2a6aaffcf37dc1d35c8674a34coar if (((status = apr_procattr_create(&procattr, pl->p)) != APR_SUCCESS) ||
577a76180006add04a166b12f1ad130aeedeaa5estoddard ((status = apr_procattr_child_errfn_set(procattr, log_child_errfn))
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding ((status = apr_procattr_error_check_set(procattr, 1)) != APR_SUCCESS)) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* Something bad happened, give up and go away. */
577a76180006add04a166b12f1ad130aeedeaa5estoddard "piped_log_spawn: unable to setup child process '%s': %s",
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding pl->program, apr_strerror(status, buf, sizeof(buf)));
char **args;
const char *pname;
return rc;
int mpm_state;
switch (reason) {
case APR_OC_REASON_DEATH:
case APR_OC_REASON_LOST:
case APR_OC_REASON_UNWRITABLE:
case APR_OC_REASON_RESTART:
case APR_OC_REASON_UNREGISTER:
return APR_SUCCESS;
pl->p = p;
return NULL;
return NULL;
return pl;
return APR_SUCCESS;
int rc;
return NULL;
pl->p = p;
return pl;