aboutsummaryrefslogtreecommitdiff
path: root/src/backend/postmaster/syslogger.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/postmaster/syslogger.c')
-rw-r--r--src/backend/postmaster/syslogger.c272
1 files changed, 211 insertions, 61 deletions
diff --git a/src/backend/postmaster/syslogger.c b/src/backend/postmaster/syslogger.c
index cd3793497bd..4e75e8d6d6f 100644
--- a/src/backend/postmaster/syslogger.c
+++ b/src/backend/postmaster/syslogger.c
@@ -18,7 +18,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/postmaster/syslogger.c,v 1.36 2007/08/04 01:26:53 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/postmaster/syslogger.c,v 1.37 2007/08/19 01:41:24 adunstan Exp $
*
*-------------------------------------------------------------------------
*/
@@ -64,10 +64,10 @@
/*
- * GUC parameters. Redirect_stderr cannot be changed after postmaster
+ * GUC parameters. Logging_collector cannot be changed after postmaster
* start, but the rest can change at SIGHUP.
*/
-bool Redirect_stderr = false;
+bool Logging_collector = false;
int Log_RotationAge = HOURS_PER_DAY * MINS_PER_HOUR;
int Log_RotationSize = 10 * 1024;
char *Log_directory = NULL;
@@ -87,7 +87,9 @@ extern bool redirection_done;
static pg_time_t next_rotation_time;
static bool pipe_eof_seen = false;
static FILE *syslogFile = NULL;
+static FILE *csvlogFile = NULL;
static char *last_file_name = NULL;
+static char *last_csvfile_name = NULL;
/*
* Buffers for saving partial messages from different backends. We don't expect
@@ -132,12 +134,13 @@ static void syslogger_parseArgs(int argc, char *argv[]);
#endif
static void process_pipe_input(char *logbuffer, int *bytes_in_logbuffer);
static void flush_pipe_input(char *logbuffer, int *bytes_in_logbuffer);
+static void open_csvlogfile(void);
#ifdef WIN32
static unsigned int __stdcall pipeThread(void *arg);
#endif
-static void logfile_rotate(bool time_based_rotation);
-static char *logfile_getname(pg_time_t timestamp);
+static void logfile_rotate(bool time_based_rotation, int size_rotation_for);
+static char *logfile_getname(pg_time_t timestamp, char * suffix);
static void set_next_rotation_time(void);
static void sigHupHandler(SIGNAL_ARGS);
static void sigUsr1Handler(SIGNAL_ARGS);
@@ -281,7 +284,7 @@ SysLoggerMain(int argc, char *argv[])
for (;;)
{
bool time_based_rotation = false;
-
+ int size_rotation_for = 0;
#ifndef WIN32
int bytesRead;
int rc;
@@ -336,11 +339,20 @@ SysLoggerMain(int argc, char *argv[])
{
/* Do a rotation if file is too big */
if (ftell(syslogFile) >= Log_RotationSize * 1024L)
+ {
+ rotation_requested = true;
+ size_rotation_for |= LOG_DESTINATION_STDERR;
+ }
+ if (csvlogFile != NULL && ftell(csvlogFile) >= Log_RotationSize * 1024L)
+ {
rotation_requested = true;
+ size_rotation_for |= LOG_DESTINATION_CSVLOG;
+ }
+
}
if (rotation_requested)
- logfile_rotate(time_based_rotation);
+ logfile_rotate(time_based_rotation, size_rotation_for);
#ifndef WIN32
@@ -405,7 +417,10 @@ SysLoggerMain(int argc, char *argv[])
if (pipe_eof_seen)
{
- ereport(LOG,
+ /* seeing this message on the real stderr is annoying - so we
+ * make it DEBUG1 to suppress in normal use.
+ */
+ ereport(DEBUG1,
(errmsg("logger shutting down")));
/*
@@ -429,7 +444,7 @@ SysLogger_Start(void)
pid_t sysloggerPid;
char *filename;
- if (!Redirect_stderr)
+ if (!Logging_collector)
return 0;
/*
@@ -477,7 +492,7 @@ SysLogger_Start(void)
* The initial logfile is created right in the postmaster, to verify that
* the Log_directory is writable.
*/
- filename = logfile_getname(time(NULL));
+ filename = logfile_getname(time(NULL), NULL);
syslogFile = fopen(filename, "a");
@@ -688,6 +703,7 @@ process_pipe_input(char *logbuffer, int *bytes_in_logbuffer)
{
char *cursor = logbuffer;
int count = *bytes_in_logbuffer;
+ int dest = LOG_DESTINATION_STDERR;
/* While we have enough for a header, process data... */
while (count >= (int) sizeof(PipeProtoHeader))
@@ -700,7 +716,8 @@ process_pipe_input(char *logbuffer, int *bytes_in_logbuffer)
if (p.nuls[0] == '\0' && p.nuls[1] == '\0' &&
p.len > 0 && p.len <= PIPE_MAX_PAYLOAD &&
p.pid != 0 &&
- (p.is_last == 't' || p.is_last == 'f'))
+ (p.is_last == 't' || p.is_last == 'f' ||
+ p.is_last == 'T' || p.is_last == 'F' ))
{
chunklen = PIPE_HEADER_SIZE + p.len;
@@ -708,7 +725,10 @@ process_pipe_input(char *logbuffer, int *bytes_in_logbuffer)
if (count < chunklen)
break;
- if (p.is_last == 'f')
+ dest = (p.is_last == 'T' || p.is_last == 'F' ) ?
+ LOG_DESTINATION_CSVLOG : LOG_DESTINATION_STDERR;
+
+ if (p.is_last == 'f' || p.is_last == 'F')
{
/*
* Save a complete non-final chunk in the per-pid buffer
@@ -751,7 +771,8 @@ process_pipe_input(char *logbuffer, int *bytes_in_logbuffer)
* chances and write out a partial message and hope that
* it's not followed by something from another pid.
*/
- write_syslogger_file(cursor + PIPE_HEADER_SIZE, p.len);
+ write_syslogger_file(cursor + PIPE_HEADER_SIZE, p.len,
+ dest);
}
}
else
@@ -778,14 +799,15 @@ process_pipe_input(char *logbuffer, int *bytes_in_logbuffer)
appendBinaryStringInfo(str,
cursor + PIPE_HEADER_SIZE,
p.len);
- write_syslogger_file(str->data, str->len);
+ write_syslogger_file(str->data, str->len, dest);
saved_chunks[existing_slot].pid = 0;
pfree(str->data);
}
else
{
/* The whole message was one chunk, evidently. */
- write_syslogger_file(cursor + PIPE_HEADER_SIZE, p.len);
+ write_syslogger_file(cursor + PIPE_HEADER_SIZE, p.len,
+ dest);
}
}
@@ -811,7 +833,8 @@ process_pipe_input(char *logbuffer, int *bytes_in_logbuffer)
if (cursor[chunklen] == '\0')
break;
}
- write_syslogger_file(cursor, chunklen);
+ /* fall back on the stderr log as the destination */
+ write_syslogger_file(cursor, chunklen, LOG_DESTINATION_STDERR);
cursor += chunklen;
count -= chunklen;
}
@@ -841,7 +864,7 @@ flush_pipe_input(char *logbuffer, int *bytes_in_logbuffer)
if (saved_chunks[i].pid != 0)
{
str = &(saved_chunks[i].data);
- write_syslogger_file(str->data, str->len);
+ write_syslogger_file(str->data, str->len, LOG_DESTINATION_STDERR);
saved_chunks[i].pid = 0;
pfree(str->data);
}
@@ -851,7 +874,8 @@ flush_pipe_input(char *logbuffer, int *bytes_in_logbuffer)
* remove any protocol headers that may exist in it.
*/
if (*bytes_in_logbuffer > 0)
- write_syslogger_file(logbuffer, *bytes_in_logbuffer);
+ write_syslogger_file(logbuffer, *bytes_in_logbuffer,
+ LOG_DESTINATION_STDERR);
*bytes_in_logbuffer = 0;
}
@@ -869,15 +893,21 @@ flush_pipe_input(char *logbuffer, int *bytes_in_logbuffer)
* even though its stderr does not point at the syslog pipe.
*/
void
-write_syslogger_file(const char *buffer, int count)
+write_syslogger_file(const char *buffer, int count, int destination)
{
int rc;
+ FILE * logfile;
+
+ if (destination == LOG_DESTINATION_CSVLOG && csvlogFile == NULL)
+ open_csvlogfile();
+
+ logfile = destination == LOG_DESTINATION_CSVLOG ? csvlogFile : syslogFile ;
#ifndef WIN32
- rc = fwrite(buffer, 1, count, syslogFile);
+ rc = fwrite(buffer, 1, count, logfile);
#else
EnterCriticalSection(&sysfileSection);
- rc = fwrite(buffer, 1, count, syslogFile);
+ rc = fwrite(buffer, 1, count, logfile);
LeaveCriticalSection(&sysfileSection);
#endif
@@ -939,12 +969,45 @@ pipeThread(void *arg)
#endif /* WIN32 */
/*
+ * open the csv log file - we do this opportunistically, because
+ * we don't know if CSV logging will be wanted.
+ */
+static void
+open_csvlogfile(void)
+{
+ char *filename;
+ FILE *fh;
+
+ filename = logfile_getname(time(NULL),".csv");
+
+ fh = fopen(filename, "a");
+
+ if (!fh)
+ ereport(FATAL,
+ (errcode_for_file_access(),
+ (errmsg("could not create log file \"%s\": %m",
+ filename))));
+
+ setvbuf(fh, NULL, LBF_MODE, 0);
+
+#ifdef WIN32
+ _setmode(_fileno(fh), _O_TEXT); /* use CRLF line endings on Windows */
+#endif
+
+ csvlogFile = fh;
+
+ pfree(filename);
+
+}
+
+/*
* perform logfile rotation
*/
static void
-logfile_rotate(bool time_based_rotation)
+logfile_rotate(bool time_based_rotation, int size_rotation_for)
{
char *filename;
+ char *csvfilename;
FILE *fh;
rotation_requested = false;
@@ -955,9 +1018,17 @@ logfile_rotate(bool time_based_rotation)
* file name when we don't do the rotation immediately.
*/
if (time_based_rotation)
- filename = logfile_getname(next_rotation_time);
+ {
+ filename = logfile_getname(next_rotation_time, NULL);
+ if (csvlogFile != NULL)
+ csvfilename = logfile_getname(next_rotation_time, ".csv");
+ }
else
- filename = logfile_getname(time(NULL));
+ {
+ filename = logfile_getname(time(NULL), NULL);
+ if (csvlogFile != NULL)
+ csvfilename = logfile_getname(time(NULL), ".csv");
+ }
/*
* Decide whether to overwrite or append. We can overwrite if (a)
@@ -970,61 +1041,132 @@ logfile_rotate(bool time_based_rotation)
* postmaster because it ain't gonna work in the EXEC_BACKEND case.) So we
* will always append in that situation, even though truncating would
* usually be safe.
+ *
+ * For consistency, we treat CSV logs the same even though they aren't
+ * opened in the postmaster.
*/
- if (Log_truncate_on_rotation && time_based_rotation &&
- last_file_name != NULL && strcmp(filename, last_file_name) != 0)
- fh = fopen(filename, "w");
- else
- fh = fopen(filename, "a");
-
- if (!fh)
+ if (time_based_rotation || (size_rotation_for & LOG_DESTINATION_STDERR))
{
- int saveerrno = errno;
+ if (Log_truncate_on_rotation && time_based_rotation &&
+ last_file_name != NULL && strcmp(filename, last_file_name) != 0)
+ fh = fopen(filename, "w");
+ else
+ fh = fopen(filename, "a");
- ereport(LOG,
- (errcode_for_file_access(),
- errmsg("could not open new log file \"%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)
+ if (!fh)
{
+ int saveerrno = errno;
+
ereport(LOG,
- (errmsg("disabling automatic rotation (use SIGHUP to reenable)")));
- Log_RotationAge = 0;
- Log_RotationSize = 0;
+ (errcode_for_file_access(),
+ errmsg("could not open new log file \"%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 automatic rotation (use SIGHUP to reenable)")));
+ Log_RotationAge = 0;
+ Log_RotationSize = 0;
+ }
+ pfree(filename);
+ return;
}
- pfree(filename);
- return;
+
+ setvbuf(fh, NULL, LBF_MODE, 0);
+
+#ifdef WIN32
+ _setmode(_fileno(fh), _O_TEXT); /* use CRLF line endings on Windows */
+#endif
+
+ /* On Windows, need to interlock against data-transfer thread */
+#ifdef WIN32
+ EnterCriticalSection(&sysfileSection);
+#endif
+ fclose(syslogFile);
+ syslogFile = fh;
+#ifdef WIN32
+ LeaveCriticalSection(&sysfileSection);
+#endif
+
+ /* instead of pfree'ing filename, remember it for next time */
+ if (last_file_name != NULL)
+ pfree(last_file_name);
+ last_file_name = filename;
+
+
}
- setvbuf(fh, NULL, LBF_MODE, 0);
+ /* same as above, but for csv file. */
+
+ if (csvlogFile != NULL && (
+ time_based_rotation ||
+ (size_rotation_for & LOG_DESTINATION_STDERR)))
+ {
+ if (Log_truncate_on_rotation && time_based_rotation &&
+ last_csvfile_name != NULL &&
+ strcmp(csvfilename, last_csvfile_name) != 0)
+
+ fh = fopen(csvfilename, "w");
+ else
+ fh = fopen(csvfilename, "a");
+
+ if (!fh)
+ {
+ int saveerrno = errno;
+
+ ereport(LOG,
+ (errcode_for_file_access(),
+ errmsg("could not open new log file \"%s\": %m",
+ csvfilename)));
+
+ /*
+ * 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 automatic rotation (use SIGHUP to reenable)")));
+ Log_RotationAge = 0;
+ Log_RotationSize = 0;
+ }
+ pfree(csvfilename);
+ return;
+ }
+
+ setvbuf(fh, NULL, LBF_MODE, 0);
#ifdef WIN32
- _setmode(_fileno(fh), _O_TEXT); /* use CRLF line endings on Windows */
+ _setmode(_fileno(fh), _O_TEXT); /* use CRLF line endings on Windows */
#endif
- /* On Windows, need to interlock against data-transfer thread */
+ /* On Windows, need to interlock against data-transfer thread */
#ifdef WIN32
- EnterCriticalSection(&sysfileSection);
+ EnterCriticalSection(&sysfileSection);
#endif
- fclose(syslogFile);
- syslogFile = fh;
+ fclose(csvlogFile);
+ syslogFile = fh;
#ifdef WIN32
- LeaveCriticalSection(&sysfileSection);
+ LeaveCriticalSection(&sysfileSection);
#endif
+ /* instead of pfree'ing filename, remember it for next time */
+ if (last_csvfile_name != NULL)
+ pfree(last_csvfile_name);
+ last_csvfile_name = filename;
+ }
+
set_next_rotation_time();
- /* instead of pfree'ing filename, remember it for next time */
- if (last_file_name != NULL)
- pfree(last_file_name);
- last_file_name = filename;
}
@@ -1034,7 +1176,7 @@ logfile_rotate(bool time_based_rotation)
* Result is palloc'd.
*/
static char *
-logfile_getname(pg_time_t timestamp)
+logfile_getname(pg_time_t timestamp, char * suffix)
{
char *filename;
int len;
@@ -1058,6 +1200,14 @@ logfile_getname(pg_time_t timestamp)
Log_filename, (unsigned long) timestamp);
}
+ if (suffix != NULL)
+ {
+ len = strlen(filename);
+ if (len > 4 && (strcmp(filename+(len-4),".log") == 0))
+ len -= 4;
+ strncpy(filename + len, suffix, MAXPGPATH - len);
+ }
+
return filename;
}