Thread: SysLogger subprocess

SysLogger subprocess

From
Andreas Pflug
Date:
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;
}

Re: SysLogger subprocess

From
Alvaro Herrera
Date:
On Thu, Jul 15, 2004 at 09:00:50PM +0200, Andreas Pflug wrote:

> 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.

No, it's not pgStatPipe[1], it's select(2)'s first argument; max fd in
the sets plus one.  Probably your code works because
pgStatPipe[1] == pgStatPipe[0] + 1.

-- 
Alvaro Herrera (<alvherre[a]dcc.uchile.cl>)
"Por suerte hoy explotó el califont porque si no me habría muerto
de aburrido"  (Papelucho)



Re: SysLogger subprocess

From
Andreas Pflug
Date:
Alvaro Herrera wrote:
> 
> No, it's not pgStatPipe[1], it's select(2)'s first argument; max fd in
> the sets plus one.  Probably your code works because
> pgStatPipe[1] == pgStatPipe[0] + 1.

Ah, I see now, thanks.

Regards,
Andreas