On 01/16/2009 12:21 AM, Rainer Jung wrote:

> 
> This difference goes back to pre 1.3 httpd.
> 
> The patch at
> 
> http://people.apache.org/~rjung/patches/reliable_error_log.patch

Just some quick comments below

Index: server/log.c
===================================================================
--- server/log.c        (revision 734457)
+++ server/log.c        (working copy)

@@ -319,20 +333,28 @@
     int rc;

     if (*s->error_fname == '|') {
-        apr_file_t *dummy = NULL;
+        piped_log *pl;
+        fname = ap_server_root_relative(p, s->error_fname + 1);

+        if (!fname) {
+            ap_log_error(APLOG_MARK, APLOG_STARTUP, APR_EBADPATH, NULL,
+                         "%s: Invalid error log path '%s'.",
+                         ap_server_argv0, s->error_fname);
+            return NULL;
+        }
+
         /* Spawn a new child logger.  If this is the main server_rec,
          * the new child must use a dummy stderr since the current
          * stderr might be a pipe to the old logger.  Otherwise, the
          * child inherits the parents stderr. */
-        rc = log_child(p, s->error_fname + 1, &dummy, is_main);
-        if (rc != APR_SUCCESS) {
-            ap_log_error(APLOG_MARK, APLOG_STARTUP, rc, NULL,
-                         "Couldn't start ErrorLog process");
+        pl = piped_log_open(p, fname, is_main);
+        if (pl == NULL) {
+            ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
+                         "%s: Couldn't start ErrorLog process '%s'.",
+                         ap_server_argv0, fname);
             return DONE;

Why not keeping the old way if

#ifndef AP_HAVE_RELIABLE_PIPED_LOGS?

         }
-
-        s->error_log = dummy;
+        s->error_log = ap_piped_log_write_fd(pl);
     }

 #ifdef HAVE_SYSLOG

@@ -953,13 +992,26 @@
             ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
                          "piped log program '%s' failed unexpectedly",
                          pl->program);
-            if ((stats = piped_log_spawn(pl)) != APR_SUCCESS) {
+
+            /* If special_stderr is non-zero, we need to get the write
+             * end of the pipe back from stderr before spawning. */
+            if ((plw->special_stderr && (stats = 
apr_file_dup(&ap_piped_log_write_fd(pl),
+                                                              stderr_log, 
pl->p))
+                != APR_SUCCESS) ||
+               ((stats = piped_log_spawn(plw)) != APR_SUCCESS) ||
+            /* If special_stderr is non-zero, we need to close the write
+             * end of the pipe after spawning, because we write to it via
+             * stderr. */
+               (plw->special_stderr && (stats = 
apr_file_close(ap_piped_log_write_fd(pl)))
+                != APR_SUCCESS)) {

I know that this is always a difficult and confusing part, so maybe it just 
confused me again,
but why do we need to do the above?
ap_piped_log_write_fd(pl) should have the correct fd already because in 
ap_open_logs we just
duplicate the write side of the pipe to stderr and in all other cases (not main 
server error log)
ap_piped_log_write_fd is just fine anyways.


+
+                char buf[120];
+
                 /* what can we do?  This could be the error log we're having
                  * problems opening up... */
-                char buf[120];
                 ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
                              "piped_log_maintenance: unable to respawn '%s': 
%s",
-                             pl->program, apr_strerror(stats, buf, 
sizeof(buf)));
+                         pl->program, apr_strerror(stats, buf, sizeof(buf)));
             }
         }
         break;

@@ -1037,21 +1094,25 @@
     return APR_SUCCESS;
 }

-AP_DECLARE(piped_log *) ap_open_piped_log(apr_pool_t *p, const char *program)
+static piped_log* piped_log_open(apr_pool_t *p, const char *program,
+                                 int special_stderr)
 {
     piped_log *pl;
     apr_file_t *dummy = NULL;
     int rc;

-    rc = log_child(p, program, &dummy, 0);
+    rc = log_child(p, program, &dummy, special_stderr);
     if (rc != APR_SUCCESS) {
         ap_log_error(APLOG_MARK, APLOG_STARTUP, rc, NULL,
-                     "Couldn't start piped log process");
+                     "Couldn't start piped log process for %s",
+                     program == NULL ? "'NULL'" : "'" program "'");
         return NULL;
     }

     pl = apr_palloc(p, sizeof (*pl));
     pl->p = p;
+    pl->program = (program == NULL) ? NULL : apr_pstrdup(p, program);
+    pl->pid = NULL;

Why is this needed now? Or was this just missed previously and is not really
related to the reliable pipe usage of the error log?

     ap_piped_log_read_fd(pl) = NULL;
     ap_piped_log_write_fd(pl) = dummy;
     apr_pool_cleanup_register(p, pl, piped_log_cleanup, piped_log_cleanup);

> 
> should fix this. I tested it with access and error logs, with the main
> server and virtual hosts and with restarts and logger killing.
> 
> The problem is the delicate handling of file descriptors in the main
> error log case.
> 
> Should I apply this to trunk?

I guess soon because this make discussion easier.

> 
> My tests are only on Solaris. I will also test on Linux, but it would be
> nice if someone could test on Windows too.
> 
> Some comments on the patch:
> 
> 1) The piped_log_maintenance() function used as a callback when the
> logger dies needs one additional data, namely whether the died logger
> was the main error log. We could add this to the piped_log structure,

This is the part I don't get :-). Why do we need to know this?

Regards

RĂ¼diger

Reply via email to