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;
}