Attached the patch, an orgy in #ifdefs, decorated with various indents and crlf line ends (glad we have pgindent).

Remarks:
Log_destination for win32 is set to file, because stderr is equivalent to /dev/null for services. This doesn't reflect correctly in postgresql.conf.sample.


Log_destination=eventlog is like logging to /var/log/messages, you'd make the sysadmin your enemy if he finds his app log flooded with "NOTICE: created implicit index for pk". FYI: The size of the event log is limited (default: 512k), cyclic overwriting can be selected, but *no* rotation. Only really important messages should go there, not standard logging. OTOH, really important messages *must* go there, so I changed FATAL and PANIC messages to eventlog unconditionally.


Regards, Andreas
Index: backend/postmaster/Makefile
===================================================================
RCS file: /projects/cvsroot/pgsql-server/src/backend/postmaster/Makefile,v
retrieving revision 1.18
diff -u -r1.18 Makefile
--- backend/postmaster/Makefile	21 Jul 2004 20:34:46 -0000	1.18
+++ backend/postmaster/Makefile	4 Aug 2004 18:40:01 -0000
@@ -12,7 +12,7 @@
 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
 
Index: backend/postmaster/postmaster.c
===================================================================
RCS file: /projects/cvsroot/pgsql-server/src/backend/postmaster/postmaster.c,v
retrieving revision 1.418
diff -u -r1.418 postmaster.c
--- backend/postmaster/postmaster.c	1 Aug 2004 17:45:43 -0000	1.418
+++ backend/postmaster/postmaster.c	4 Aug 2004 18:40:06 -0000
@@ -117,7 +117,7 @@
 #include "utils/ps_status.h"
 #include "bootstrap/bootstrap.h"
 #include "pgstat.h"
-
+#include "postmaster/syslogger.h"
 
 /*
  * List of active backends (or child processes anyway; we don't actually
@@ -200,6 +200,7 @@
 			BgWriterPID = 0,
 			PgArchPID = 0,
 			PgStatPID = 0;
+pid_t       SysLoggerPID = 0;
 
 /* Startup/shutdown state */
 #define			NoShutdown		0
@@ -851,6 +852,12 @@
 #endif
 
 	/*
+	 * start logging to file
+	 */ 
+
+    SysLoggerPID = SysLogger_Start();
+
+	/*
 	 * Reset whereToSendOutput from Debug (its starting state) to None.
 	 * This stops ereport from sending log messages to stderr unless
 	 * Log_destination permits.  We don't do this until the postmaster
@@ -1230,6 +1237,11 @@
 			StartupPID == 0 && !FatalError && Shutdown == NoShutdown)
 			PgStatPID = pgstat_start();
 
+		/* If we have lost the system logger, try to start a new one */
+		if (SysLoggerPID == 0 &&
+			StartupPID == 0 && !FatalError && Shutdown == NoShutdown)
+			SysLoggerPID = SysLogger_Start();
+
 		/*
 		 * Touch the socket and lock file at least every ten minutes, to ensure
 		 * that they are not removed by overzealous /tmp-cleaning tasks.
@@ -1770,6 +1782,8 @@
 			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();
@@ -1836,7 +1850,7 @@
 				kill(PgStatPID, SIGQUIT);
 			break;
 
-		case SIGINT:
+                        case SIGINT:
 			/*
 			 * Fast Shutdown:
 			 *
@@ -2064,6 +2078,15 @@
 			continue;
 		}
 
+		/* was it the system logger, try to start a new one */
+		if (SysLoggerPID != 0 && pid == SysLoggerPID)
+		{
+			if (exitstatus != 0)
+				LogChildExit(LOG, gettext("system logger process"),
+							 pid, exitstatus);
+			SysLoggerPID = SysLogger_Start();
+			continue;
+		}
 		/*
 		 * Else do standard backend child cleanup.
 		 */
@@ -2967,7 +2990,16 @@
 		PgstatCollectorMain(argc, argv);
 		proc_exit(0);
 	}
+	if (strcmp(argv[1], "-forklog") == 0)
+	{
+		/* Close the postmaster's sockets */
+		ClosePostmasterPorts();
 
+		/* Do not want to attach to shared memory */
+
+		SysLoggerMain(argc, argv);
+		proc_exit(0);
+	}
 	return 1;					/* shouldn't get here */
 }
 
@@ -3023,7 +3055,7 @@
 		if (Shutdown <= SmartShutdown)
 			SignalChildren(SIGUSR1);
 	}
- 
+
 	if (PgArchPID != 0 && Shutdown == NoShutdown)
 	{
 		if (CheckPostmasterSignal(PMSIGNAL_WAKEN_ARCHIVER))
@@ -3036,6 +3068,11 @@
 		}
     }
 
+    if (CheckPostmasterSignal(PMSIGNAL_ROTATE_LOGFILE) && SysLoggerPID != 0)
+    {
+        kill(SysLoggerPID, SIGUSR1);
+    }
+
 	PG_SETMASK(&UnBlockSig);
 
 	errno = save_errno;
Index: backend/utils/error/elog.c
===================================================================
RCS file: /projects/cvsroot/pgsql-server/src/backend/utils/error/elog.c,v
retrieving revision 1.144
diff -u -r1.144 elog.c
--- backend/utils/error/elog.c	31 Jul 2004 00:45:38 -0000	1.144
+++ backend/utils/error/elog.c	4 Aug 2004 18:40:10 -0000
@@ -71,7 +71,11 @@
 /* GUC parameters */
 PGErrorVerbosity Log_error_verbosity = PGERROR_VERBOSE;
 char       *Log_line_prefix = NULL; /* format for extra log line info */
+#ifdef WIN32
+unsigned int Log_destination = LOG_DESTINATION_FILE;
+#else
 unsigned int Log_destination = LOG_DESTINATION_STDERR;
+#endif
 
 #ifdef HAVE_SYSLOG
 char	   *Syslog_facility;	/* openlog() parameters */
@@ -83,6 +87,11 @@
 static void write_eventlog(int level, const char *line);
 #endif
 
+/* in syslogger.c */
+extern FILE *syslogFile;
+extern FILE *realStdErr;
+extern pid_t SysLoggerPID;
+
 /* We provide a small stack of ErrorData records for re-entrant cases */
 #define ERRORDATA_STACK_SIZE  5
 
@@ -1554,7 +1563,8 @@
 	}
 #endif   /* HAVE_SYSLOG */
 #ifdef WIN32
-	if (Log_destination & LOG_DESTINATION_EVENTLOG)
+	if ((Log_destination & LOG_DESTINATION_EVENTLOG)
+            || edata->elevel >= FATAL)
 	{
 		int eventlog_level;
 		switch (edata->elevel) 
@@ -1583,10 +1593,31 @@
 		write_eventlog(eventlog_level, buf.data);
 	}
 #endif   /* WIN32 */
-	/* Write to stderr, if enabled */
-	if ((Log_destination & LOG_DESTINATION_STDERR) || whereToSendOutput == Debug)
+	/*
+	 * Write to stderr. If Log_destination is file or stderr
+	 * if file is target, the logger process will handle this
+	 */
+	if ((Log_destination & (LOG_DESTINATION_STDERR | LOG_DESTINATION_FILE)) 
+		|| whereToSendOutput == Debug)
 	{
-		fprintf(stderr, "%s", buf.data);
+	    if (SysLoggerPID == MyProcPid || syslogFile != 0)
+            {
+                if ((Log_destination & LOG_DESTINATION_STDERR)
+                            || whereToSendOutput == Debug)
+                {
+                     if (realStdErr != 0)
+                        fprintf(realStdErr, "%s", buf.data);
+                    else
+                        fprintf(stderr, "%s", buf.data) ;
+
+                }
+
+                if (syslogFile != 0)
+                    fprintf(syslogFile, "%s", buf.data) ;
+            }
+            else
+		fprintf(stderr, "%s", buf.data) ;
+
 	}
 
 	pfree(buf.data);
Index: backend/utils/misc/guc.c
===================================================================
RCS file: /projects/cvsroot/pgsql-server/src/backend/utils/misc/guc.c,v
retrieving revision 1.225
diff -u -r1.225 guc.c
--- backend/utils/misc/guc.c	28 Jul 2004 14:23:29 -0000	1.225
+++ backend/utils/misc/guc.c	4 Aug 2004 18:40:19 -0000
@@ -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"
@@ -1285,6 +1286,23 @@
 		BLCKSZ, BLCKSZ, BLCKSZ, 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 if this size is reached (in kb)"),
+	   NULL
+	  },
+	  &Log_RotationSize,
+	  10*1024, 0, INT_MAX, NULL, NULL
+	},
+
 	/* End-of-list marker */
 	{
 		{NULL, 0, 0, NULL, NULL}, NULL, 0, 0, 0, NULL, NULL
@@ -1625,14 +1643,37 @@
 	},
 
 	{
-		{"log_destination", PGC_SIGHUP, LOGGING_WHERE,
-		 gettext_noop("Sets the destination for server log output."),
-		 gettext_noop("Valid values are combinations of stderr, syslog "
+		{"log_destination", PGC_POSTMASTER, LOGGING_WHERE,
+		 gettext_noop("Sets the target for log output."),
+		 gettext_noop("Valid values are combinations of stderr, file, syslog "
 					  "and eventlog, depending on platform."),
 		 GUC_LIST_INPUT
 		},
 		&log_destination_string,
+#ifdef WIN32
+		"file", assign_log_destination, NULL
+#else
 		"stderr", assign_log_destination, NULL
+#endif
+        },
+	{
+		{"log_directory", PGC_SIGHUP, LOGGING_WHERE,
+		 gettext_noop("Sets the target directory for log output."),
+		 gettext_noop("May be specified as relative to the cluster directory "
+					  "or as absolute path."),
+		 GUC_LIST_INPUT | GUC_REPORT
+		},
+		&Log_directory,
+		"pg_log", NULL, NULL
+	},
+	{
+		{"log_filename_prefix", PGC_SIGHUP, LOGGING_WHERE,
+		 gettext_noop("prefix for logfile names created in the log_directory."),
+		 NULL,
+		 GUC_LIST_INPUT | GUC_REPORT
+		},
+		&Log_filename_prefix,
+		"postgresql-", NULL, NULL
 	},
 
 #ifdef HAVE_SYSLOG
@@ -5079,6 +5120,8 @@
 	
 		if (pg_strcasecmp(tok,"stderr") == 0)
 			newlogdest |= LOG_DESTINATION_STDERR;
+		else if (pg_strcasecmp(tok,"file") == 0)
+			newlogdest |= LOG_DESTINATION_FILE;
 #ifdef HAVE_SYSLOG
 		else if (pg_strcasecmp(tok,"syslog") == 0)
 			newlogdest |= LOG_DESTINATION_SYSLOG;
Index: backend/utils/misc/postgresql.conf.sample
===================================================================
RCS file: /projects/cvsroot/pgsql-server/src/backend/utils/misc/postgresql.conf.sample,v
retrieving revision 1.118
diff -u -r1.118 postgresql.conf.sample
--- backend/utils/misc/postgresql.conf.sample	21 Jul 2004 20:34:46 -0000	1.118
+++ backend/utils/misc/postgresql.conf.sample	4 Aug 2004 18:40:20 -0000
@@ -167,9 +167,17 @@
 
 # - Where to Log -
 
-#log_destination = 'stderr'	# Valid values are combinations of stderr,
-                                # syslog and eventlog, depending on
-                                # platform.
+#log_destination = 'stderr' # Valid values are combinations of stderr, file,
+                            # syslog and eventlog, depending on platform.
+#log_directory = 'pg_log'   # subdirectory where logfiles are written 
+                            # if 'file' log_destination is used.
+                            # 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 if 
+                            # specified age in minutes is reached. 0 to disable.
+#log_rotation_size = 10240  # Automatic rotation of logfiles will happen if 
+                            # specified size in kb is reached. 0 to disable.
+
 #syslog_facility = 'LOCAL0'
 #syslog_ident = 'postgres'
 
Index: include/storage/pmsignal.h
===================================================================
RCS file: /projects/cvsroot/pgsql-server/src/include/storage/pmsignal.h,v
retrieving revision 1.9
diff -u -r1.9 pmsignal.h
--- include/storage/pmsignal.h	19 Jul 2004 02:47:15 -0000	1.9
+++ include/storage/pmsignal.h	4 Aug 2004 18:40:21 -0000
@@ -25,7 +25,7 @@
 	PMSIGNAL_PASSWORD_CHANGE,	/* pg_pwd file has changed */
 	PMSIGNAL_WAKEN_CHILDREN,	/* send a SIGUSR1 signal to all backends */
 	PMSIGNAL_WAKEN_ARCHIVER,	/* send a NOTIFY signal to xlog archiver */
-
+	PMSIGNAL_ROTATE_LOGFILE,	/* send SIGUSR1 to syslogger to rotate logfile */
 	NUM_PMSIGNALS				/* Must be last value of enum! */
 } PMSignalReason;
 
Index: elog.h===================================================================
RCS file: /projects/cvsroot/pgsql-server/src/include/utils/elog.h,v
retrieving revision 1.72
diff -u -r1.72 elog.h
--- elog.h	31 Jul 2004 23:04:55 -0000	1.72
+++ elog.h	4 Aug 2004 18:45:49 -0000
@@ -278,6 +278,7 @@
 #define LOG_DESTINATION_STDERR   1
 #define LOG_DESTINATION_SYSLOG   2
 #define LOG_DESTINATION_EVENTLOG 4
+#define LOG_DESTINATION_FILE     8
 
 /* Other exported functions */
 extern void DebugFileOpen(void);



/*-------------------------------------------------------------------------
 *
 * syslogger.c
 *
 * The system logger (syslogger) is new in Postgres 7.5. It catches all 
 * stderr output from backends, the postmaster and subprocesses by 
 * redirecting to a pipe, and writes it to a logfile and stderr if 
 * configured.
 * 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 <[EMAIL PROTECTED]>
 *
 * Copyright (c) 2004, PostgreSQL Global Development Group
 *
 *
 * IDENTIFICATION
 *	  $PostgreSQL: $
 *
 *-------------------------------------------------------------------------
 */
#include "postgres.h"

#include <signal.h>
#include <time.h>
#include <unistd.h>
#include "libpq/pqsignal.h"
#include "miscadmin.h"
#include "postmaster/postmaster.h"
#include "storage/pmsignal.h"
#include "storage/pg_shmem.h"
#include "storage/ipc.h"
#include "postmaster/syslogger.h"
#include "utils/ps_status.h"
#include "utils/guc.h"

/*
 * GUC parameters
 */
int			Log_RotationAge = 24*60;
int			Log_RotationSize  = 10*1024;
char *      Log_directory = "pg_log";
char *      Log_filename_prefix = "postgresql-";


extern pid_t SysLoggerPID;


/*
 * Flags set by interrupt handlers for later service in the main loop.
 */
static volatile sig_atomic_t got_SIGHUP = false;
static volatile sig_atomic_t rotation_requested = false;

#define MAXRETRIES  3
static pg_time_t	last_rotation_time = 0;
static char         currentLogDir[MAXPGPATH];


static void sigHupHandler(SIGNAL_ARGS);
static void rotationHandler(SIGNAL_ARGS);
void writeLogfile(char *buffer, int count);

#ifdef EXEC_BACKEND
static pid_t syslogger_forkexec(void);
#endif

static char* logfile_getname(pg_time_t timestamp);
static bool logfile_rotate(void);

FILE *realStdErr = NULL;
volatile FILE *syslogFile = NULL;

#ifdef WIN32
static unsigned int __stdcall pipeThread(void *arg);
static HANDLE readPipe=0, writePipe=0;
static HANDLE threadHandle=0;
static CRITICAL_SECTION sysfileSection;
#else
static int syslogPipe[2] = {0, 0};
#endif


void
writeLogfile(char *buffer, int count)
{
    int rc;
#ifdef WIN32
    EnterCriticalSection(&sysfileSection);
    rc = fwrite(buffer, 1, count, (FILE*)syslogFile);
    LeaveCriticalSection(&sysfileSection);
#else
    rc = fwrite(buffer, 1, count, (FILE*)syslogFile);
#endif
    if (rc < 1)
    {
        ereport(COMMERROR,
                            (errcode_for_file_access(),
                             errmsg("fwrite to logfile failed in system logger: %m")));
            exit(1);
    }

    if (Log_destination & LOG_DESTINATION_STDERR)
    {
        if (realStdErr)
            fwrite(buffer, 1, count, realStdErr);
        else
            fwrite(buffer, 1, count, stderr);
    }
}

#ifdef WIN32
unsigned int __stdcall
pipeThread(void *arg)
{
    DWORD bytesRead;
    char    logbuffer[1024];
    for (;;)
    {
        if (!ReadFile(readPipe, 
            logbuffer, sizeof(logbuffer), &bytesRead, 0))
        {
                ereport(COMMERROR,
                                (errcode_for_file_access(),
                                 errmsg("could not read from system logger pipe: %m")));
                exit(1);
        }
        if (bytesRead > 0)
            writeLogfile(logbuffer, bytesRead);
    }
    
    _endthread();
    return 0;
}
#endif

/*
 * Main entry point for syslogger process
 * argc/argv parameters are valid only in EXEC_BACKEND case.
 */

void
SysLoggerMain(int argc, char *argv[])
{
#ifdef EXEC_BACKEND
    int fd;
	Assert(argc == 8);
    
	argv += 3;
	strncpy(postgres_exec_path, *argv++, MAXPGPATH);

#ifdef WIN32
	readPipe = (HANDLE)atoi(*argv++);
	writePipe = (HANDLE)atoi(*argv++);
	fd = atoi(*argv++);
        if (fd != 0)
            fd = _open_osfhandle(fd, _O_APPEND);
	if (fd != 0)
	    syslogFile = fdopen(fd, "a+");

	fd = atoi(*argv++);
        if (fd != 0)
            fd = _open_osfhandle(fd, _O_APPEND);
	if (fd != 0)
        {
	    realStdErr = fdopen(fd, "a");
            setvbuf((FILE*)realStdErr, 0, _IONBF, 0);
        }
        InitializeCriticalSection(&sysfileSection);

        unsigned int tid;
        threadHandle = (HANDLE)_beginthreadex(0, 0, pipeThread, 0, 0, &tid);
        
#else
	syslogPipe[0] = atoi(*argv++);
	syslogPipe[1] = atoi(*argv++);
	fd = atoi(*argv++);
	if (fd != 0)
	    syslogFile = fdopen(fd, "a+");
	fd = atoi(*argv++);
	if (fd != 0)
        {
	    realStdErr = fdopen(fd, "a");
            setvbuf((FILE*)realStdErr, 0, _IONBF, 0);
        }
#endif

#endif 

        setvbuf((FILE*)syslogFile, 0, _IONBF, 0);
        
	IsUnderPostmaster = true;
	MyProcPid = getpid();
	init_ps_display("system logger process", "", "");
	set_ps_display("");

	/*
	 * Properly accept or ignore signals the postmaster might send us
	 *
	 * Note: we ignore all termination signals, and wait for the postmaster
	 * to die to catch as much pipe output as possible.
	 */

	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, rotationHandler);  /* request log rotation */
	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);

	/* 
	 * if we restarted, our stderr is redirected. 
	 * Direct it back to system stderr.
	 */
	if (realStdErr != NULL)
	{
	    if (dup2(fileno(realStdErr), fileno(stderr)) < 0)
		{
		    char *errstr = strerror(errno);
			/*
			 * Now we have a real problem: we can't redirect to stderr,
			 * and can't ereport it correctly (it would go into our queue
			 * which will never be read
			 * We're writing everywhere, hoping to leave at least some
			 * hint of what happened.
			 */
		    
		    fprintf(realStdErr, "PANIC: Syslogger couldn't redirect its stderr to the saved stderr: %s\n", errstr);
			fprintf(stderr, "PANIC: Syslogger couldn't redirect its stderr to the saved stderr: %s\n", errstr);
			ereport(PANIC,
					(errcode_for_file_access(),
					 (errmsg("Syslogger couldn't redirect its stderr to the saved stderr: %s", errstr))));
			exit(1);
		}

		realStdErr = NULL;
	}

	/* remember age of initial logfile */
	last_rotation_time = time(NULL);

	strncpy(currentLogDir, Log_directory, MAXPGPATH);
	/* main worker loop */
	for (;;)
	{
                pg_time_t   now;
                int         elapsed_secs;
#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, we rotate to make sure
                     * we're writing the logfiles where the backends
                     * expect us to do so.
                     */
                    if (strncmp(Log_directory, currentLogDir, MAXPGPATH))
                    {
                            rotation_requested = true;
                            strncpy(currentLogDir, Log_directory, MAXPGPATH);
                    }
                }
            
                if (!rotation_requested && last_rotation_time != 0 && Log_RotationAge > 0)
                {
                    /*
                     * Do an unforced rotation if too much time has elapsed
                       * since the last one.
                     */
                    now = time(NULL);
                    elapsed_secs = now - last_rotation_time;
                    if (elapsed_secs >= Log_RotationAge * 60)
                                rotation_requested = true;
                }
            
                if (!rotation_requested && Log_RotationSize > 0)
                {
                    /*
                     * Do an unforced rotation if file is too big
                     */
                    if (ftell((FILE*)syslogFile) >= Log_RotationSize * 1024)
                        rotation_requested = true;
                }
            
                if (rotation_requested)
                {
                    if (!logfile_rotate())
                    {
                        ereport(ERROR,
                                            (errcode_for_file_access(),
                                             (errmsg("logfile rotation failed, disabling auto rotation (SIGHUP to reenable): %m"))));
                      
                            Log_RotationAge = 0;
                            Log_RotationSize = 0;
                    }
                    rotation_requested = false;
                }

#ifdef WIN32
               pgwin32_backend_usleep(1000000);
#else
		FD_ZERO(&rfds);
		FD_SET(syslogPipe[0], &rfds);
		timeout.tv_sec=1;
		timeout.tv_usec=0;

		/*
		 * Check if data is present
		 */
		rc = select(syslogPipe[0]+1, &rfds, NULL, NULL, &timeout);
		PG_SETMASK(&UnBlockSig);

		if (rc < 0 && errno != EINTR)
		{
			ereport(COMMERROR,
					(errcode_for_socket_access(),
					 errmsg("select() failed in system logger: %m")));
			exit(1);
		}
		if (rc > 0 && FD_ISSET(syslogPipe[0], &rfds))
		{
		    bytesRead = piperead(syslogPipe[0],
								 logbuffer, sizeof(logbuffer));
			
			if (bytesRead < 0 && errno != EINTR)
			{
			    /* 
				 * EMFILE has been observed when a backend terminated
				 * after a SSL client connection broke down.
				 * There might be others we should ignore.
				 */
			    if (errno == EMFILE)
				    continue;

				ereport(COMMERROR,
						(errcode_for_socket_access(),
						 errmsg("could not read from system logger pipe: %m")));
				exit(1);
			}
                        else if (bytesRead > 0)
			{
                                writeLogfile(logbuffer, bytesRead);
				continue;
			}
                }
#endif
		/*
		 * If postmaster died, there's nothing to log any more.
		 * We check this only after pipe timeouts to receive as much as possible
		 * from the pipe.
		 */
		if (!PostmasterIsAlive(true))
		{
#ifdef WIN32
                    /* make sure the pipe is empty */
                    Sleep(100); 
                    SuspendThread(threadHandle);
                    CloseHandle(threadHandle);
#endif
                    if (syslogFile)
			    fclose((FILE*)syslogFile);
			exit(0);
		}
	}
}


int
SysLogger_Start(void)
{
    pid_t sysloggerPid;
	pg_time_t now;
	char *filename;

	if (!(Log_destination & LOG_DESTINATION_FILE))
	    return 0;

	/* create the pipe which will receive stderr output */	
#ifdef WIN32
    if (!readPipe)
	{
            SECURITY_ATTRIBUTES sa;
            memset(&sa, 0, sizeof(SECURITY_ATTRIBUTES));
            sa.nLength = sizeof(SECURITY_ATTRIBUTES);
            sa.bInheritHandle = TRUE;
            
            if (!CreatePipe(&readPipe, &writePipe, &sa, 32768))
		    ereport(FATAL,
					(errcode_for_file_access(),
					 (errmsg("pipe for syslogging not created: %m"))));
#else
    if (!syslogPipe[0])
	{
	    if (pgpipe(syslogPipe) < 0)
		    ereport(FATAL,
					(errcode_for_socket_access(),
					 (errmsg("pipe for syslogging not created: %m"))));

		if (!set_noblock(syslogPipe[1]))
		{
			ereport(FATAL,
					(errcode_for_socket_access(),
					 errmsg("could not set syslogging pipe to nonblocking mode: %m")));
		}
#endif
	}

	now = time(NULL);

        /*
           * create log directory, ignore error (will be caught on first logfile open)
           */
        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 insure that the logger process has a writable file.
	 */
	filename = logfile_getname(now);

	/*
	 * The file is opened for appending, in case the syslogger 
	 * is restarted right after a rotation.
	 */
	syslogFile = fopen(filename, "a+");

	if (!syslogFile)
	{
	    /* 
		 * if we can't open the syslog file for the syslogger process,
		 * we try to redirect stderr back to have some logging.
		 */
	    ereport(WARNING,
				(errcode_for_file_access(),
				 (errmsg("error opening syslog file %s: %m", filename))));

		if (realStdErr != NULL)
		{
		    if (dup2(fileno(realStdErr), fileno(stderr)) < 0)
			    ereport(FATAL,
						(errcode_for_file_access(),
						 (errmsg("error redirecting stderr to default: %m"))));

			ereport(FATAL,
					(errmsg("logfile output corrupted")));
		}

	}

	pfree(filename);

	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();

			/* Drop our connection to postmaster's shared memory, as well */
			PGSharedMemoryDetach();

			/* do the work */
			SysLoggerMain(0, NULL);
			break;
#endif

		default:
		    /* now we redirect stderr, if not done already */
		    if (realStdErr == NULL)
			{
			    int dh= dup(fileno(stderr));

				if (dh < 0)
				    ereport(FATAL,
							(errcode_for_file_access(),
							 (errmsg("stderr duplication failed: %m"))));

				realStdErr = fdopen(dh, "a");
				if (realStdErr == NULL)
				    ereport(FATAL,
							(errcode_for_file_access(),
							 (errmsg("realstderr reopen failed: %m"))));
#ifdef WIN32
				if (dup2(_open_osfhandle((long)writePipe, _O_APPEND), _fileno(stderr)) < 0)
				    ereport(FATAL,
							(errcode_for_file_access(),
						  (errmsg("stderr pipe redirection failed: %m"))));
#else
				if (dup2(syslogPipe[1], fileno(stdout)) < 0)
				    ereport(FATAL,
							(errcode_for_file_access(),
						  (errmsg("stdout pipe redirection failed: %m"))));
				if (dup2(syslogPipe[1], fileno(stderr)) < 0)
				    ereport(FATAL,
							(errcode_for_file_access(),
						  (errmsg("stderr pipe redirection failed: %m"))));
#endif
			}

			/* postmaster will never write the file; close it */
			fclose((FILE*)syslogFile);
			syslogFile = NULL;
			return (int) sysloggerPid;
	}
	/* we should never reach here */
	return 0;
}


#ifdef EXEC_BACKEND
static pid_t
syslogger_forkexec()
{
	char *av[10];
	int ac = 0, bufc = 0, i;
	char numbuf[4][32];

	av[ac++] = "postgres";
	av[ac++] = "-forklog";
	av[ac++] = NULL;			/* filled in by postmaster_forkexec */

	/* postgres_exec_path is not passed by write_backend_variables */
	av[ac++] = postgres_exec_path;

	/* Pipe file ids (those not passed by write_backend_variables) */
#ifdef WIN32
	snprintf(numbuf[bufc++], 32, "%d", (int)readPipe);
	snprintf(numbuf[bufc++], 32, "%d", (int)writePipe);
	if (syslogFile != 0)
	    snprintf(numbuf[bufc++], 32, "%ld", _get_osfhandle(_fileno((FILE*)syslogFile)));
    else
	    strcpy(numbuf[bufc++], "0");
	if (realStdErr != 0)
	    snprintf(numbuf[bufc++],32, "%ld", _get_osfhandle(_fileno(realStdErr)));
    else
	    strcpy(numbuf[bufc++], "0");
#else
	snprintf(numbuf[bufc++],32, "%d", syslogPipe[0]);
	snprintf(numbuf[bufc++],32, "%d", syslogPipe[1]);
	if (syslogFile != 0)
	    snprintf(numbuf[bufc++], 32, "%d", fileno(syslogFile)));
    else
	    strcpy(numbuf[bufc++], "0");
	if (realStdErr != 0)
	    snprintf(numbuf[bufc++], 32, "%d", fileno(realStdErr)));
    else
	    strcpy(numbuf[bufc++], "0");
#endif
    
	/* Add to the arg list */
	Assert(bufc <= lengthof(pgstatBuf));
	for (i = 0; i < bufc; i++)
		av[ac++] = numbuf[i];

	av[ac] = NULL;
	Assert(ac < lengthof(av));

	return postmaster_forkexec(ac, av);
}
#endif

/* --------------------------------
 *		logfile routines
 * --------------------------------
 */


/*
 * perform rotation
 */
bool
logfile_rotate(void)
{
	char *filename;
	pg_time_t now;
	FILE *fh;

	now = time(NULL);
	filename = logfile_getname(now);
	
	fh = fopen(filename, "a+");
	if (!fh)
	{
	    /*
		 * if opening the new file fails, the caller is responsible
		 * for taking consequences. */

		pfree(filename);
		return false;
	}
        setvbuf(fh, 0, _IONBF, 0);

#ifdef WIN32
        EnterCriticalSection(&sysfileSection);
	fclose((FILE*)syslogFile);
	syslogFile = fh;
        LeaveCriticalSection(&sysfileSection);
#else
	fclose(syslogFile);
	syslogFile = fh;
#endif
	last_rotation_time = now;

	/* official opening of the new logfile */
	ereport(NOTICE,
			(errcode(ERRCODE_WARNING),
			 errmsg("Opened new log file %s", filename)));

	pfree(filename);
	return true;
}



/*
 * creates logfile name using timestamp information
 */

#define TIMESTAMPPATTERN "%Y-%m-%d_%H%M%S"

static char*
logfile_getname(pg_time_t timestamp)
{
	char *filetemplate;
	char *filename;


	if (is_absolute_path(Log_directory))
	{
	  filetemplate = palloc(strlen(Log_directory)
							+ strlen(Log_filename_prefix)
							+ sizeof(TIMESTAMPPATTERN)+10 +2);
		if (filetemplate)
		    sprintf(filetemplate, "%s/%s%s_%05lu.log", 
					Log_directory, Log_filename_prefix, 
					TIMESTAMPPATTERN, (unsigned long)PostmasterPid);
	}
	else
	{
		filetemplate = palloc(strlen(DataDir) + strlen(Log_directory) 
							  + strlen(Log_filename_prefix)
							  + sizeof(TIMESTAMPPATTERN) +10 +3);
		if (filetemplate)
		    sprintf(filetemplate, "%s/%s/%s%s_%05lu.log", 
					DataDir, Log_directory, Log_filename_prefix,
					TIMESTAMPPATTERN, (unsigned long)PostmasterPid);
	}
	filename = palloc(MAXPGPATH);

	if (!filename || !filetemplate)
	    ereport(FATAL,
				(errcode(ERRCODE_OUT_OF_MEMORY),
				 errmsg("Out of memory")));

	pg_strftime(filename, MAXPGPATH, filetemplate, pg_localtime(&timestamp));

	pfree(filetemplate);

	return filename;
}

/* --------------------------------
 *		API helper routines
 * --------------------------------
 */

/*
 * Rotate log file
 */
bool
LogFileRotate(void)
{
    if (!(Log_destination & LOG_DESTINATION_FILE))
	{
	    ereport(NOTICE,
				(errcode(ERRCODE_WARNING),
				 errmsg("no logfile configured; rotation not supported")));
	    return false;
	}

	SendPostmasterSignal(PMSIGNAL_ROTATE_LOGFILE);

	return true;
}

/* --------------------------------
 *		signal handler routines
 * --------------------------------
 */

/* SIGHUP: set flag to reload config file */
static void
sigHupHandler(SIGNAL_ARGS)
{
    got_SIGHUP = true;
}

/* SIGUSR1: set flag to rotate logfile */
static void
rotationHandler(SIGNAL_ARGS)
{
    rotation_requested = true;
}
/*-------------------------------------------------------------------------
 *
 * syslogger.h
 *	  Exports from postmaster/syslogger.c.
 *
 * Copyright (c) 2004, PostgreSQL Global Development Group
 *
 * $PostgreSQL: $
 *
 *-------------------------------------------------------------------------
 */
#ifndef _SYSLOGGER_H
#define _SYSLOGGER_H

#include "pgtime.h"

/* GUC options */
extern int		Log_RotationAge;
extern int		Log_RotationSize;
extern char *   Log_directory;
extern char *   Log_filename_prefix;


extern int SysLogger_Start(void);
extern void SysLoggerMain(int argc, char *argv[]);

extern bool LogFileRotate(void);

#endif   /* _SYSLOGGER_H */
---------------------------(end of broadcast)---------------------------
TIP 1: subscribe and unsubscribe commands go to [EMAIL PROTECTED]

Reply via email to