1 /* Copyright 1999-2005 The Apache Software Foundation or its licensors, as
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
18 * http_log.c: Dealing with the logs and errors
25 #include "apr_general.h" /* for signal stuff */
26 #include "apr_strings.h"
27 #include "apr_errno.h"
28 #include "apr_thread_proc.h"
30 #include "apr_signal.h"
32 #define APR_WANT_STDIO
33 #define APR_WANT_STRFUNC
45 #include "ap_config.h"
47 #include "http_config.h"
48 #include "http_core.h"
50 #include "http_main.h"
51 #include "util_time.h"
60 APR_HOOK_LINK(error_log)
63 int AP_DECLARE_DATA ap_default_loglevel = DEFAULT_LOGLEVEL;
67 static const TRANS facilities[] = {
70 {"authpriv",LOG_AUTHPRIV},
76 {"daemon", LOG_DAEMON},
94 {"syslog", LOG_SYSLOG},
103 {"local0", LOG_LOCAL0},
106 {"local1", LOG_LOCAL1},
109 {"local2", LOG_LOCAL2},
112 {"local3", LOG_LOCAL3},
115 {"local4", LOG_LOCAL4},
118 {"local5", LOG_LOCAL5},
121 {"local6", LOG_LOCAL6},
124 {"local7", LOG_LOCAL7},
130 static const TRANS priorities[] = {
131 {"emerg", APLOG_EMERG},
132 {"alert", APLOG_ALERT},
133 {"crit", APLOG_CRIT},
134 {"error", APLOG_ERR},
135 {"warn", APLOG_WARNING},
136 {"notice", APLOG_NOTICE},
137 {"info", APLOG_INFO},
138 {"debug", APLOG_DEBUG},
142 static apr_file_t *stderr_log = NULL;
144 AP_DECLARE(void) ap_open_stderr_log(apr_pool_t *p)
146 apr_file_open_stderr(&stderr_log, p);
149 AP_DECLARE(apr_status_t) ap_replace_stderr_log(apr_pool_t *p,
152 apr_file_t *stderr_file;
154 char *filename = ap_server_root_relative(p, fname);
156 ap_log_error(APLOG_MARK, APLOG_STARTUP|APLOG_CRIT,
157 APR_EBADPATH, NULL, "Invalid -E error log file %s",
161 if ((rc = apr_file_open(&stderr_file, filename,
162 APR_APPEND | APR_WRITE | APR_CREATE | APR_LARGEFILE,
163 APR_OS_DEFAULT, p)) != APR_SUCCESS) {
164 ap_log_error(APLOG_MARK, APLOG_STARTUP, rc, NULL,
165 "%s: could not open error log file %s.",
166 ap_server_argv0, fname);
169 if ((rc = apr_file_open_stderr(&stderr_log, p)) == APR_SUCCESS) {
170 apr_file_flush(stderr_log);
171 if ((rc = apr_file_dup2(stderr_log, stderr_file, p)) == APR_SUCCESS) {
172 apr_file_close(stderr_file);
175 if (rc != APR_SUCCESS) {
176 ap_log_error(APLOG_MARK, APLOG_CRIT, rc, NULL,
177 "unable to replace stderr with error_log");
182 static void log_child_errfn(apr_pool_t *pool, apr_status_t err,
183 const char *description)
185 ap_log_error(APLOG_MARK, APLOG_ERR, err, NULL,
189 static int log_child(apr_pool_t *p, const char *progname,
192 /* Child process code for 'ErrorLog "|..."';
193 * may want a common framework for this, since I expect it will
194 * be common for other foo-loggers to want this sort of thing...
197 apr_procattr_t *procattr;
200 if (((rc = apr_procattr_create(&procattr, p)) == APR_SUCCESS)
201 && ((rc = apr_procattr_cmdtype_set(procattr,
202 APR_SHELLCMD_ENV)) == APR_SUCCESS)
203 && ((rc = apr_procattr_io_set(procattr,
206 APR_NO_PIPE)) == APR_SUCCESS)
207 && ((rc = apr_procattr_error_check_set(procattr, 1)) == APR_SUCCESS)
208 && ((rc = apr_procattr_child_errfn_set(procattr, log_child_errfn)) == APR_SUCCESS)) {
212 apr_tokenize_to_argv(progname, &args, p);
213 pname = apr_pstrdup(p, args[0]);
214 procnew = (apr_proc_t *)apr_pcalloc(p, sizeof(*procnew));
215 rc = apr_proc_create(procnew, pname, (const char * const *)args,
218 if (rc == APR_SUCCESS) {
219 apr_pool_note_subprocess(p, procnew, APR_KILL_AFTER_TIMEOUT);
220 (*fpin) = procnew->in;
227 static int open_error_log(server_rec *s, apr_pool_t *p)
232 if (*s->error_fname == '|') {
233 apr_file_t *dummy = NULL;
235 /* This starts a new process... */
236 rc = log_child (p, s->error_fname + 1, &dummy);
237 if (rc != APR_SUCCESS) {
238 ap_log_error(APLOG_MARK, APLOG_STARTUP, rc, NULL,
239 "Couldn't start ErrorLog process");
243 s->error_log = dummy;
247 else if (!strncasecmp(s->error_fname, "syslog", 6)) {
248 if ((fname = strchr(s->error_fname, ':'))) {
252 for (fac = facilities; fac->t_name; fac++) {
253 if (!strcasecmp(fname, fac->t_name)) {
254 openlog(ap_server_argv0, LOG_NDELAY|LOG_CONS|LOG_PID,
262 openlog(ap_server_argv0, LOG_NDELAY|LOG_CONS|LOG_PID, LOG_LOCAL7);
269 fname = ap_server_root_relative(p, s->error_fname);
271 ap_log_error(APLOG_MARK, APLOG_STARTUP, APR_EBADPATH, NULL,
272 "%s: Invalid error log path %s.",
273 ap_server_argv0, s->error_fname);
276 if ((rc = apr_file_open(&s->error_log, fname,
277 APR_APPEND | APR_WRITE | APR_CREATE | APR_LARGEFILE,
278 APR_OS_DEFAULT, p)) != APR_SUCCESS) {
279 ap_log_error(APLOG_MARK, APLOG_STARTUP, rc, NULL,
280 "%s: could not open error log file %s.",
281 ap_server_argv0, fname);
289 int ap_open_logs(apr_pool_t *pconf, apr_pool_t *p /* plog */,
290 apr_pool_t *ptemp, server_rec *s_main)
292 apr_status_t rc = APR_SUCCESS;
293 server_rec *virt, *q;
295 apr_file_t *errfile = NULL;
297 if (open_error_log(s_main, p) != OK) {
302 if (s_main->error_log) {
303 /* replace stderr with this new log */
304 apr_file_flush(s_main->error_log);
305 if ((rc = apr_file_open_stderr(&errfile, p)) == APR_SUCCESS) {
306 rc = apr_file_dup2(errfile, s_main->error_log, p);
308 if (rc != APR_SUCCESS) {
309 ap_log_error(APLOG_MARK, APLOG_CRIT, rc, s_main,
310 "unable to replace stderr with error_log");
316 /* note that stderr may still need to be replaced with something
317 * because it points to the old error log, or back to the tty
319 * XXX: This is BS - /dev/null is non-portable
321 if (replace_stderr && freopen("/dev/null", "w", stderr) == NULL) {
322 ap_log_error(APLOG_MARK, APLOG_CRIT, errno, s_main,
323 "unable to replace stderr with /dev/null");
326 for (virt = s_main->next; virt; virt = virt->next) {
327 if (virt->error_fname) {
328 for (q=s_main; q != virt; q = q->next) {
329 if (q->error_fname != NULL
330 && strcmp(q->error_fname, virt->error_fname) == 0) {
336 if (open_error_log(virt, p) != OK) {
341 virt->error_log = q->error_log;
345 virt->error_log = s_main->error_log;
351 AP_DECLARE(void) ap_error_log2stderr(server_rec *s) {
352 apr_file_t *errfile = NULL;
354 apr_file_open_stderr(&errfile, s->process->pool);
355 if (s->error_log != NULL) {
356 apr_file_dup2(s->error_log, errfile, s->process->pool);
360 static void log_error_core(const char *file, int line, int level,
361 apr_status_t status, const server_rec *s,
363 const request_rec *r, apr_pool_t *pool,
364 const char *fmt, va_list args)
366 char errstr[MAX_STRING_LEN];
367 #ifndef AP_UNSAFE_ERROR_LOG_UNESCAPED
368 char scratch[MAX_STRING_LEN];
370 apr_size_t len, errstrlen;
371 apr_file_t *logf = NULL;
373 int level_and_mask = level & APLOG_LEVELMASK;
375 if (r && r->connection) {
381 * If we are doing stderr logging (startup), don't log messages that are
382 * above the default server log level unless it is a startup/shutdown
385 if ((level_and_mask != APLOG_NOTICE)
386 && (level_and_mask > ap_default_loglevel)) {
392 else if (s->error_log) {
394 * If we are doing normal logging, don't log messages that are
395 * above the server log level unless it is a startup/shutdown notice
397 if ((level_and_mask != APLOG_NOTICE)
398 && (level_and_mask > s->loglevel)) {
405 else if (tpf_child) {
407 * If we are doing normal logging, don't log messages that are
408 * above the server log level unless it is a startup/shutdown notice
410 if ((level_and_mask != APLOG_NOTICE)
411 && (level_and_mask > s->loglevel)) {
420 * If we are doing syslog logging, don't log messages that are
421 * above the server log level (including a startup/shutdown notice)
423 if (level_and_mask > s->loglevel) {
428 if (logf && ((level & APLOG_STARTUP) != APLOG_STARTUP)) {
430 ap_recent_ctime(errstr + 1, apr_time_now());
431 errstr[1 + APR_CTIME_LEN - 1] = ']';
432 errstr[1 + APR_CTIME_LEN ] = ' ';
433 len = 1 + APR_CTIME_LEN + 1;
438 if ((level & APLOG_STARTUP) != APLOG_STARTUP) {
439 len += apr_snprintf(errstr + len, MAX_STRING_LEN - len,
440 "[%s] ", priorities[level_and_mask].t_name);
444 if (file && level_and_mask == APLOG_DEBUG) {
445 #if defined(_OSD_POSIX) || defined(WIN32)
447 char *e = strrchr(file, '/');
450 e = strrchr(file, '\\');
454 /* In OSD/POSIX, the compiler returns for __FILE__
455 * a string like: __FILE__="*POSIX(/usr/include/stdio.h)"
456 * (it even returns an absolute path for sources in
457 * the current directory). Here we try to strip this
458 * down to the basename.
460 if (e != NULL && e[1] != '\0') {
461 apr_snprintf(tmp, sizeof(tmp), "%s", &e[1]);
462 e = &tmp[strlen(tmp)-1];
468 #else /* _OSD_POSIX || WIN32 */
470 /* On Unix, __FILE__ may be an absolute path in a
472 if (file[0] == '/' && (p = ap_strrchr_c(file, '/')) != NULL) {
475 #endif /*_OSD_POSIX || WIN32 */
476 len += apr_snprintf(errstr + len, MAX_STRING_LEN - len,
477 "%s(%d): ", file, line);
482 /* XXX: TODO: add a method of selecting whether logged client
483 * addresses are in dotted quad or resolved form... dotted
484 * quad is the most secure, which is why I'm implementing it
487 len += apr_snprintf(errstr + len, MAX_STRING_LEN - len,
488 "[client %s] ", c->remote_ip);
491 if (status < APR_OS_START_EAIERR) {
492 len += apr_snprintf(errstr + len, MAX_STRING_LEN - len,
495 else if (status < APR_OS_START_SYSERR) {
496 len += apr_snprintf(errstr + len, MAX_STRING_LEN - len,
497 "(EAI %d)", status - APR_OS_START_EAIERR);
499 else if (status < 100000 + APR_OS_START_SYSERR) {
500 len += apr_snprintf(errstr + len, MAX_STRING_LEN - len,
501 "(OS %d)", status - APR_OS_START_SYSERR);
504 len += apr_snprintf(errstr + len, MAX_STRING_LEN - len,
505 "(os 0x%08x)", status - APR_OS_START_SYSERR);
507 apr_strerror(status, errstr + len, MAX_STRING_LEN - len);
508 len += strlen(errstr + len);
509 if (MAX_STRING_LEN - len > 2) {
517 #ifndef AP_UNSAFE_ERROR_LOG_UNESCAPED
518 if (apr_vsnprintf(scratch, MAX_STRING_LEN - len, fmt, args)) {
519 len += ap_escape_errorlog_item(errstr + len, scratch,
520 MAX_STRING_LEN - len);
523 len += apr_vsnprintf(errstr + len, MAX_STRING_LEN - len, fmt, args);
526 if ( r && (referer = apr_table_get(r->headers_in, "Referer"))
527 #ifndef AP_UNSAFE_ERROR_LOG_UNESCAPED
528 && ap_escape_errorlog_item(scratch, referer, MAX_STRING_LEN - len)
531 len += apr_snprintf(errstr + len, MAX_STRING_LEN - len,
533 #ifndef AP_UNSAFE_ERROR_LOG_UNESCAPED
541 /* NULL if we are logging to syslog */
543 /* Truncate for the terminator (as apr_snprintf does) */
544 if (len > MAX_STRING_LEN - sizeof(APR_EOL_STR)) {
545 len = MAX_STRING_LEN - sizeof(APR_EOL_STR);
547 strcpy(errstr + len, APR_EOL_STR);
548 apr_file_puts(errstr, logf);
549 apr_file_flush(logf);
553 syslog(level_and_mask, "%s", errstr);
557 ap_run_error_log(file, line, level, status, s, r, pool, errstr + errstrlen);
560 AP_DECLARE(void) ap_log_error(const char *file, int line, int level,
561 apr_status_t status, const server_rec *s,
562 const char *fmt, ...)
567 log_error_core(file, line, level, status, s, NULL, NULL, NULL, fmt, args);
571 AP_DECLARE(void) ap_log_perror(const char *file, int line, int level,
572 apr_status_t status, apr_pool_t *p,
573 const char *fmt, ...)
578 log_error_core(file, line, level, status, NULL, NULL, NULL, p, fmt, args);
582 AP_DECLARE(void) ap_log_rerror(const char *file, int line, int level,
583 apr_status_t status, const request_rec *r,
584 const char *fmt, ...)
589 log_error_core(file, line, level, status, r->server, NULL, r, NULL, fmt,
593 * IF APLOG_TOCLIENT is set,
594 * AND the error level is 'warning' or more severe,
595 * AND there isn't already error text associated with this request,
596 * THEN make the message text available to ErrorDocument and
597 * other error processors.
601 if ((level & APLOG_TOCLIENT)
602 && ((level & APLOG_LEVELMASK) <= APLOG_WARNING)
603 && (apr_table_get(r->notes, "error-notes") == NULL)) {
604 apr_table_setn(r->notes, "error-notes",
605 ap_escape_html(r->pool, apr_pvsprintf(r->pool, fmt,
611 AP_DECLARE(void) ap_log_cerror(const char *file, int line, int level,
612 apr_status_t status, const conn_rec *c,
613 const char *fmt, ...)
618 log_error_core(file, line, level, status, c->base_server, c, NULL, NULL,
623 AP_DECLARE(void) ap_log_pid(apr_pool_t *p, const char *filename)
625 apr_file_t *pid_file = NULL;
627 static pid_t saved_pid = -1;
636 fname = ap_server_root_relative(p, filename);
638 ap_log_error(APLOG_MARK, APLOG_STARTUP|APLOG_CRIT, APR_EBADPATH,
639 NULL, "Invalid PID file path %s, ignoring.", filename);
644 if (mypid != saved_pid
645 && apr_stat(&finfo, fname, APR_FINFO_MTIME, p) == APR_SUCCESS) {
646 /* AP_SIG_GRACEFUL and HUP call this on each restart.
647 * Only warn on first time through for this pid.
649 * XXX: Could just write first time through too, although
650 * that may screw up scripts written to do something
651 * based on the last modification time of the pid file.
653 ap_log_perror(APLOG_MARK, APLOG_WARNING, 0, p,
654 "pid file %s overwritten -- Unclean "
655 "shutdown of previous Apache run?",
659 if ((rv = apr_file_open(&pid_file, fname,
660 APR_WRITE | APR_CREATE | APR_TRUNCATE,
661 APR_UREAD | APR_UWRITE | APR_GREAD | APR_WREAD, p))
663 ap_log_error(APLOG_MARK, APLOG_ERR, rv, NULL,
664 "could not create %s", fname);
665 ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,
666 "%s: could not log pid to file %s",
667 ap_server_argv0, fname);
670 apr_file_printf(pid_file, "%ld" APR_EOL_STR, (long)mypid);
671 apr_file_close(pid_file);
675 AP_DECLARE(apr_status_t) ap_read_pid(apr_pool_t *p, const char *filename,
678 const apr_size_t BUFFER_SIZE = sizeof(long) * 3 + 2; /* see apr_ltoa */
679 apr_file_t *pid_file = NULL;
683 apr_size_t bytes_read;
689 fname = ap_server_root_relative(p, filename);
691 ap_log_error(APLOG_MARK, APLOG_STARTUP|APLOG_CRIT, APR_EBADPATH,
692 NULL, "Invalid PID file path %s, ignoring.", filename);
696 rv = apr_file_open(&pid_file, fname, APR_READ, APR_OS_DEFAULT, p);
697 if (rv != APR_SUCCESS) {
701 buf = apr_palloc(p, BUFFER_SIZE);
703 rv = apr_file_read_full(pid_file, buf, BUFFER_SIZE - 1, &bytes_read);
704 if (rv != APR_SUCCESS && rv != APR_EOF) {
708 /* If we fill the buffer, we're probably reading a corrupt pid file.
709 * To be nice, let's also ensure the first char is a digit. */
710 if (bytes_read == 0 || bytes_read == BUFFER_SIZE - 1 || !apr_isdigit(*buf)) {
714 buf[bytes_read] = '\0';
715 *mypid = strtol(buf, &endptr, 10);
717 apr_file_close(pid_file);
721 AP_DECLARE(void) ap_log_assert(const char *szExp, const char *szFile,
724 char time_str[APR_CTIME_LEN];
726 apr_ctime(time_str, apr_time_now());
727 ap_log_error(APLOG_MARK, APLOG_CRIT, 0, NULL,
728 "[%s] file %s, line %d, assertion \"%s\" failed",
729 time_str, szFile, nLine, szExp);
733 /* unix assert does an abort leading to a core dump */
738 /* piped log support */
740 #ifdef AP_HAVE_RELIABLE_PIPED_LOGS
741 /* forward declaration */
742 static void piped_log_maintenance(int reason, void *data, apr_wait_t status);
744 static int piped_log_spawn(piped_log *pl)
747 apr_procattr_t *procattr;
748 apr_proc_t *procnew = NULL;
751 if (((status = apr_procattr_create(&procattr, pl->p)) != APR_SUCCESS) ||
752 ((status = apr_procattr_cmdtype_set(procattr,
753 APR_SHELLCMD_ENV)) != APR_SUCCESS) ||
754 ((status = apr_procattr_child_in_set(procattr,
755 ap_piped_log_read_fd(pl),
756 ap_piped_log_write_fd(pl)))
758 ((status = apr_procattr_child_errfn_set(procattr, log_child_errfn))
760 ((status = apr_procattr_error_check_set(procattr, 1)) != APR_SUCCESS)) {
762 /* Something bad happened, give up and go away. */
763 ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
764 "piped_log_spawn: unable to setup child process '%s': %s",
765 pl->program, apr_strerror(status, buf, sizeof(buf)));
772 apr_tokenize_to_argv(pl->program, &args, pl->p);
773 pname = apr_pstrdup(pl->p, args[0]);
774 procnew = apr_pcalloc(pl->p, sizeof(apr_proc_t));
775 status = apr_proc_create(procnew, pname, (const char * const *) args,
776 NULL, procattr, pl->p);
778 if (status == APR_SUCCESS) {
780 ap_piped_log_write_fd(pl) = procnew->in;
781 apr_proc_other_child_register(procnew, piped_log_maintenance, pl,
782 ap_piped_log_write_fd(pl), pl->p);
786 /* Something bad happened, give up and go away. */
787 ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
788 "unable to start piped log program '%s': %s",
789 pl->program, apr_strerror(status, buf, sizeof(buf)));
798 static void piped_log_maintenance(int reason, void *data, apr_wait_t status)
800 piped_log *pl = data;
805 case APR_OC_REASON_DEATH:
806 case APR_OC_REASON_LOST:
807 pl->pid = NULL; /* in case we don't get it going again, this
808 * tells other logic not to try to kill it
810 apr_proc_other_child_unregister(pl);
811 stats = ap_mpm_query(AP_MPMQ_MPM_STATE, &mpm_state);
812 if (stats != APR_SUCCESS) {
813 ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
814 "can't query MPM state; not restarting "
815 "piped log program '%s'",
818 else if (mpm_state != AP_MPMQ_STOPPING) {
819 ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
820 "piped log program '%s' failed unexpectedly",
822 if ((stats = piped_log_spawn(pl)) != APR_SUCCESS) {
823 /* what can we do? This could be the error log we're having
824 * problems opening up... */
826 ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
827 "piped_log_maintenance: unable to respawn '%s': %s",
828 pl->program, apr_strerror(stats, buf, sizeof(buf)));
833 case APR_OC_REASON_UNWRITABLE:
834 /* We should not kill off the pipe here, since it may only be full.
835 * If it really is locked, we should kill it off manually. */
838 case APR_OC_REASON_RESTART:
839 if (pl->pid != NULL) {
840 apr_proc_kill(pl->pid, SIGTERM);
845 case APR_OC_REASON_UNREGISTER:
851 static apr_status_t piped_log_cleanup_for_exec(void *data)
853 piped_log *pl = data;
855 apr_file_close(ap_piped_log_read_fd(pl));
856 apr_file_close(ap_piped_log_write_fd(pl));
861 static apr_status_t piped_log_cleanup(void *data)
863 piped_log *pl = data;
865 if (pl->pid != NULL) {
866 apr_proc_kill(pl->pid, SIGTERM);
868 return piped_log_cleanup_for_exec(data);
872 AP_DECLARE(piped_log *) ap_open_piped_log(apr_pool_t *p, const char *program)
876 pl = apr_palloc(p, sizeof (*pl));
878 pl->program = apr_pstrdup(p, program);
880 if (apr_file_pipe_create(&ap_piped_log_read_fd(pl),
881 &ap_piped_log_write_fd(pl), p) != APR_SUCCESS) {
884 apr_pool_cleanup_register(p, pl, piped_log_cleanup,
885 piped_log_cleanup_for_exec);
886 if (piped_log_spawn(pl) == -1) {
887 int save_errno = errno;
888 apr_pool_cleanup_kill(p, pl, piped_log_cleanup);
889 apr_file_close(ap_piped_log_read_fd(pl));
890 apr_file_close(ap_piped_log_write_fd(pl));
897 #else /* !AP_HAVE_RELIABLE_PIPED_LOGS */
899 static apr_status_t piped_log_cleanup(void *data)
901 piped_log *pl = data;
903 apr_file_close(ap_piped_log_write_fd(pl));
907 AP_DECLARE(piped_log *) ap_open_piped_log(apr_pool_t *p, const char *program)
910 apr_file_t *dummy = NULL;
913 rc = log_child(p, program, &dummy);
914 if (rc != APR_SUCCESS) {
915 ap_log_error(APLOG_MARK, APLOG_STARTUP, rc, NULL,
916 "Couldn't start piped log process");
920 pl = apr_palloc(p, sizeof (*pl));
922 ap_piped_log_read_fd(pl) = NULL;
923 ap_piped_log_write_fd(pl) = dummy;
924 apr_pool_cleanup_register(p, pl, piped_log_cleanup, piped_log_cleanup);
931 AP_DECLARE(void) ap_close_piped_log(piped_log *pl)
933 apr_pool_cleanup_run(pl->p, pl, piped_log_cleanup);
936 AP_IMPLEMENT_HOOK_VOID(error_log,
937 (const char *file, int line, int level,
938 apr_status_t status, const server_rec *s,
939 const request_rec *r, apr_pool_t *pool,
940 const char *errstr), (file, line, level,
941 status, s, r, pool, errstr))