Here's the core of the logger subprocess.

- no rotation code so far, all syslogFile handling is for testing only
- send_message_to_serverlog needs some careful handling of stderr, in case pipe writing fails or if after a log process restart redirecting stderr fails. In these cases, the original stderr should be used.


While looking at pgstat.c to see how to peek for pipe data, I found
        readpipe=pgStatPipe[0];
        select(readPipe+1, ..);

which is probably usually the same as select(pgStatPipe[1], ..) This fd arithmetics seem a bit dubious to me.

Regards,
Andreas
/*-------------------------------------------------------------------------
 *
 * syslogger.c
 *
 *
 *
 * Portions 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/ipc.h"
#include "storage/pg_shmem.h"
#include "postmaster/syslogger.h"
#include "utils/guc.h"



/*
 * GUC parameters
 */
int			SyslogRotationDelay = 24*60*60;
int			SyslogRotationSize  = 10*1024*1024;

/*
 * 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;

static time_t	last_rotation_time;


static void sigHupHandler(SIGNAL_ARGS);
static void rotationHandler(SIGNAL_ARGS);
static void SysLoggerMain(void);

FILE *syslogFile=0;
int syslogPipe[2] = {0, 0};

int realStdErr = 0;

/*
 * Main entry point for bgwriter process
 *
 * This is invoked from BootstrapMain, which has already created the basic
 * execution environment, but not enabled signals yet.
 */
void
SysLoggerMain(void)
{
	/*
	 * Properly accept or ignore signals the postmaster might send us
	 *
	 * Note: we deliberately ignore SIGTERM, because during a standard Unix
	 * system shutdown cycle, init will SIGTERM all processes at once.  We
	 * want to wait for the backends to exit, whereupon the postmaster will
	 * tell us it's okay to shut down (via SIGQUIT).
	 *
	 */
	pqsignal(SIGHUP, sigHupHandler);	/* set flag to read config file */
	pqsignal(SIGINT,  rotationHandler);	/* request log rotation */
	pqsignal(SIGTERM, SIG_IGN);			/* ignore SIGTERM */
	pqsignal(SIGQUIT, SIG_IGN);         /* we do not exit on any signal, but wait for the postmaster to end */
	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);

	/* !!!!!!!! work to do here */
	syslogFile=fopen("/usr/data/pgsql-7.4/pgsql.log", "a+");

	/* 
	 * if we restarted, our stderr is redirected. 
	 * Direct it back to system stderr.
	 */
	if (realStdErr != 0)
	{
	    if (dup2(realStdErr, fileno(stderr)) < 0)
		{
			/*
			 * Now we have a real problem: we can't redirect to stderr,
			 * and can't ereport it correctly.
			 */
			ereport(PANIC,
					(errcode_for_file_access(),
					 (errmsg("stderr restoration failed: %m"))));
			exit(1);
		}

		realStdErr=0;
	}

	last_rotation_time = time(NULL);

	/*
     * main worker loop
     * */

	for (;;)
	{
		time_t		now;
		int			elapsed_secs;
		char        logbuffer[1024];
		char        bytesRead;
		fd_set		rfds;
		struct timeval timeout;
		int         rc;

		if (got_SIGHUP)
		{
			got_SIGHUP = false;
			ProcessConfigFile(PGC_SIGHUP);
		}

		if (!rotation_requested && SyslogRotationDelay > 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 >= SyslogRotationDelay)
			    rotation_requested = true;
		}

		if (!rotation_requested && SyslogRotationSize > 0)
		{
		    if (ftell(syslogFile) >= SyslogRotationSize)
			    rotation_requested = true;
		}


		if (rotation_requested)
		{
		    rotation_requested = false;
		}
		
		FD_ZERO(&rfds);
		FD_SET(syslogPipe[0], &rfds);
		timeout.tv_sec=1;
		timeout.tv_usec=0;

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

		if (rc > 0 && FD_ISSET(syslogPipe[0], &rfds))
		{
		    bytesRead = piperead(syslogPipe[0],
								 logbuffer, sizeof(logbuffer));

			if (bytesRead > 0)
			{
				if (fwrite(logbuffer, 1, bytesRead, syslogFile) < 1)
				    ereport(FATAL,
							(errcode_for_file_access(),
							 errmsg("fwrite to logfile failed in system logger: %m")));

				fflush(syslogFile);

				if (Log_destination & LOG_DESTINATION_STDERR)
				{
				    fwrite(logbuffer, 1, bytesRead, stderr);
					fflush(stderr);
				}
			}
			else if (bytesRead < 0 && errno != EINTR)
			{
				ereport(FATAL,
						(errcode_for_socket_access(),
						 errmsg("could not read from system logger pipe: %m")));
			}
			continue;
		}
		
		if (rc < 0 && errno != EINTR)
		{
			ereport(FATAL,
					(errcode_for_socket_access(),
					 errmsg("select() failed in system logger: %m")));
			exit(1);
		}

		/*
		 * 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))
		{
			if (syslogFile)
			    fclose(syslogFile);
			exit(1);
		}

	}
}


int
SysLogger_Start(void)
{
    pid_t sysloggerPid;

    if (!syslogPipe[0])
	{
	    if (pgpipe(syslogPipe) < 0)
		    ereport(FATAL,
					(errcode_for_file_access(),
					 (errmsg("pipe for syslogging not created: %m"))));
	}
	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();

			//			closesocket(syslogPipe[1]);

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

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

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

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


			}

			return (int) sysloggerPid;
	}

	/* shouldn't get here */
	return 0;
}


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

/* SIGHUP: set flag to re-read config file at next convenient time */
static void
sigHupHandler(SIGNAL_ARGS)
{
	got_SIGHUP = true;
}

/* SIGINT: set flag to rotate logfile */
static void
rotationHandler(SIGNAL_ARGS)
{
	rotation_requested = true;
}
---------------------------(end of broadcast)---------------------------
TIP 7: don't forget to increase your free space map settings

Reply via email to