diff --git a/doc/src/sgml/maintenance.sgml b/doc/src/sgml/maintenance.sgml
index 91ead3dc1681064b49dd4a148efe8c314e74bfed..7d1dafad3182b74dc9f307746d5ead34258b050c 100644
--- a/doc/src/sgml/maintenance.sgml
+++ b/doc/src/sgml/maintenance.sgml
@@ -1,5 +1,5 @@
 <!--
-$PostgreSQL: pgsql/doc/src/sgml/maintenance.sgml,v 1.36 2004/07/24 19:51:22 tgl Exp $
+$PostgreSQL: pgsql/doc/src/sgml/maintenance.sgml,v 1.37 2004/08/05 23:32:10 tgl Exp $
 -->
 
 <chapter id="maintenance">
@@ -445,22 +445,52 @@ VACUUM
   </para>
 
   <para>
-   If you simply direct the <systemitem>stderr</> of the <command>postmaster</command> into a
-   file, the only way to truncate the log file is to stop and restart
+   If you simply direct the <systemitem>stderr</> of the
+   <command>postmaster</command> into a
+   file, you will have log output, but
+   the only way to truncate the log file is to stop and restart
    the <command>postmaster</command>. This may be OK if you are using
    <productname>PostgreSQL</productname> in a development environment,
    but few production servers would find this behavior acceptable.
   </para>
 
   <para>
-   The simplest production-grade approach to managing log output is to
+   A better approach is to send the <command>postmaster</>'s
+   <systemitem>stderr</> output to some type of log rotation program.
+   There is a built-in log rotation program, which you can use by
+   setting the configuration parameter <literal>redirect_stderr</> to
+   <literal>true</> in <filename>postgresql.conf</>.  The control
+   parameters for this program are described in <xref
+   linkend="runtime-config-logging-where">.
+  </para>
+
+  <para>
+   Alternatively, you might prefer to use an external log rotation
+   program, if you have one that you are already using with other
+   server software. For example, the <application>rotatelogs</application>
+   tool included in the <productname>Apache</productname> distribution
+   can be used with <productname>PostgreSQL</productname>.  To do this,
+   just pipe the <command>postmaster</>'s
+   <systemitem>stderr</> output to the desired program.
+   If you start the server with
+   <command>pg_ctl</>, then <systemitem>stderr</>
+   is already redirected to <systemitem>stdout</>, so you just need a
+   pipe command:
+
+<programlisting>
+pg_ctl start | rotatelogs /var/log/pgsql_log 86400
+</programlisting>
+  </para>
+
+  <para>
+   Another production-grade approach to managing log output is to
    send it all to <application>syslog</> and let
    <application>syslog</> deal with file rotation. To do this, set the
-   configuration parameter <literal>log_destination</> to 'syslog' (to log to
-   <application>syslog</> only) in <filename>postgresql.conf</>. Then
-   you can send a <literal>SIGHUP</literal> signal to the
-   <application>syslog</> daemon whenever you want to force it to
-   start writing a new log file.  If you want to automate log
+   configuration parameter <literal>log_destination</> to <literal>syslog</>
+   (to log to <application>syslog</> only) in
+   <filename>postgresql.conf</>. Then you can send a <literal>SIGHUP</literal>
+   signal to the <application>syslog</> daemon whenever you want to force it
+   to start writing a new log file.  If you want to automate log
    rotation, the <application>logrotate</application> program can be
    configured to work with log files from
    <application>syslog</application>.
@@ -471,27 +501,15 @@ VACUUM
    particularly with large log messages; it may truncate or drop messages
    just when you need them the most.  Also, on <productname>linux</>,
    <application>syslog</> will sync each message to disk, yielding poor
-   performance.  Use a <literal>-</> at the start of the file name
-   in the <application>syslog</> config file to disable this behavior.
+   performance.  (You can use a <literal>-</> at the start of the file name
+   in the <application>syslog</> config file to disable this behavior.)
   </para>
 
   <para>
-   You may find it more useful to pipe the
-   <systemitem>stderr</> of the <command>postmaster</> to some type of
-   log rotation program. If you start the server with
-   <command>pg_ctl</>, then the <systemitem>stderr</> of the <command>postmaster</command>
-   is already redirected to <systemitem>stdout</>, so you just need a
-   pipe command:
-
-<programlisting>
-pg_ctl start | rotatelogs /var/log/pgsql_log 86400
-</programlisting>
-
-   The <productname>PostgreSQL</> distribution doesn't include a
-   suitable log rotation program, but there are many available on the
-   Internet. For example, the <application>rotatelogs</application>
-   tool included in the <productname>Apache</productname> distribution
-   can be used with <productname>PostgreSQL</productname>.
+   Note that all the solutions described above take care of starting new
+   log files at configurable intervals, but they do not handle deletion
+   of old, no-longer-interesting log files.  You will also want to set
+   up a batch job to periodically delete old log files.
   </para>
  </sect1>
 </chapter>
diff --git a/doc/src/sgml/runtime.sgml b/doc/src/sgml/runtime.sgml
index 95a8c23c8220c57e76290862a5fa334eac092630..9f569712b08b4bef0330523c90321744dc7ef67e 100644
--- a/doc/src/sgml/runtime.sgml
+++ b/doc/src/sgml/runtime.sgml
@@ -1,5 +1,5 @@
 <!--
-$PostgreSQL: pgsql/doc/src/sgml/runtime.sgml,v 1.271 2004/08/03 23:42:59 tgl Exp $
+$PostgreSQL: pgsql/doc/src/sgml/runtime.sgml,v 1.272 2004/08/05 23:32:10 tgl Exp $
 -->
 
 <Chapter Id="runtime">
@@ -1800,15 +1800,91 @@ SET ENABLE_SEQSCAN TO OFF;
 	 option to a list of desired log destinations separated by
 	 commas. The default is to log to <systemitem>stderr</systemitem> 
 	 only.
+         This option can only be set at server start or in the
+         <filename>postgresql.conf</filename> configuration file.
        </para>
       </listitem>
      </varlistentry>
 
+     <varlistentry id="guc-redirect-stderr" xreflabel="redirect_stderr">
+      <term><varname>redirect_stderr</varname> (<type>boolean</type>)</term>
+       <listitem>
+        <para>
+	  This option allows messages sent to <application>stderr</> to be
+	  captured and redirected into log files.
+	  This option, in combination with logging to <application>stderr</>,
+	  is often more useful than
+	  logging to <application>syslog</>, since some types of messages
+	  may not appear in <application>syslog</> output (a common example
+	  is dynamic-linker failure messages).
+	  This option can only be set at server start.
+        </para>
+       </listitem>
+     </varlistentry>
+
+     <varlistentry id="guc-log-directory" xreflabel="log_directory">
+      <term><varname>log_directory</varname> (<type>string</type>)</term>
+       <listitem>
+        <para>
+	  When <varname>redirect_stderr</> is enabled, this option
+          determines the directory in which log files will be created.
+	  It may be specified as an absolute path, or relative to the
+	  cluster data directory.
+         This option can only be set at server start or in the
+         <filename>postgresql.conf</filename> configuration file.
+        </para>
+       </listitem>
+     </varlistentry>
+
+     <varlistentry id="guc-log-filename-prefix" xreflabel="log_filename_prefix">
+      <term><varname>log_filename_prefix</varname> (<type>string</type>)</term>
+       <listitem>
+        <para>
+	  When <varname>redirect_stderr</> is enabled, this option
+          sets the prefix of the file names of the created log files.
+	  The postmaster PID and the current time are appended to this
+	  prefix to form an exact log file name.
+         This option can only be set at server start or in the
+         <filename>postgresql.conf</filename> configuration file.
+        </para>
+       </listitem>
+     </varlistentry>
+
+     <varlistentry id="guc-log-rotation-age" xreflabel="log_rotation_age">
+      <term><varname>log_rotation_age</varname> (<type>integer</type>)</term>
+       <listitem>
+        <para>
+	  When <varname>redirect_stderr</> is enabled, this option
+	  determines the maximum lifetime of an individual log file.
+	  After this many minutes have elapsed, a new log file will
+	  be created.  Set to zero to disable time-based creation of
+	  new log files.
+         This option can only be set at server start or in the
+         <filename>postgresql.conf</filename> configuration file.
+        </para>
+       </listitem>
+     </varlistentry>
+
+     <varlistentry id="guc-log-rotation-size" xreflabel="log_rotation_size">
+      <term><varname>log_rotation_size</varname> (<type>integer</type>)</term>
+       <listitem>
+        <para>
+	  When <varname>redirect_stderr</> is enabled, this option
+	  determines the maximum size of an individual log file.
+	  After this many kilobytes have been emitted into a log file,
+	  a new log file will be created.  Set to zero to disable size-based
+	  creation of new log files.
+         This option can only be set at server start or in the
+         <filename>postgresql.conf</filename> configuration file.
+        </para>
+       </listitem>
+     </varlistentry>
+
      <varlistentry id="guc-syslog-facility" xreflabel="syslog_facility">
       <term><varname>syslog_facility</varname> (<type>string</type>)</term>
        <listitem>
         <para>
-          If logging to <application>syslog</> is enabled, this option
+          When logging to <application>syslog</> is enabled, this option
           determines the <application>syslog</application>
           <quote>facility</quote> to be used.  You may choose
           from <literal>LOCAL0</>, <literal>LOCAL1</>,
@@ -1826,7 +1902,7 @@ SET ENABLE_SEQSCAN TO OFF;
       <term><varname>syslog_ident</varname> (<type>string</type>)</term>
        <listitem>
         <para>
-         If logging to <application>syslog</> is enabled, this option
+         When logging to <application>syslog</> is enabled, this option
          determines the program name used to identify
          <productname>PostgreSQL</productname> messages in
          <application>syslog</application> logs. The default is
diff --git a/src/backend/postmaster/Makefile b/src/backend/postmaster/Makefile
index abbac1674f1ec8a6a1f1200d1faf3637b182c319..fdb12febb4a4579a14246674361fcacfc467e569 100644
--- a/src/backend/postmaster/Makefile
+++ b/src/backend/postmaster/Makefile
@@ -4,7 +4,7 @@
 #    Makefile for src/backend/postmaster
 #
 # IDENTIFICATION
-#    $PostgreSQL: pgsql/src/backend/postmaster/Makefile,v 1.18 2004/07/21 20:34:46 momjian Exp $
+#    $PostgreSQL: pgsql/src/backend/postmaster/Makefile,v 1.19 2004/08/05 23:32:10 tgl Exp $
 #
 #-------------------------------------------------------------------------
 
@@ -12,7 +12,7 @@ subdir = src/backend/postmaster
 top_builddir = ../../..
 include $(top_builddir)/src/Makefile.global
 
-OBJS = postmaster.o bgwriter.o pgstat.o pgarch.o
+OBJS = postmaster.o bgwriter.o pgstat.o pgarch.o syslogger.o
 
 all: SUBSYS.o
 
diff --git a/src/backend/postmaster/pgarch.c b/src/backend/postmaster/pgarch.c
index 960ece7583199f56e915a4f065d67f6f303cf2a0..1d398ba596212f688deb621de0a0f314f1b65924 100644
--- a/src/backend/postmaster/pgarch.c
+++ b/src/backend/postmaster/pgarch.c
@@ -19,7 +19,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/postmaster/pgarch.c,v 1.4 2004/08/03 20:32:33 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/postmaster/pgarch.c,v 1.5 2004/08/05 23:32:10 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -172,7 +172,7 @@ pgarch_start(void)
 			beos_backend_startup();
 #endif
 			/* Close the postmaster's sockets */
-			ClosePostmasterPorts();
+			ClosePostmasterPorts(false);
 
 			/* Drop our connection to postmaster's shared memory, as well */
 			PGSharedMemoryDetach();
diff --git a/src/backend/postmaster/pgstat.c b/src/backend/postmaster/pgstat.c
index dbd4f15cefdfd5cbcfeef6b1691a11b39475e393..7638dd28a1130e6516bc6a4870d7fef27cd2d088 100644
--- a/src/backend/postmaster/pgstat.c
+++ b/src/backend/postmaster/pgstat.c
@@ -13,7 +13,7 @@
  *
  *	Copyright (c) 2001-2003, PostgreSQL Global Development Group
  *
- *	$PostgreSQL: pgsql/src/backend/postmaster/pgstat.c,v 1.77 2004/07/01 00:50:36 tgl Exp $
+ *	$PostgreSQL: pgsql/src/backend/postmaster/pgstat.c,v 1.78 2004/08/05 23:32:10 tgl Exp $
  * ----------
  */
 #include "postgres.h"
@@ -611,7 +611,7 @@ pgstat_start(void)
 			beos_backend_startup();
 #endif
 			/* Close the postmaster's sockets */
-			ClosePostmasterPorts();
+			ClosePostmasterPorts(false);
 
 			/* Drop our connection to postmaster's shared memory, as well */
 			PGSharedMemoryDetach();
diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c
index 6c9e87f5f3a56baedb7c63ffea3f3b6355581f78..870ad318a830bb26349f6c7cb9bff8369d0cc87f 100644
--- a/src/backend/postmaster/postmaster.c
+++ b/src/backend/postmaster/postmaster.c
@@ -37,7 +37,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/postmaster/postmaster.c,v 1.419 2004/08/04 20:09:47 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/postmaster/postmaster.c,v 1.420 2004/08/05 23:32:10 tgl Exp $
  *
  * NOTES
  *
@@ -104,6 +104,7 @@
 #include "nodes/nodes.h"
 #include "postmaster/postmaster.h"
 #include "postmaster/pgarch.h"
+#include "postmaster/syslogger.h"
 #include "storage/fd.h"
 #include "storage/ipc.h"
 #include "storage/pg_shmem.h"
@@ -199,7 +200,8 @@ char	   *preload_libraries_string = NULL;
 static pid_t StartupPID = 0,
 			BgWriterPID = 0,
 			PgArchPID = 0,
-			PgStatPID = 0;
+			PgStatPID = 0,
+			SysLoggerPID = 0;
 
 /* Startup/shutdown state */
 #define			NoShutdown		0
@@ -828,7 +830,7 @@ PostmasterMain(int argc, char *argv[])
 	 * CAUTION: when changing this list, check for side-effects on the signal
 	 * handling setup of child processes.  See tcop/postgres.c,
 	 * bootstrap/bootstrap.c, postmaster/bgwriter.c, postmaster/pgarch.c,
-	 * and postmaster/pgstat.c.
+	 * postmaster/pgstat.c, and postmaster/syslogger.c.
 	 */
 	pqinitmask();
 	PG_SETMASK(&BlockSig);
@@ -850,6 +852,11 @@ PostmasterMain(int argc, char *argv[])
 	pqsignal(SIGXFSZ, SIG_IGN); /* ignored */
 #endif
 
+	/*
+	 * If enabled, start up syslogger collection subprocess
+	 */
+	SysLoggerPID = SysLogger_Start();
+
 	/*
 	 * Reset whereToSendOutput from Debug (its starting state) to None.
 	 * This stops ereport from sending log messages to stderr unless
@@ -933,8 +940,8 @@ checkDataDir(const char *checkdir)
 	{
 		write_stderr("%s does not know where to find the database system data.\n"
 					 "You must specify the directory that contains the database system\n"
-					 "or configuration files by either specifying the -D invocation option\n"
-					 "or by setting the PGDATA environment variable.\n",
+					 "either by specifying the -D invocation option or by setting the\n"
+					 "PGDATA environment variable.\n",
 					 progname);
 		ExitPostmaster(2);
 	}
@@ -944,12 +951,12 @@ checkDataDir(const char *checkdir)
 		if (errno == ENOENT)
 			ereport(FATAL,
 					(errcode_for_file_access(),
-					 errmsg("data or configuration location \"%s\" does not exist",
+					 errmsg("data directory \"%s\" does not exist",
 							checkdir)));
 		else
 			ereport(FATAL,
 					(errcode_for_file_access(),
-			 errmsg("could not read permissions of \"%s\": %m",
+			 errmsg("could not read permissions of directory \"%s\": %m",
 					checkdir)));
 	}
 
@@ -1050,7 +1057,7 @@ pmdaemonize(void)
 		ExitPostmaster(1);
 	}
 #endif
-	i = open(NULL_DEV, O_RDWR | PG_BINARY);
+	i = open(NULL_DEV, O_RDWR);
 	dup2(i, 0);
 	dup2(i, 1);
 	dup2(i, 2);
@@ -1207,6 +1214,10 @@ ServerLoop(void)
 			}
 		}
 
+		/* If we have lost the system logger, try to start a new one */
+		if (SysLoggerPID == 0 && Redirect_stderr)
+			SysLoggerPID = SysLogger_Start();
+
 		/*
 		 * If no background writer process is running, and we are not in
 		 * a state that prevents it, start one.  It doesn't matter if this
@@ -1714,9 +1725,12 @@ ConnFree(Port *conn)
  * This is called during child process startup to release file descriptors
  * that are not needed by that child process.  The postmaster still has
  * them open, of course.
+ *
+ * Note: we pass am_syslogger as a boolean because we don't want to set
+ * the global variable yet when this is called.
  */
 void
-ClosePostmasterPorts(void)
+ClosePostmasterPorts(bool am_syslogger)
 {
 	int			i;
 
@@ -1729,6 +1743,20 @@ ClosePostmasterPorts(void)
 			ListenSocket[i] = -1;
 		}
 	}
+
+	/* If using syslogger, close the read side of the pipe */
+	if (!am_syslogger)
+	{
+#ifndef WIN32
+		if (syslogPipe[0] >= 0)
+			close(syslogPipe[0]);
+		syslogPipe[0] = -1;
+#else
+		if (syslogPipe[0])
+			CloseHandle(syslogPipe[0]);
+		syslogPipe[0] = 0;
+#endif
+	}
 }
 
 
@@ -1770,6 +1798,8 @@ SIGHUP_handler(SIGNAL_ARGS)
 			kill(BgWriterPID, SIGHUP);
 		if (PgArchPID != 0)
 			kill(PgArchPID, SIGHUP);
+		if (SysLoggerPID != 0)
+			kill(SysLoggerPID, SIGHUP);
 		/* PgStatPID does not currently need SIGHUP */
 		load_hba();
 		load_ident();
@@ -2063,6 +2093,18 @@ reaper(SIGNAL_ARGS)
 			continue;
 		}
 
+		/* Was it the system logger? try to start a new one */
+		if (SysLoggerPID != 0 && pid == SysLoggerPID)
+		{
+			SysLoggerPID = 0;
+			/* for safety's sake, launch new logger *first* */
+			SysLoggerPID = SysLogger_Start();
+			if (exitstatus != 0)
+				LogChildExit(LOG, gettext("system logger process"),
+							 pid, exitstatus);
+			continue;
+		}
+
 		/*
 		 * Else do standard backend child cleanup.
 		 */
@@ -2258,6 +2300,8 @@ HandleChildCrash(int pid, int exitstatus, const char *procname)
 		kill(PgStatPID, SIGQUIT);
 	}
 
+	/* We do NOT restart the syslogger */
+
 	FatalError = true;
 }
 
@@ -2528,7 +2572,7 @@ BackendRun(Port *port)
 	 * Let's clean up ourselves as the postmaster child, and close the
 	 * postmaster's listen sockets
 	 */
-	ClosePostmasterPorts();
+	ClosePostmasterPorts(false);
 
 	/* We don't want the postmaster's proc_exit() handlers */
 	on_exit_reset();
@@ -2921,7 +2965,7 @@ SubPostmasterMain(int argc, char *argv[])
 	if (strcmp(argv[1], "-forkboot") == 0)
 	{
 		/* Close the postmaster's sockets */
-		ClosePostmasterPorts();
+		ClosePostmasterPorts(false);
 
 		/* Attach process to shared segments */
 		CreateSharedMemoryAndSemaphores(false, MaxBackends, 0);
@@ -2932,7 +2976,7 @@ SubPostmasterMain(int argc, char *argv[])
 	if (strcmp(argv[1], "-forkarch") == 0)
 	{
 		/* Close the postmaster's sockets */
-		ClosePostmasterPorts();
+		ClosePostmasterPorts(false);
 
 		/* Do not want to attach to shared memory */
 
@@ -2942,7 +2986,7 @@ SubPostmasterMain(int argc, char *argv[])
 	if (strcmp(argv[1], "-forkbuf") == 0)
 	{
 		/* Close the postmaster's sockets */
-		ClosePostmasterPorts();
+		ClosePostmasterPorts(false);
 
 		/* Do not want to attach to shared memory */
 
@@ -2961,6 +3005,16 @@ SubPostmasterMain(int argc, char *argv[])
 		PgstatCollectorMain(argc, argv);
 		proc_exit(0);
 	}
+	if (strcmp(argv[1], "-forklog") == 0)
+	{
+		/* Close the postmaster's sockets */
+		ClosePostmasterPorts(true);
+
+		/* Do not want to attach to shared memory */
+
+		SysLoggerMain(argc, argv);
+		proc_exit(0);
+	}
 
 	return 1;					/* shouldn't get here */
 }
@@ -3017,7 +3071,7 @@ sigusr1_handler(SIGNAL_ARGS)
 		if (Shutdown <= SmartShutdown)
 			SignalChildren(SIGUSR1);
 	}
- 
+
 	if (PgArchPID != 0 && Shutdown == NoShutdown)
 	{
 		if (CheckPostmasterSignal(PMSIGNAL_WAKEN_ARCHIVER))
@@ -3214,7 +3268,7 @@ StartChildProcess(int xlop)
 		IsUnderPostmaster = true;	/* we are a postmaster subprocess now */
 
 		/* Close the postmaster's sockets */
-		ClosePostmasterPorts();
+		ClosePostmasterPorts(false);
 
 		/* Lose the postmaster's on-exit routines and port connections */
 		on_exit_reset();
@@ -3400,6 +3454,9 @@ write_backend_variables(char *filename, Port *port)
 	write_var(PostmasterHandle, fp);
 #endif
 
+	write_var(syslogPipe[0], fp);
+	write_var(syslogPipe[1], fp);
+
 	StrNCpy(str_buf, my_exec_path, MAXPGPATH);
 	write_array_var(str_buf, fp);
 
@@ -3471,6 +3528,9 @@ read_backend_variables(char *filename, Port *port)
 	read_var(PostmasterHandle, fp);
 #endif
 
+	read_var(syslogPipe[0], fp);
+	read_var(syslogPipe[1], fp);
+
 	read_array_var(str_buf, fp);
 	StrNCpy(my_exec_path, str_buf, MAXPGPATH);
 
diff --git a/src/backend/postmaster/syslogger.c b/src/backend/postmaster/syslogger.c
new file mode 100644
index 0000000000000000000000000000000000000000..f5bffdb8a2f26ce61e8c5c28a26fab35073fcbea
--- /dev/null
+++ b/src/backend/postmaster/syslogger.c
@@ -0,0 +1,748 @@
+/*-------------------------------------------------------------------------
+ *
+ * syslogger.c
+ *
+ * The system logger (syslogger) is new in Postgres 8.0. It catches all
+ * stderr output from the postmaster, backends, and other subprocesses
+ * by redirecting to a pipe, and writes it to a set of logfiles.
+ * It's possible to have size and age limits for the logfile configured
+ * in postgresql.conf. If these limits are reached or passed, the
+ * current logfile is closed and a new one is created (rotated).
+ * The logfiles are stored in a subdirectory (configurable in
+ * postgresql.conf), using an internal naming scheme that mangles
+ * creation time and current postmaster pid.
+ *
+ * Author: Andreas Pflug <pgadmin@pse-consulting.de>
+ *
+ * Copyright (c) 2004, PostgreSQL Global Development Group
+ *
+ *
+ * IDENTIFICATION
+ *	  $PostgreSQL: pgsql/src/backend/postmaster/syslogger.c,v 1.1 2004/08/05 23:32:10 tgl Exp $
+ *
+ *-------------------------------------------------------------------------
+ */
+#include "postgres.h"
+
+#include <fcntl.h>
+#include <signal.h>
+#include <time.h>
+#include <unistd.h>
+#include <sys/stat.h>
+
+#include "libpq/pqsignal.h"
+#include "miscadmin.h"
+#include "postmaster/postmaster.h"
+#include "postmaster/syslogger.h"
+#include "pgtime.h"
+#include "storage/ipc.h"
+#include "storage/pg_shmem.h"
+#include "utils/guc.h"
+#include "utils/ps_status.h"
+
+
+/*
+ * GUC parameters.  Redirect_stderr cannot be changed after postmaster
+ * start, but the rest can change at SIGHUP.
+ */
+bool		Redirect_stderr = false;
+int			Log_RotationAge = 24*60;
+int			Log_RotationSize  = 10*1024;
+char *      Log_directory = "pg_log";
+char *      Log_filename_prefix = "postgresql-";
+
+/*
+ * Globally visible state (used by elog.c)
+ */
+bool am_syslogger = false;
+
+/*
+ * Private state
+ */
+static pg_time_t	last_rotation_time = 0;
+
+static bool	redirection_done = false;
+
+static bool	pipe_eof_seen = false;
+
+static FILE *syslogFile = NULL;
+
+/* These must be exported for EXEC_BACKEND case ... annoying */
+#ifndef WIN32
+int syslogPipe[2] = {-1, -1};
+#else
+HANDLE syslogPipe[2] = {0, 0};
+#endif
+
+#ifdef WIN32
+static HANDLE threadHandle=0;
+static CRITICAL_SECTION sysfileSection;
+#endif
+
+/*
+ * Flags set by interrupt handlers for later service in the main loop.
+ */
+static volatile sig_atomic_t got_SIGHUP = false;
+
+
+/* Local subroutines */
+#ifdef EXEC_BACKEND
+static pid_t syslogger_forkexec(void);
+static void syslogger_parseArgs(int argc, char *argv[]);
+#endif
+#ifdef WIN32
+static unsigned int __stdcall pipeThread(void *arg);
+#endif
+static void logfile_rotate(void);
+static char* logfile_getname(pg_time_t timestamp);
+static void sigHupHandler(SIGNAL_ARGS);
+
+
+/*
+ * Main entry point for syslogger process
+ * argc/argv parameters are valid only in EXEC_BACKEND case.
+ */
+NON_EXEC_STATIC void
+SysLoggerMain(int argc, char *argv[])
+{
+	char         currentLogDir[MAXPGPATH];
+
+	IsUnderPostmaster = true;	/* we are a postmaster subprocess now */
+
+	MyProcPid = getpid();		/* reset MyProcPid */
+
+	/* Lose the postmaster's on-exit routines */
+	on_exit_reset();
+
+#ifdef EXEC_BACKEND
+	syslogger_parseArgs(argc, argv);
+#endif /* EXEC_BACKEND */
+
+	am_syslogger = true;
+
+	init_ps_display("logger process", "", "");
+	set_ps_display("");
+
+	/*
+	 * If we restarted, our stderr is already redirected into our own
+	 * input pipe.  This is of course pretty useless, not to mention that
+	 * it interferes with detecting pipe EOF.  Point stderr to /dev/null.
+	 * This assumes that all interesting messages generated in the syslogger
+	 * will come through elog.c and will be sent to write_syslogger_file.
+	 */
+	if (redirection_done)
+	{
+		int	i = open(NULL_DEV, O_WRONLY);
+
+		dup2(i, fileno(stdout));
+		dup2(i, fileno(stderr));
+		close(i);
+	}
+
+	/*
+	 * Also close our copy of the write end of the pipe.  This is needed
+	 * to ensure we can detect pipe EOF correctly.  (But note that in the
+	 * restart case, the postmaster already did this.)
+	 */
+#ifndef WIN32
+	if (syslogPipe[1] >= 0)
+		close(syslogPipe[1]);
+	syslogPipe[1] = -1;
+#else
+	if (syslogPipe[1])
+		CloseHandle(syslogPipe[1]);
+	syslogPipe[1] = 0;
+#endif
+
+	/*
+	 * Properly accept or ignore signals the postmaster might send us
+	 *
+	 * Note: we ignore all termination signals, and instead exit only when
+	 * all upstream processes are gone, to ensure we don't miss any dying
+	 * gasps of broken backends...
+	 */
+
+	pqsignal(SIGHUP, sigHupHandler);	/* set flag to read config file */
+	pqsignal(SIGINT,  SIG_IGN);
+	pqsignal(SIGTERM, SIG_IGN);
+	pqsignal(SIGQUIT, SIG_IGN);
+	pqsignal(SIGALRM, SIG_IGN);
+	pqsignal(SIGPIPE, SIG_IGN);
+	pqsignal(SIGUSR1, SIG_IGN);
+	pqsignal(SIGUSR2, SIG_IGN);
+
+	/*
+	 * Reset some signals that are accepted by postmaster but not here
+	 */
+	pqsignal(SIGCHLD, SIG_DFL);
+	pqsignal(SIGTTIN, SIG_DFL);
+	pqsignal(SIGTTOU, SIG_DFL);
+	pqsignal(SIGCONT, SIG_DFL);
+	pqsignal(SIGWINCH, SIG_DFL);
+
+	PG_SETMASK(&UnBlockSig);
+
+#ifdef WIN32
+	/* Fire up separate data transfer thread */
+	InitializeCriticalSection(&sysfileSection);
+
+	{
+		unsigned int tid;
+
+		threadHandle = (HANDLE)_beginthreadex(0, 0, pipeThread, 0, 0, &tid);
+	}
+#endif  /* WIN32 */
+
+	/* remember age of initial logfile */
+	last_rotation_time = time(NULL);
+	/* remember active logfile directory */
+	strncpy(currentLogDir, Log_directory, MAXPGPATH);
+
+	/* main worker loop */
+	for (;;)
+	{
+		bool rotation_requested = false;
+#ifndef WIN32
+		char        logbuffer[1024];
+		int          bytesRead;
+		int         rc;
+		fd_set		rfds;
+		struct timeval timeout;
+#endif
+
+		if (got_SIGHUP)
+		{
+			got_SIGHUP = false;
+			ProcessConfigFile(PGC_SIGHUP);
+
+			/*
+			 * Check if the log directory changed in postgresql.conf. If so,
+			 * force rotation to make sure we're writing the logfiles in the
+			 * right place.
+			 *
+			 * XXX is it worth responding similarly to a change of
+			 * Log_filename_prefix?
+			 */
+			if (strncmp(Log_directory, currentLogDir, MAXPGPATH) != 0)
+			{
+				strncpy(currentLogDir, Log_directory, MAXPGPATH);
+				rotation_requested = true;
+			}
+		}
+
+		if (!rotation_requested &&
+			last_rotation_time != 0 &&
+			Log_RotationAge > 0)
+		{
+			/*
+			 * Do a logfile rotation if too much time has elapsed
+			 * since the last one.
+			 */
+			pg_time_t   now = time(NULL);
+			int         elapsed_secs = now - last_rotation_time;
+
+			if (elapsed_secs >= Log_RotationAge * 60)
+				rotation_requested = true;
+		}
+
+		if (!rotation_requested && Log_RotationSize > 0)
+		{
+			/*
+			 * Do a rotation if file is too big
+			 */
+			if (ftell(syslogFile) >= Log_RotationSize * 1024L)
+				rotation_requested = true;
+		}
+
+		if (rotation_requested)
+			logfile_rotate();
+
+#ifndef WIN32
+		/*
+		 * Wait for some data, timing out after 1 second
+		 */
+		FD_ZERO(&rfds);
+		FD_SET(syslogPipe[0], &rfds);
+		timeout.tv_sec=1;
+		timeout.tv_usec=0;
+
+		rc = select(syslogPipe[0]+1, &rfds, NULL, NULL, &timeout);
+
+		if (rc < 0)
+		{
+			if (errno != EINTR)
+				ereport(LOG,
+						(errcode_for_socket_access(),
+						 errmsg("select() failed in logger process: %m")));
+		}
+		else if (rc > 0 && FD_ISSET(syslogPipe[0], &rfds))
+		{
+		    bytesRead = piperead(syslogPipe[0],
+								 logbuffer, sizeof(logbuffer));
+
+			if (bytesRead < 0)
+			{
+				if (errno != EINTR)
+					ereport(LOG,
+							(errcode_for_socket_access(),
+							 errmsg("could not read from logger pipe: %m")));
+			}
+			else if (bytesRead > 0)
+			{
+				write_syslogger_file(logbuffer, bytesRead);
+				continue;
+			}
+			else
+			{
+				/*
+				 * Zero bytes read when select() is saying read-ready
+				 * means EOF on the pipe: that is, there are no longer
+				 * any processes with the pipe write end open.  Therefore,
+				 * the postmaster and all backends are shut down, and we
+				 * are done.
+				 */
+				pipe_eof_seen = true;
+			}
+		}
+#else /* WIN32 */
+		/*
+		 * On Windows we leave it to a separate thread to transfer data and
+		 * detect pipe EOF.  The main thread just wakes up once a second to
+		 * check for SIGHUP and rotation conditions.
+		 */
+		pgwin32_backend_usleep(1000000);
+#endif /* WIN32 */
+
+		if (pipe_eof_seen)
+		{
+			ereport(LOG,
+					(errmsg("logger shutting down")));
+			if (syslogFile)
+				fclose(syslogFile);
+			/* normal exit from the syslogger is here */
+			proc_exit(0);
+		}
+	}
+}
+
+/*
+ * Postmaster subroutine to start a syslogger subprocess.
+ */
+int
+SysLogger_Start(void)
+{
+    pid_t sysloggerPid;
+	pg_time_t now;
+	char *filename;
+
+	if (!Redirect_stderr)
+	    return 0;
+
+	/*
+	 * If first time through, create the pipe which will receive stderr output.
+	 *
+	 * If the syslogger crashes and needs to be restarted, we continue to use
+	 * the same pipe (indeed must do so, since extant backends will be writing
+	 * into that pipe).
+	 *
+	 * This means the postmaster must continue to hold the read end of the
+	 * pipe open, so we can pass it down to the reincarnated syslogger.
+	 * This is a bit klugy but we have little choice.
+	 */
+#ifndef WIN32
+    if (syslogPipe[0] < 0)
+	{
+	    if (pgpipe(syslogPipe) < 0)
+		    ereport(FATAL,
+					(errcode_for_socket_access(),
+					 (errmsg("could not create pipe for syslogging: %m"))));
+	}
+#else
+    if (!syslogPipe[0])
+	{
+		SECURITY_ATTRIBUTES sa;
+
+		memset(&sa, 0, sizeof(SECURITY_ATTRIBUTES));
+		sa.nLength = sizeof(SECURITY_ATTRIBUTES);
+		sa.bInheritHandle = TRUE;
+
+		if (!CreatePipe(&syslogPipe[0], &syslogPipe[1], &sa, 32768))
+		    ereport(FATAL,
+					(errcode_for_file_access(),
+					 (errmsg("could not create pipe for syslogging: %m"))));
+	}
+#endif
+
+	/*
+	 * create log directory if not present; ignore errors
+	 */
+	if (is_absolute_path(Log_directory))
+		mkdir(Log_directory, 0700);
+	else
+	{
+		filename = palloc(MAXPGPATH);
+		snprintf(filename, MAXPGPATH, "%s/%s", DataDir, Log_directory);
+		mkdir(filename, 0700);
+		pfree(filename);
+	}
+
+	/*
+	 * The initial logfile is created right in the postmaster,
+	 * to verify that the Log_directory is writable.
+	 */
+	now = time(NULL);
+	filename = logfile_getname(now);
+
+	syslogFile = fopen(filename, "a");
+
+	if (!syslogFile)
+	    ereport(FATAL,
+				(errcode_for_file_access(),
+				 (errmsg("could not create logfile \"%s\": %m",
+						 filename))));
+
+	setvbuf(syslogFile, NULL, _IOLBF, 0);
+
+	pfree(filename);
+
+	/*
+	 * Now we can fork off the syslogger subprocess.
+	 */
+	fflush(stdout);
+	fflush(stderr);
+
+#ifdef __BEOS__
+	/* Specific beos actions before backend startup */
+	beos_before_backend_startup();
+#endif
+
+#ifdef EXEC_BACKEND
+	switch ((sysloggerPid = syslogger_forkexec()))
+#else
+	switch ((sysloggerPid = fork()))
+#endif
+	{
+		case -1:
+#ifdef __BEOS__
+			/* Specific beos actions */
+			beos_backend_startup_failed();
+#endif
+			ereport(LOG,
+					(errmsg("could not fork system logger: %m")));
+			return 0;
+
+#ifndef EXEC_BACKEND
+		case 0:
+			/* in postmaster child ... */
+#ifdef __BEOS__
+			/* Specific beos actions after backend startup */
+			beos_backend_startup();
+#endif
+			/* Close the postmaster's sockets */
+			ClosePostmasterPorts(true);
+
+			/* Drop our connection to postmaster's shared memory, as well */
+			PGSharedMemoryDetach();
+
+			/* do the work */
+			SysLoggerMain(0, NULL);
+			break;
+#endif
+
+		default:
+			/* success, in postmaster */
+
+			/* now we redirect stderr, if not done already */
+			if (!redirection_done)
+			{
+#ifndef WIN32
+				fflush(stdout);
+				if (dup2(syslogPipe[1], fileno(stdout)) < 0)
+					ereport(FATAL,
+							(errcode_for_file_access(),
+							 errmsg("could not redirect stdout: %m")));
+				fflush(stderr);
+				if (dup2(syslogPipe[1], fileno(stderr)) < 0)
+					ereport(FATAL,
+							(errcode_for_file_access(),
+							 errmsg("could not redirect stderr: %m")));
+				/* Now we are done with the write end of the pipe. */
+				close(syslogPipe[1]);
+				syslogPipe[1] = -1;
+#else
+				fflush(stderr);
+				if (dup2(_open_osfhandle((long)syslogPipe[1], _O_APPEND),
+						 _fileno(stderr)) < 0)
+					ereport(FATAL,
+							(errcode_for_file_access(),
+							 errmsg("could not redirect stderr: %m")));
+				/* Now we are done with the write end of the pipe. */
+				CloseHandle(syslogPipe[1]);
+				syslogPipe[1] = 0;
+#endif
+				redirection_done = true;
+			}
+
+			/* postmaster will never write the file; close it */
+			fclose(syslogFile);
+			syslogFile = NULL;
+			return (int) sysloggerPid;
+	}
+
+	/* we should never reach here */
+	return 0;
+}
+
+
+#ifdef EXEC_BACKEND
+
+/*
+ * syslogger_forkexec() -
+ *
+ * Format up the arglist for, then fork and exec, a syslogger process
+ */
+static pid_t
+syslogger_forkexec(void)
+{
+	char *av[10];
+	int ac = 0, bufc = 0, i;
+	char numbuf[2][32];
+
+	av[ac++] = "postgres";
+	av[ac++] = "-forklog";
+	av[ac++] = NULL;			/* filled in by postmaster_forkexec */
+
+	/* static variables (those not passed by write_backend_variables) */
+#ifndef WIN32
+	if (syslogFile != NULL)
+	    snprintf(numbuf[bufc++], 32, "%d", fileno(syslogFile));
+    else
+	    strcpy(numbuf[bufc++], "-1");
+	snprintf(numbuf[bufc++], 32, "%d", (int) redirection_done);
+#else  /* WIN32 */
+	if (syslogFile != NULL)
+	    snprintf(numbuf[bufc++], 32, "%ld",
+				 _get_osfhandle(_fileno(syslogFile)));
+    else
+	    strcpy(numbuf[bufc++], "0");
+	snprintf(numbuf[bufc++], 32, "%d", (int) redirection_done);
+#endif /* WIN32 */
+
+	/* Add to the arg list */
+	Assert(bufc <= lengthof(numbuf));
+	for (i = 0; i < bufc; i++)
+		av[ac++] = numbuf[i];
+
+	av[ac] = NULL;
+	Assert(ac < lengthof(av));
+
+	return postmaster_forkexec(ac, av);
+}
+
+/*
+ * syslogger_parseArgs() -
+ *
+ * Extract data from the arglist for exec'ed syslogger process
+ */
+static void
+syslogger_parseArgs(int argc, char *argv[])
+{
+    int fd;
+
+	Assert(argc == 5);
+	argv += 3;
+
+#ifndef WIN32
+	fd = atoi(*argv++);
+	if (fd != -1)
+	{
+	    syslogFile = fdopen(fd, "a");
+		setvbuf(syslogFile, NULL, _IOLBF, 0);
+	}
+	redirection_done = (bool) atoi(*argv++);
+#else  /* WIN32 */
+	fd = atoi(*argv++);
+	if (fd != 0)
+	{
+		fd = _open_osfhandle(fd, _O_APPEND);
+		if (fd != 0)
+		{
+			syslogFile = fdopen(fd, "a");
+			setvbuf(syslogFile, NULL, _IOLBF, 0);
+		}
+	}
+	redirection_done = (bool) atoi(*argv++);
+#endif /* WIN32 */
+}
+
+#endif /* EXEC_BACKEND */
+
+
+/* --------------------------------
+ *		logfile routines
+ * --------------------------------
+ */
+
+/*
+ * Write to the currently open logfile
+ *
+ * This is exported so that elog.c can call it when am_syslogger is true.
+ * This allows the syslogger process to record elog messages of its own,
+ * even though its stderr does not point at the syslog pipe.
+ */
+void
+write_syslogger_file(const char *buffer, int count)
+{
+    int rc;
+
+#ifndef WIN32
+    rc = fwrite(buffer, 1, count, syslogFile);
+#else
+    EnterCriticalSection(&sysfileSection);
+    rc = fwrite(buffer, 1, count, syslogFile);
+    LeaveCriticalSection(&sysfileSection);
+#endif
+
+    if (rc != count)
+        ereport(LOG,
+				(errcode_for_file_access(),
+				 errmsg("could not write to logfile: %m")));
+}
+
+#ifdef WIN32
+
+/*
+ * Worker thread to transfer data from the pipe to the current logfile.
+ *
+ * We need this because on Windows, WaitForSingleObject does not work on
+ * unnamed pipes: it always reports "signaled", so the blocking ReadFile won't
+ * allow for SIGHUP; and select is for sockets only.
+ */
+static unsigned int __stdcall
+pipeThread(void *arg)
+{
+    DWORD bytesRead;
+    char    logbuffer[1024];
+
+    for (;;)
+    {
+        if (!ReadFile(syslogPipe[0], logbuffer, sizeof(logbuffer),
+					  &bytesRead, 0))
+		{
+			DWORD error = GetLastError();
+
+			if (error == ERROR_HANDLE_EOF)
+				break;
+			ereport(LOG,
+					(errcode_for_file_access(),
+					 errmsg("could not read from logger pipe: %m")));
+		}
+        else if (bytesRead > 0)
+            write_syslogger_file(logbuffer, bytesRead);
+    }
+
+	/* We exit the above loop only upon detecting pipe EOF */
+	pipe_eof_seen = true;
+    _endthread();
+    return 0;
+}
+
+#endif /* WIN32 */
+
+/*
+ * perform logfile rotation
+ */
+static void
+logfile_rotate(void)
+{
+	char *filename;
+	pg_time_t now;
+	FILE *fh;
+
+	now = time(NULL);
+	filename = logfile_getname(now);
+
+	fh = fopen(filename, "a");
+	if (!fh)
+	{
+		int	saveerrno = errno;
+
+		ereport(LOG,
+				(errcode_for_file_access(),
+				 errmsg("could not open new logfile \"%s\": %m",
+						filename)));
+
+		/*
+		 * ENFILE/EMFILE are not too surprising on a busy system; just keep
+		 * using the old file till we manage to get a new one.  Otherwise,
+		 * assume something's wrong with Log_directory and stop trying to
+		 * create files.
+		 */
+		if (saveerrno != ENFILE && saveerrno != EMFILE)
+		{
+			ereport(LOG,
+				(errmsg("disabling auto rotation (use SIGHUP to reenable)")));
+			Log_RotationAge = 0;
+			Log_RotationSize = 0;
+		}
+		pfree(filename);
+		return;
+	}
+
+	setvbuf(fh, NULL, _IOLBF, 0);
+
+	/* On Windows, need to interlock against data-transfer thread */
+#ifdef WIN32
+	EnterCriticalSection(&sysfileSection);
+#endif
+	fclose(syslogFile);
+	syslogFile = fh;
+#ifdef WIN32
+	LeaveCriticalSection(&sysfileSection);
+#endif
+
+	last_rotation_time = now;
+
+	pfree(filename);
+}
+
+
+/*
+ * construct logfile name using timestamp information
+ *
+ * Result is palloc'd.
+ */
+static char*
+logfile_getname(pg_time_t timestamp)
+{
+	char *filename;
+	char stamptext[128];
+
+	pg_strftime(stamptext, sizeof(stamptext), "%Y-%m-%d_%H%M%S",
+				pg_localtime(&timestamp));
+
+	filename = palloc(MAXPGPATH);
+
+	if (is_absolute_path(Log_directory))
+		snprintf(filename, MAXPGPATH, "%s/%s%05u_%s.log",
+				 Log_directory, Log_filename_prefix,
+				 (unsigned int) PostmasterPid, stamptext);
+	else
+		snprintf(filename, MAXPGPATH, "%s/%s/%s%05u_%s.log",
+				 DataDir, Log_directory, Log_filename_prefix,
+				 (unsigned int) PostmasterPid, stamptext);
+
+	return filename;
+}
+
+/* --------------------------------
+ *		signal handler routines
+ * --------------------------------
+ */
+
+/* SIGHUP: set flag to reload config file */
+static void
+sigHupHandler(SIGNAL_ARGS)
+{
+    got_SIGHUP = true;
+}
diff --git a/src/backend/utils/error/elog.c b/src/backend/utils/error/elog.c
index 340cca03cac63c635984010ceb8fe7a0552040f6..9723cf76f590121995fc0af8c476783e003802b2 100644
--- a/src/backend/utils/error/elog.c
+++ b/src/backend/utils/error/elog.c
@@ -37,7 +37,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/utils/error/elog.c,v 1.145 2004/08/04 20:58:46 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/utils/error/elog.c,v 1.146 2004/08/05 23:32:11 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -57,6 +57,7 @@
 #include "mb/pg_wchar.h"
 #include "miscadmin.h"
 #include "postmaster/postmaster.h"
+#include "postmaster/syslogger.h"
 #include "storage/ipc.h"
 #include "tcop/tcopprot.h"
 #include "utils/memutils.h"
@@ -71,7 +72,7 @@ sigjmp_buf *PG_exception_stack = NULL;
 /* GUC parameters */
 PGErrorVerbosity Log_error_verbosity = PGERROR_VERBOSE;
 char       *Log_line_prefix = NULL; /* format for extra log line info */
-unsigned int Log_destination = LOG_DESTINATION_STDERR;
+int			Log_destination = LOG_DESTINATION_STDERR;
 
 #ifdef HAVE_SYSLOG
 char	   *Syslog_facility;	/* openlog() parameters */
@@ -1589,6 +1590,10 @@ send_message_to_server_log(ErrorData *edata)
 		fprintf(stderr, "%s", buf.data);
 	}
 
+	/* If in the syslogger process, try to write messages direct to file */
+	if (am_syslogger)
+		write_syslogger_file(buf.data, buf.len);
+
 	pfree(buf.data);
 }
 
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 22df3effc329e1812c7d96603d39d8c0b485e0e2..a827653bec400ab6b9cb153b158a14df2e1698de 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -10,7 +10,7 @@
  * Written by Peter Eisentraut <peter_e@gmx.net>.
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.225 2004/07/28 14:23:29 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.226 2004/08/05 23:32:12 tgl Exp $
  *
  *--------------------------------------------------------------------
  */
@@ -44,6 +44,7 @@
 #include "parser/parse_expr.h"
 #include "parser/parse_relation.h"
 #include "postmaster/bgwriter.h"
+#include "postmaster/syslogger.h"
 #include "postmaster/postmaster.h"
 #include "storage/bufmgr.h"
 #include "storage/fd.h"
@@ -801,19 +802,13 @@ static struct config_bool ConfigureNamesBool[] =
 		&default_with_oids,
 		true, NULL, NULL
 	},
-
 	{
-		{"integer_datetimes", PGC_INTERNAL, COMPILE_OPTIONS,
-			gettext_noop("Datetimes are integer based"),
-			NULL,
-			GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE
+		{"redirect_stderr", PGC_POSTMASTER, LOGGING_WHERE,
+		 gettext_noop("Start a subprocess to capture stderr output into log files"),
+		 NULL
 		},
-		&integer_datetimes,
-#ifdef HAVE_INT64_TIMESTAMP
-		true, NULL, NULL
-#else
+		&Redirect_stderr,
 		false, NULL, NULL
-#endif
 	},
 
 #ifdef WAL_DEBUG
@@ -828,6 +823,20 @@ static struct config_bool ConfigureNamesBool[] =
 	},
 #endif
 
+	{
+		{"integer_datetimes", PGC_INTERNAL, COMPILE_OPTIONS,
+			gettext_noop("Datetimes are integer based"),
+			NULL,
+			GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE
+		},
+		&integer_datetimes,
+#ifdef HAVE_INT64_TIMESTAMP
+		true, NULL, NULL
+#else
+		false, NULL, NULL
+#endif
+	},
+
 	/* End-of-list marker */
 	{
 		{NULL, 0, 0, NULL, NULL}, NULL, false, NULL, NULL
@@ -1245,6 +1254,24 @@ static struct config_int ConfigureNamesInt[] =
 		100, 1, 1000, NULL, NULL
 	},
 
+	{
+		{"log_rotation_age", PGC_SIGHUP, LOGGING_WHERE,
+		 gettext_noop("Automatic logfile rotation will occur after N minutes"),
+		 NULL
+		},
+		&Log_RotationAge,
+		24*60, 0, INT_MAX, NULL, NULL
+	},
+
+	{
+		{"log_rotation_size", PGC_SIGHUP, LOGGING_WHERE,
+		 gettext_noop("Automatic logfile rotation will occur after N kilobytes"),
+		 NULL
+		},
+		&Log_RotationSize,
+		10*1024, 0, INT_MAX, NULL, NULL
+	},
+
 	{
 		{"max_function_args", PGC_INTERNAL, COMPILE_OPTIONS,
 			gettext_noop("Shows the maximum number of function arguments"),
@@ -1634,6 +1661,23 @@ static struct config_string ConfigureNamesString[] =
 		&log_destination_string,
 		"stderr", assign_log_destination, NULL
 	},
+	{
+		{"log_directory", PGC_SIGHUP, LOGGING_WHERE,
+		 gettext_noop("Sets the destination directory for logfiles."),
+		 gettext_noop("May be specified as relative to the cluster directory "
+					  "or as absolute path.")
+		},
+		&Log_directory,
+		"pg_log", NULL, NULL
+	},
+	{
+		{"log_filename_prefix", PGC_SIGHUP, LOGGING_WHERE,
+		 gettext_noop("Prefix for file names created in the log_directory."),
+		 NULL
+		},
+		&Log_filename_prefix,
+		"postgresql-", NULL, NULL
+	},
 
 #ifdef HAVE_SYSLOG
 	{
@@ -5055,7 +5099,7 @@ assign_log_destination(const char *value, bool doit, GucSource source)
 	char *rawstring;
 	List *elemlist;
 	ListCell *l;
-	unsigned int  newlogdest = 0;
+	int  newlogdest = 0;
  
 	/* Need a modifiable copy of string */
 	rawstring = pstrdup(value);
diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample
index 9dc1ec8d837323d227814062789f9b52c693634e..633bb5a32296dd9d2cd39c62100cb65f864dbd28 100644
--- a/src/backend/utils/misc/postgresql.conf.sample
+++ b/src/backend/utils/misc/postgresql.conf.sample
@@ -170,9 +170,23 @@
 #log_destination = 'stderr'	# Valid values are combinations of stderr,
                                 # syslog and eventlog, depending on
                                 # platform.
+
+# This is relevant when logging to stderr:
+#redirect_stderr = false    # Enable capturing of stderr into log files.
+# These are only relevant if redirect_stderr is true:
+#log_directory = 'pg_log'   # Directory where logfiles are written.
+                            # May be specified absolute or relative to PGDATA
+#log_filename_prefix = 'postgresql_' # Prefix for logfile names.
+#log_rotation_age = 1440    # Automatic rotation of logfiles will happen after
+                            # so many minutes.  0 to disable.
+#log_rotation_size = 10240  # Automatic rotation of logfiles will happen after
+                            # so many kilobytes of log output.  0 to disable.
+
+# These are relevant when logging to syslog:
 #syslog_facility = 'LOCAL0'
 #syslog_ident = 'postgres'
 
+
 # - When to Log -
 
 #client_min_messages = notice	# Values, in order of decreasing detail:
diff --git a/src/include/postmaster/postmaster.h b/src/include/postmaster/postmaster.h
index 75242d156d1acc7b62eba2468a9b4148f71fc1ff..9afc228efd0e6cb7bdcc43aa96c62144fe79553d 100644
--- a/src/include/postmaster/postmaster.h
+++ b/src/include/postmaster/postmaster.h
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/postmaster/postmaster.h,v 1.4 2004/07/21 20:34:48 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/postmaster/postmaster.h,v 1.5 2004/08/05 23:32:12 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -36,7 +36,7 @@ extern HANDLE PostmasterHandle;
 
 
 extern int	PostmasterMain(int argc, char *argv[]);
-extern void ClosePostmasterPorts(void);
+extern void ClosePostmasterPorts(bool am_syslogger);
 #ifdef EXEC_BACKEND
 extern pid_t postmaster_forkexec(int argc, char *argv[]);
 extern int	SubPostmasterMain(int argc, char *argv[]);
diff --git a/src/include/postmaster/syslogger.h b/src/include/postmaster/syslogger.h
new file mode 100644
index 0000000000000000000000000000000000000000..a0f775c9a21099132adf30c9fa16ea6a4caf7bd4
--- /dev/null
+++ b/src/include/postmaster/syslogger.h
@@ -0,0 +1,39 @@
+/*-------------------------------------------------------------------------
+ *
+ * syslogger.h
+ *	  Exports from postmaster/syslogger.c.
+ *
+ * Copyright (c) 2004, PostgreSQL Global Development Group
+ *
+ * $PostgreSQL: pgsql/src/include/postmaster/syslogger.h,v 1.1 2004/08/05 23:32:12 tgl Exp $
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef _SYSLOGGER_H
+#define _SYSLOGGER_H
+
+/* GUC options */
+extern bool Redirect_stderr;
+extern int	Log_RotationAge;
+extern int	Log_RotationSize;
+extern char *Log_directory;
+extern char *Log_filename_prefix;
+
+extern bool am_syslogger;
+
+#ifndef WIN32
+extern int syslogPipe[2];
+#else
+extern HANDLE syslogPipe[2];
+#endif
+
+
+extern int SysLogger_Start(void);
+
+extern void write_syslogger_file(const char *buffer, int count);
+
+#ifdef EXEC_BACKEND
+extern void SysLoggerMain(int argc, char *argv[]);
+#endif
+
+#endif   /* _SYSLOGGER_H */
diff --git a/src/include/utils/elog.h b/src/include/utils/elog.h
index 4a2d26ddb9d97a291cb33b74a563bf420b5b97cf..ac27b796249eda4abf638251904ad2fe167713bc 100644
--- a/src/include/utils/elog.h
+++ b/src/include/utils/elog.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/utils/elog.h,v 1.72 2004/07/31 23:04:55 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/utils/elog.h,v 1.73 2004/08/05 23:32:13 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -272,7 +272,7 @@ typedef enum
 
 extern PGErrorVerbosity Log_error_verbosity;
 extern char *Log_line_prefix;
-extern unsigned int Log_destination;
+extern int Log_destination;
 
 /* Log destination bitmap */
 #define LOG_DESTINATION_STDERR   1