diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c
index 95180b2ef5..7c4eb5743f 100644
--- a/src/backend/postmaster/postmaster.c
+++ b/src/backend/postmaster/postmaster.c
@@ -1764,7 +1764,7 @@ ServerLoop(void)
 		}
 
 		/* If we have lost the log collector, try to start a new one */
-		if (SysLoggerPID == 0 && Logging_collector)
+		if (SysLoggerPID == 0)
 			SysLoggerPID = SysLogger_Start();
 
 		/*
diff --git a/src/backend/postmaster/syslogger.c b/src/backend/postmaster/syslogger.c
index 3255b42c7d..15fc606d24 100644
--- a/src/backend/postmaster/syslogger.c
+++ b/src/backend/postmaster/syslogger.c
@@ -57,10 +57,8 @@
 
 
 /*
- * GUC parameters.  Logging_collector cannot be changed after postmaster
- * start, but the rest can change at SIGHUP.
+ * GUC parameters. Can change at SIGHUP.
  */
-bool		Logging_collector = false;
 int			Log_RotationAge = HOURS_PER_DAY * MINS_PER_HOUR;
 int			Log_RotationSize = 10 * 1024;
 char	   *Log_directory = NULL;
@@ -182,6 +180,10 @@ SysLoggerMain(int argc, char *argv[])
 	 * assumes that all interesting messages generated in the syslogger will
 	 * come through elog.c and will be sent to write_syslogger_file.
 	 */
+	/*
+	 * XXX: this does not work when we want to use stderr in the syslogger.
+	 * needs fixing!
+	 */
 	if (redirection_done)
 	{
 		int			fd = open(DEVNULL, O_WRONLY, 0);
@@ -370,10 +372,11 @@ SysLoggerMain(int argc, char *argv[])
 		if (!rotation_requested && Log_RotationSize > 0 && !rotation_disabled)
 		{
 			/* Do a rotation if file is too big */
-			if (ftell(syslogFile) >= Log_RotationSize * 1024L)
+			if (syslogFile != NULL &&
+				ftell(syslogFile) >= Log_RotationSize * 1024L)
 			{
 				rotation_requested = true;
-				size_rotation_for |= LOG_DESTINATION_STDERR;
+				size_rotation_for |= LOG_DESTINATION_FILE;
 			}
 			if (csvlogFile != NULL &&
 				ftell(csvlogFile) >= Log_RotationSize * 1024L)
@@ -390,7 +393,7 @@ SysLoggerMain(int argc, char *argv[])
 			 * was sent by pg_rotate_logfile.
 			 */
 			if (!time_based_rotation && size_rotation_for == 0)
-				size_rotation_for = LOG_DESTINATION_STDERR | LOG_DESTINATION_CSVLOG;
+				size_rotation_for = LOG_DESTINATION_FILE | LOG_DESTINATION_CSVLOG;
 			logfile_rotate(time_based_rotation, size_rotation_for);
 		}
 
@@ -522,9 +525,6 @@ SysLogger_Start(void)
 	pid_t		sysloggerPid;
 	char	   *filename;
 
-	if (!Logging_collector)
-		return 0;
-
 	/*
 	 * If first time through, create the pipe which will receive stderr
 	 * output.
@@ -581,7 +581,10 @@ SysLogger_Start(void)
 	first_syslogger_file_time = time(NULL);
 	filename = logfile_getname(first_syslogger_file_time, NULL);
 
-	syslogFile = logfile_open(filename, "a", false);
+	if (Log_destination & LOG_DESTINATION_FILE)
+		syslogFile = logfile_open(filename, "a", false);
+	else
+		syslogFile = NULL;
 
 	pfree(filename);
 
@@ -675,7 +678,8 @@ SysLogger_Start(void)
 			}
 
 			/* postmaster will never write the file; close it */
-			fclose(syslogFile);
+			if (syslogFile != NULL)
+				fclose(syslogFile);
 			syslogFile = NULL;
 			return (int) sysloggerPid;
 	}
@@ -794,7 +798,7 @@ process_pipe_input(char *logbuffer, int *bytes_in_logbuffer)
 {
 	char	   *cursor = logbuffer;
 	int			count = *bytes_in_logbuffer;
-	int			dest = LOG_DESTINATION_STDERR;
+	bool		dest_csv = false;
 
 	/* While we have enough for a header, process data... */
 	while (count >= (int) (offsetof(PipeProtoHeader, data) + 1))
@@ -822,8 +826,7 @@ process_pipe_input(char *logbuffer, int *bytes_in_logbuffer)
 			if (count < chunklen)
 				break;
 
-			dest = (p.is_last == 'T' || p.is_last == 'F') ?
-				LOG_DESTINATION_CSVLOG : LOG_DESTINATION_STDERR;
+			dest_csv = (p.is_last == 'T' || p.is_last == 'F');
 
 			/* Locate any existing buffer for this source pid */
 			buffer_list = buffer_lists[p.pid % NBUFFER_LISTS];
@@ -886,7 +889,7 @@ process_pipe_input(char *logbuffer, int *bytes_in_logbuffer)
 					appendBinaryStringInfo(str,
 										   cursor + PIPE_HEADER_SIZE,
 										   p.len);
-					write_syslogger_file(str->data, str->len, dest);
+					write_syslogger_file(str->data, str->len, dest_csv);
 					/* Mark the buffer unused, and reclaim string storage */
 					existing_slot->pid = 0;
 					pfree(str->data);
@@ -895,7 +898,7 @@ process_pipe_input(char *logbuffer, int *bytes_in_logbuffer)
 				{
 					/* The whole message was one chunk, evidently. */
 					write_syslogger_file(cursor + PIPE_HEADER_SIZE, p.len,
-										 dest);
+										 dest_csv);
 				}
 			}
 
@@ -922,7 +925,7 @@ process_pipe_input(char *logbuffer, int *bytes_in_logbuffer)
 					break;
 			}
 			/* fall back on the stderr log as the destination */
-			write_syslogger_file(cursor, chunklen, LOG_DESTINATION_STDERR);
+			write_syslogger_file(cursor, chunklen, false);
 			cursor += chunklen;
 			count -= chunklen;
 		}
@@ -960,7 +963,7 @@ flush_pipe_input(char *logbuffer, int *bytes_in_logbuffer)
 				StringInfo	str = &(buf->data);
 
 				write_syslogger_file(str->data, str->len,
-									 LOG_DESTINATION_STDERR);
+									 LOG_DESTINATION_FILE);
 				/* Mark the buffer unused, and reclaim string storage */
 				buf->pid = 0;
 				pfree(str->data);
@@ -974,7 +977,7 @@ flush_pipe_input(char *logbuffer, int *bytes_in_logbuffer)
 	 */
 	if (*bytes_in_logbuffer > 0)
 		write_syslogger_file(logbuffer, *bytes_in_logbuffer,
-							 LOG_DESTINATION_STDERR);
+							 LOG_DESTINATION_FILE);
 	*bytes_in_logbuffer = 0;
 }
 
@@ -985,23 +988,39 @@ flush_pipe_input(char *logbuffer, int *bytes_in_logbuffer)
  */
 
 /*
- * Write text to the currently open logfile
+ * Write text to the currently open logfile and/or stderr.
  *
  * 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 destination)
+write_syslogger_file(const char *buffer, int count, bool dest_csv)
 {
-	int			rc;
-	FILE	   *logfile;
-
-	if (destination == LOG_DESTINATION_CSVLOG && csvlogFile == NULL)
-		open_csvlogfile();
+	int			rc = 0;
 
-	logfile = destination == LOG_DESTINATION_CSVLOG ? csvlogFile : syslogFile;
-	rc = fwrite(buffer, 1, count, logfile);
+	if (dest_csv)
+	{
+		if (csvlogFile == NULL)
+			open_csvlogfile();
+		rc = fwrite(buffer, 1, count, csvlogFile);
+	}
+	else
+	{
+		/* non-csv can go to file, stderr or both */
+		if (Log_destination & LOG_DESTINATION_STDERR)
+		{
+			rc = fwrite(buffer, 1, count, stderr);
+			/*
+			 * if we fail to write to stderr, we're not likely to be able
+			 * to write the error message about it either, so just
+			 * ignore and let the result be overwritten if we log to both
+			 * file and stderr.
+			 */
+		}
+		if (Log_destination & LOG_DESTINATION_FILE)
+			rc = fwrite(buffer, 1, count, syslogFile);
+	}
 
 	/* can't use ereport here because of possible recursion */
 	if (rc != count)
@@ -1064,7 +1083,7 @@ pipeThread(void *arg)
 		 */
 		if (Log_RotationSize > 0)
 		{
-			if (ftell(syslogFile) >= Log_RotationSize * 1024L ||
+			if ((syslogFile != NULL && ftell(syslogFile) >= Log_RotationSize * 1024L ||
 				(csvlogFile != NULL && ftell(csvlogFile) >= Log_RotationSize * 1024L))
 				SetLatch(MyLatch);
 		}
@@ -1189,7 +1208,7 @@ logfile_rotate(bool time_based_rotation, int size_rotation_for)
 	 *
 	 * Note: last_file_name should never be NULL here, but if it is, append.
 	 */
-	if (time_based_rotation || (size_rotation_for & LOG_DESTINATION_STDERR))
+	if (time_based_rotation || (size_rotation_for & LOG_DESTINATION_FILE))
 	{
 		if (Log_truncate_on_rotation && time_based_rotation &&
 			last_file_name != NULL &&
@@ -1220,7 +1239,8 @@ logfile_rotate(bool time_based_rotation, int size_rotation_for)
 			return;
 		}
 
-		fclose(syslogFile);
+		if (syslogFile != NULL)
+			fclose(syslogFile);
 		syslogFile = fh;
 
 		/* instead of pfree'ing filename, remember it for next time */
@@ -1362,7 +1382,7 @@ update_metainfo_datafile(void)
 {
 	FILE	   *fh;
 
-	if (!(Log_destination & LOG_DESTINATION_STDERR) &&
+	if (!(Log_destination & LOG_DESTINATION_FILE) &&
 		!(Log_destination & LOG_DESTINATION_CSVLOG))
 	{
 		if (unlink(LOG_METAINFO_DATAFILE) < 0 && errno != ENOENT)
@@ -1382,7 +1402,7 @@ update_metainfo_datafile(void)
 		return;
 	}
 
-	if (last_file_name && (Log_destination & LOG_DESTINATION_STDERR))
+	if (last_file_name && (Log_destination & LOG_DESTINATION_FILE))
 	{
 		if (fprintf(fh, "stderr %s\n", last_file_name) < 0)
 		{
diff --git a/src/backend/utils/adt/misc.c b/src/backend/utils/adt/misc.c
index 62341b84d1..5e7df05e01 100644
--- a/src/backend/utils/adt/misc.c
+++ b/src/backend/utils/adt/misc.c
@@ -349,13 +349,6 @@ pg_reload_conf(PG_FUNCTION_ARGS)
 Datum
 pg_rotate_logfile(PG_FUNCTION_ARGS)
 {
-	if (!Logging_collector)
-	{
-		ereport(WARNING,
-				(errmsg("rotation not possible because log collection not active")));
-		PG_RETURN_BOOL(false);
-	}
-
 	SendPostmasterSignal(PMSIGNAL_ROTATE_LOGFILE);
 	PG_RETURN_BOOL(true);
 }
diff --git a/src/backend/utils/error/elog.c b/src/backend/utils/error/elog.c
index 918db0a8f2..2c23914b82 100644
--- a/src/backend/utils/error/elog.c
+++ b/src/backend/utils/error/elog.c
@@ -175,7 +175,7 @@ static const char *process_log_prefix_padding(const char *p, int *padding);
 static void log_line_prefix(StringInfo buf, ErrorData *edata);
 static void write_csvlog(ErrorData *edata);
 static void send_message_to_server_log(ErrorData *edata);
-static void write_pipe_chunks(char *data, int len, int dest);
+static void write_pipe_chunks(char *data, int len, bool csv);
 static void send_message_to_frontend(ErrorData *edata);
 static char *expand_fmt_string(const char *fmt, ErrorData *edata);
 static const char *useful_strerror(int errnum);
@@ -2831,7 +2831,7 @@ write_csvlog(ErrorData *edata)
 	if (am_syslogger)
 		write_syslogger_file(buf.data, buf.len, LOG_DESTINATION_CSVLOG);
 	else
-		write_pipe_chunks(buf.data, buf.len, LOG_DESTINATION_CSVLOG);
+		write_pipe_chunks(buf.data, buf.len, true);
 
 	pfree(buf.data);
 }
@@ -3008,7 +3008,7 @@ send_message_to_server_log(ErrorData *edata)
 #endif							/* WIN32 */
 
 	/* Write to stderr, if enabled */
-	if ((Log_destination & LOG_DESTINATION_STDERR) || whereToSendOutput == DestDebug)
+	if ((Log_destination & (LOG_DESTINATION_STDERR | LOG_DESTINATION_FILE)) || whereToSendOutput == DestDebug)
 	{
 		/*
 		 * Use the chunking protocol if we know the syslogger should be
@@ -3016,7 +3016,7 @@ send_message_to_server_log(ErrorData *edata)
 		 * Otherwise, just do a vanilla write to stderr.
 		 */
 		if (redirection_done && !am_syslogger)
-			write_pipe_chunks(buf.data, buf.len, LOG_DESTINATION_STDERR);
+			write_pipe_chunks(buf.data, buf.len, false);
 #ifdef WIN32
 
 		/*
@@ -3088,7 +3088,7 @@ send_message_to_server_log(ErrorData *edata)
  * rc to void to shut up the compiler.
  */
 static void
-write_pipe_chunks(char *data, int len, int dest)
+write_pipe_chunks(char *data, int len, bool csv)
 {
 	PipeProtoChunk p;
 	int			fd = fileno(stderr);
@@ -3102,7 +3102,7 @@ write_pipe_chunks(char *data, int len, int dest)
 	/* write all but the last chunk */
 	while (len > PIPE_MAX_PAYLOAD)
 	{
-		p.proto.is_last = (dest == LOG_DESTINATION_CSVLOG ? 'F' : 'f');
+		p.proto.is_last = (csv ? 'F' : 'f');
 		p.proto.len = PIPE_MAX_PAYLOAD;
 		memcpy(p.proto.data, data, PIPE_MAX_PAYLOAD);
 		rc = write(fd, &p, PIPE_HEADER_SIZE + PIPE_MAX_PAYLOAD);
@@ -3112,7 +3112,7 @@ write_pipe_chunks(char *data, int len, int dest)
 	}
 
 	/* write the last chunk */
-	p.proto.is_last = (dest == LOG_DESTINATION_CSVLOG ? 'T' : 't');
+	p.proto.is_last = (csv ? 'T' : 't');
 	p.proto.len = len;
 	memcpy(p.proto.data, data, len);
 	rc = write(fd, &p, PIPE_HEADER_SIZE + len);
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 246fea8693..26ae6bf296 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -1436,15 +1436,6 @@ static struct config_bool ConfigureNamesBool[] =
 		NULL, NULL, NULL
 	},
 	{
-		{"logging_collector", PGC_POSTMASTER, LOGGING_WHERE,
-			gettext_noop("Start a subprocess to capture stderr output and/or csvlogs into log files."),
-			NULL
-		},
-		&Logging_collector,
-		false,
-		NULL, NULL, NULL
-	},
-	{
 		{"log_truncate_on_rotation", PGC_SIGHUP, LOGGING_WHERE,
 			gettext_noop("Truncate existing log files of same name during log rotation."),
 			NULL
@@ -3325,7 +3316,7 @@ static struct config_string ConfigureNamesString[] =
 		{"log_destination", PGC_SIGHUP, LOGGING_WHERE,
 			gettext_noop("Sets the destination for server log output."),
 			gettext_noop("Valid values are combinations of \"stderr\", "
-						 "\"syslog\", \"csvlog\", and \"eventlog\", "
+						 "\"file\", \"syslog\", \"csvlog\", and \"eventlog\", "
 						 "depending on the platform."),
 			GUC_LIST_INPUT
 		},
@@ -10077,6 +10068,8 @@ check_log_destination(char **newval, void **extra, GucSource source)
 
 		if (pg_strcasecmp(tok, "stderr") == 0)
 			newlogdest |= LOG_DESTINATION_STDERR;
+		else if (pg_strcasecmp(tok, "file") == 0)
+			newlogdest |= LOG_DESTINATION_FILE;
 		else if (pg_strcasecmp(tok, "csvlog") == 0)
 			newlogdest |= LOG_DESTINATION_CSVLOG;
 #ifdef HAVE_SYSLOG
diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample
index df5d2f3f22..58f899c097 100644
--- a/src/backend/utils/misc/postgresql.conf.sample
+++ b/src/backend/utils/misc/postgresql.conf.sample
@@ -342,17 +342,10 @@
 # - Where to Log -
 
 #log_destination = 'stderr'		# Valid values are combinations of
-					# stderr, csvlog, syslog, and eventlog,
-					# depending on platform.  csvlog
-					# requires logging_collector to be on.
-
-# This is used when logging to stderr:
-#logging_collector = off		# Enable capturing of stderr and csvlog
-					# into log files. Required to be on for
-					# csvlogs.
-					# (change requires restart)
+					# stderr, file, csvlog, syslog, and
+					# eventlog, depending on platform. 
 
-# These are only used if logging_collector is on:
+# These are only used if log_destination is file or csvlog
 #log_directory = 'log'			# directory where log files are written,
 					# can be absolute or relative to PGDATA
 #log_filename = 'postgresql-%Y-%m-%d_%H%M%S.log'	# log file name pattern,
diff --git a/src/include/postmaster/syslogger.h b/src/include/postmaster/syslogger.h
index f4248ef5d4..82eafc0241 100644
--- a/src/include/postmaster/syslogger.h
+++ b/src/include/postmaster/syslogger.h
@@ -62,7 +62,6 @@ typedef union
 
 
 /* GUC options */
-extern bool Logging_collector;
 extern int	Log_RotationAge;
 extern int	Log_RotationSize;
 extern PGDLLIMPORT char *Log_directory;
@@ -81,7 +80,7 @@ extern HANDLE syslogPipe[2];
 
 extern int	SysLogger_Start(void);
 
-extern void write_syslogger_file(const char *buffer, int count, int dest);
+extern void write_syslogger_file(const char *buffer, int count, bool dest_csv);
 
 #ifdef EXEC_BACKEND
 extern void SysLoggerMain(int argc, char *argv[]) pg_attribute_noreturn();
diff --git a/src/include/utils/elog.h b/src/include/utils/elog.h
index 7bfd25a9e9..49dc7ea9e5 100644
--- a/src/include/utils/elog.h
+++ b/src/include/utils/elog.h
@@ -396,6 +396,7 @@ extern bool syslog_split_messages;
 #define LOG_DESTINATION_SYSLOG	 2
 #define LOG_DESTINATION_EVENTLOG 4
 #define LOG_DESTINATION_CSVLOG	 8
+#define LOG_DESTINATION_FILE     16
 
 /* Other exported functions */
 extern void DebugFileOpen(void);
