diff --git a/doc/src/sgml/maintenance.sgml b/doc/src/sgml/maintenance.sgml
index 91ead3dc168..7d1dafad318 100644
--- a/doc/src/sgml/maintenance.sgml
+++ b/doc/src/sgml/maintenance.sgml
@@ -1,5 +1,5 @@
@@ -445,22 +445,52 @@ VACUUM
- If you simply direct the stderr> of the postmaster into a
- file, the only way to truncate the log file is to stop and restart
+ If you simply direct the stderr> of the
+ postmaster into a
+ file, you will have log output, but
+ the only way to truncate the log file is to stop and restart
the postmaster. This may be OK if you are using
PostgreSQL in a development environment,
but few production servers would find this behavior acceptable.
- The simplest production-grade approach to managing log output is to
+ A better approach is to send the postmaster>'s
+ 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 redirect_stderr> to
+ true> in postgresql.conf>. The control
+ parameters for this program are described in .
+
+
+
+ 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 rotatelogs
+ tool included in the Apache distribution
+ can be used with PostgreSQL. To do this,
+ just pipe the postmaster>'s
+ stderr> output to the desired program.
+ If you start the server with
+ pg_ctl>, then stderr>
+ is already redirected to stdout>, so you just need a
+ pipe command:
+
+
+pg_ctl start | rotatelogs /var/log/pgsql_log 86400
+
+
+
+
+ Another production-grade approach to managing log output is to
send it all to syslog> and let
syslog> deal with file rotation. To do this, set the
- configuration parameter log_destination> to 'syslog' (to log to
- syslog> only) in postgresql.conf>. Then
- you can send a SIGHUP signal to the
- syslog> daemon whenever you want to force it to
- start writing a new log file. If you want to automate log
+ configuration parameter log_destination> to syslog>
+ (to log to syslog> only) in
+ postgresql.conf>. Then you can send a SIGHUP
+ signal to the syslog> daemon whenever you want to force it
+ to start writing a new log file. If you want to automate log
rotation, the logrotate program can be
configured to work with log files from
syslog.
@@ -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 linux>,
syslog> will sync each message to disk, yielding poor
- performance. Use a -> at the start of the file name
- in the syslog> config file to disable this behavior.
+ performance. (You can use a -> at the start of the file name
+ in the syslog> config file to disable this behavior.)
- You may find it more useful to pipe the
- stderr> of the postmaster> to some type of
- log rotation program. If you start the server with
- pg_ctl>, then the stderr> of the postmaster
- is already redirected to stdout>, so you just need a
- pipe command:
-
-
-pg_ctl start | rotatelogs /var/log/pgsql_log 86400
-
-
- The PostgreSQL> distribution doesn't include a
- suitable log rotation program, but there are many available on the
- Internet. For example, the rotatelogs
- tool included in the Apache distribution
- can be used with PostgreSQL.
+ 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.
diff --git a/doc/src/sgml/runtime.sgml b/doc/src/sgml/runtime.sgml
index 95a8c23c822..9f569712b08 100644
--- a/doc/src/sgml/runtime.sgml
+++ b/doc/src/sgml/runtime.sgml
@@ -1,5 +1,5 @@
@@ -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 stderr
only.
+ This option can only be set at server start or in the
+ postgresql.conf configuration file.
+
+ redirect_stderr (boolean)
+
+
+ This option allows messages sent to stderr> to be
+ captured and redirected into log files.
+ This option, in combination with logging to stderr>,
+ is often more useful than
+ logging to syslog>, since some types of messages
+ may not appear in syslog> output (a common example
+ is dynamic-linker failure messages).
+ This option can only be set at server start.
+
+
+
+
+
+ log_directory (string)
+
+
+ When 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
+ postgresql.conf configuration file.
+
+
+
+
+
+ log_filename_prefix (string)
+
+
+ When 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
+ postgresql.conf configuration file.
+
+
+
+
+
+ log_rotation_age (integer)
+
+
+ When 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
+ postgresql.conf configuration file.
+
+
+
+
+
+ log_rotation_size (integer)
+
+
+ When 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
+ postgresql.conf configuration file.
+
+
+
+
syslog_facility (string)
- If logging to syslog> is enabled, this option
+ When logging to syslog> is enabled, this option
determines the syslog
facility
to be used. You may choose
from LOCAL0>, LOCAL1>,
@@ -1826,7 +1902,7 @@ SET ENABLE_SEQSCAN TO OFF;
syslog_ident (string)
- If logging to syslog> is enabled, this option
+ When logging to syslog> is enabled, this option
determines the program name used to identify
PostgreSQL messages in
syslog logs. The default is
diff --git a/src/backend/postmaster/Makefile b/src/backend/postmaster/Makefile
index abbac1674f1..fdb12febb4a 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 960ece75831..1d398ba5962 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 dbd4f15cefd..7638dd28a11 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 6c9e87f5f3a..870ad318a83 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 00000000000..f5bffdb8a2f
--- /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
+ *
+ * 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
+#include
+#include
+#include
+#include
+
+#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(×tamp));
+
+ 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 340cca03cac..9723cf76f59 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 22df3effc32..a827653bec4 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -10,7 +10,7 @@
* Written by Peter Eisentraut .
*
* 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,6 +802,26 @@ static struct config_bool ConfigureNamesBool[] =
&default_with_oids,
true, NULL, NULL
},
+ {
+ {"redirect_stderr", PGC_POSTMASTER, LOGGING_WHERE,
+ gettext_noop("Start a subprocess to capture stderr output into log files"),
+ NULL
+ },
+ &Redirect_stderr,
+ false, NULL, NULL
+ },
+
+#ifdef WAL_DEBUG
+ {
+ {"wal_debug", PGC_SUSET, DEVELOPER_OPTIONS,
+ gettext_noop("Emit WAL-related debugging output."),
+ NULL,
+ GUC_NOT_IN_SAMPLE
+ },
+ &XLOG_DEBUG,
+ false, NULL, NULL
+ },
+#endif
{
{"integer_datetimes", PGC_INTERNAL, COMPILE_OPTIONS,
@@ -816,18 +837,6 @@ static struct config_bool ConfigureNamesBool[] =
#endif
},
-#ifdef WAL_DEBUG
- {
- {"wal_debug", PGC_SUSET, DEVELOPER_OPTIONS,
- gettext_noop("Emit WAL-related debugging output."),
- NULL,
- GUC_NOT_IN_SAMPLE
- },
- &XLOG_DEBUG,
- 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 9dc1ec8d837..633bb5a3229 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 75242d156d1..9afc228efd0 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 00000000000..a0f775c9a21
--- /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 4a2d26ddb9d..ac27b796249 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