diff options
author | Andrew Dunstan <andrew@dunslane.net> | 2007-06-14 01:48:51 +0000 |
---|---|---|
committer | Andrew Dunstan <andrew@dunslane.net> | 2007-06-14 01:48:51 +0000 |
commit | bd2cb9aaa55d2c6760e2722557a8a87b0bd40945 (patch) | |
tree | 2301545dd731540c607b94277e4e52377f82f821 /src/backend/utils | |
parent | 320f8205850a2e42b0c6a1e8a7649a7df72b547d (diff) | |
download | postgresql-bd2cb9aaa55d2c6760e2722557a8a87b0bd40945.tar.gz postgresql-bd2cb9aaa55d2c6760e2722557a8a87b0bd40945.zip |
Implement a chunking protocol for writes to the syslogger pipe, with messages
reassembled in the syslogger before writing to the log file. This prevents
partial messages from being written, which mucks up log rotation, and
messages from different backends being interleaved, which causes garbled
logs. Backport as far as 8.0, where the syslogger was introduced.
Tom Lane and Andrew Dunstan
Diffstat (limited to 'src/backend/utils')
-rw-r--r-- | src/backend/utils/error/elog.c | 43 |
1 files changed, 41 insertions, 2 deletions
diff --git a/src/backend/utils/error/elog.c b/src/backend/utils/error/elog.c index c6952ef20e8..c762475d65a 100644 --- a/src/backend/utils/error/elog.c +++ b/src/backend/utils/error/elog.c @@ -42,7 +42,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/error/elog.c,v 1.186 2007/06/07 21:45:59 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/utils/error/elog.c,v 1.187 2007/06/14 01:48:51 adunstan Exp $ * *------------------------------------------------------------------------- */ @@ -124,6 +124,7 @@ static const char *useful_strerror(int errnum); static const char *error_severity(int elevel); static void append_with_tabs(StringInfo buf, const char *str); static bool is_log_level_output(int elevel, int log_min_level); +static void write_pipe_chunks(int fd, char *data, int len); /* @@ -1783,7 +1784,10 @@ send_message_to_server_log(ErrorData *edata) write_eventlog(edata->elevel, buf.data); else #endif - fprintf(stderr, "%s", buf.data); + if (Redirect_stderr) + write_pipe_chunks(fileno(stderr), buf.data, buf.len); + else + write(fileno(stderr), buf.data, buf.len); } /* If in the syslogger process, try to write messages direct to file */ @@ -1793,6 +1797,37 @@ send_message_to_server_log(ErrorData *edata) pfree(buf.data); } +/* + * Send data to the syslogger using the chunked protocol + */ +static void +write_pipe_chunks(int fd, char *data, int len) +{ + PipeProtoChunk p; + + Assert(len > 0); + + p.proto.nuls[0] = p.proto.nuls[1] = '\0'; + p.proto.pid = MyProcPid; + + /* write all but the last chunk */ + while (len > PIPE_MAX_PAYLOAD) + { + p.proto.is_last = 'f'; + p.proto.len = PIPE_MAX_PAYLOAD; + memcpy(p.proto.data, data, PIPE_MAX_PAYLOAD); + write(fd, &p, PIPE_HEADER_SIZE + PIPE_MAX_PAYLOAD); + data += PIPE_MAX_PAYLOAD; + len -= PIPE_MAX_PAYLOAD; + } + + /* write the last chunk */ + p.proto.is_last = 't'; + p.proto.len = len; + memcpy(p.proto.data, data, len); + write(fd, &p, PIPE_HEADER_SIZE + len); +} + /* * Write error report to client @@ -2115,6 +2150,7 @@ write_stderr(const char *fmt,...) #ifndef WIN32 /* On Unix, we just fprintf to stderr */ vfprintf(stderr, fmt, ap); + fflush(stderr); #else /* @@ -2130,8 +2166,11 @@ write_stderr(const char *fmt,...) write_eventlog(ERROR, errbuf); } else + { /* Not running as service, write to stderr */ vfprintf(stderr, fmt, ap); + fflush(stderr); + } #endif va_end(ap); } |