v2-0001-Unified-logging-system-for-command-line-programs.patch

text/plain

Filename: v2-0001-Unified-logging-system-for-command-line-programs.patch
Type: text/plain
Part: 0
Message: Re: Unified logging system for command-line programs

Patch

Format: format-patch
Series: patch v2-0001
Subject: Unified logging system for command-line programs
File+
src/backend/utils/misc/pg_controldata.c 4 4
src/bin/initdb/initdb.c 106 156
src/bin/initdb/nls.mk 3 2
src/bin/pg_archivecleanup/Makefile 3 1
src/bin/pg_archivecleanup/nls.mk 3 1
src/bin/pg_archivecleanup/pg_archivecleanup.c 23 30
src/bin/pg_basebackup/nls.mk 3 2
src/bin/pg_basebackup/pg_basebackup.c 153 258
src/bin/pg_basebackup/pg_receivewal.c 51 73
src/bin/pg_basebackup/pg_recvlogical.c 59 98
src/bin/pg_basebackup/receivelog.c 92 124
src/bin/pg_basebackup/streamutil.c 42 55
src/bin/pg_basebackup/walmethods.c 8 8
src/bin/pgbench/pgbench.c 2 16
src/bin/pg_controldata/Makefile 3 1
src/bin/pg_controldata/pg_controldata.c 3 2
src/bin/pg_ctl/Makefile 3 1
src/bin/pg_ctl/pg_ctl.c 3 1
src/bin/pg_dump/common.c 43 81
src/bin/pg_dump/compress_io.c 16 30
src/bin/pg_dump/nls.mk 7 6
src/bin/pg_dump/parallel.c 23 37
src/bin/pg_dump/pg_backup_archiver.c 97 129
src/bin/pg_dump/pg_backup_archiver.h 3 10
src/bin/pg_dump/pg_backup_custom.c 38 55
src/bin/pg_dump/pg_backup_db.c 20 20
src/bin/pg_dump/pg_backup_directory.c 29 43
src/bin/pg_dump/pg_backup_null.c 2 2
src/bin/pg_dump/pg_backup_tar.c 35 53
src/bin/pg_dump/pg_backup_utils.c 4 18
src/bin/pg_dump/pg_backup_utils.h 3 1
src/bin/pg_dump/pg_dumpall.c 51 67
src/bin/pg_dump/pg_dump.c 150 180
src/bin/pg_dump/pg_dump.h 0 1
src/bin/pg_dump/pg_dump_sort.c 12 14
src/bin/pg_dump/pg_restore.c 16 20
src/bin/pg_dump/t/001_basic.pl 26 26
src/bin/pg_dump/t/002_pg_dump.pl 8 8
src/bin/pg_resetwal/Makefile 3 1
src/bin/pg_resetwal/nls.mk 3 1
src/bin/pg_resetwal/pg_resetwal.c 74 107
src/bin/pg_resetwal/t/002_corrupted.pl 2 2
src/bin/pg_rewind/copy_fetch.c 19 19
src/bin/pg_rewind/datapagemap.c 3 2
src/bin/pg_rewind/filemap.c 16 18
src/bin/pg_rewind/file_ops.c 30 30
src/bin/pg_rewind/libpq_fetch.c 18 18
src/bin/pg_rewind/logging.c 2 67
src/bin/pg_rewind/logging.h 4 14
src/bin/pg_rewind/Makefile 2 2
src/bin/pg_rewind/nls.mk 3 4
src/bin/pg_rewind/parsexlog.c 11 11
src/bin/pg_rewind/pg_rewind.c 37 33
src/bin/pg_rewind/pg_rewind.h 0 1
src/bin/pg_rewind/timeline.c 9 8
src/bin/pg_test_fsync/Makefile 3 1
src/bin/pg_test_fsync/pg_test_fsync.c 7 12
src/bin/pg_upgrade/pg_upgrade.c 3 1
src/bin/pg_verify_checksums/Makefile 3 1
src/bin/pg_verify_checksums/nls.mk 3 1
src/bin/pg_verify_checksums/pg_verify_checksums.c 20 23
src/bin/pg_waldump/Makefile 2 1
src/bin/pg_waldump/nls.mk 3 3
src/bin/pg_waldump/pg_waldump.c 23 48
src/bin/psql/command.c 81 76
src/bin/psql/common.c 30 51
src/bin/psql/common.h 0 2
src/bin/psql/copy.c 20 22
src/bin/psql/crosstabview.c 10 9
src/bin/psql/describe.c 38 37
src/bin/psql/help.c 2 1
src/bin/psql/input.c 7 8
src/bin/psql/large_obj.c 8 7
src/bin/psql/mainloop.c 7 7
src/bin/psql/nls.mk 5 3
src/bin/psql/psqlscanslash.l 6 5
src/bin/psql/startup.c 34 8
src/bin/psql/variables.c 7 4
src/bin/scripts/clusterdb.c 10 10
src/bin/scripts/common.c 13 17
src/bin/scripts/createdb.c 10 12
src/bin/scripts/createuser.c 7 6
src/bin/scripts/dropdb.c 6 5
src/bin/scripts/dropuser.c 7 5
src/bin/scripts/nls.mk 4 2
src/bin/scripts/pg_isready.c 6 4
src/bin/scripts/reindexdb.c 22 20
src/bin/scripts/vacuumdb.c 19 21
src/common/controldata_utils.c 14 12
src/common/file_utils.c 37 47
src/common/pgfnames.c 9 22
src/common/restricted_token.c 11 12
src/common/rmtree.c 9 18
src/fe_utils/logging.c 165 0
src/fe_utils/Makefile 1 1
src/fe_utils/psqlscan.l 2 1
src/include/common/controldata_utils.h 1 1
src/include/common/file_utils.h 5 8
src/include/common/restricted_token.h 2 2
src/include/fe_utils/logging.h 94 0
src/include/fe_utils/psqlscan.h 0 7
src/interfaces/ecpg/test/Makefile 2 0
src/nls-global.mk 8 0
src/test/isolation/Makefile 2 1
src/test/regress/GNUmakefile 3 1
src/test/regress/pg_regress.c 4 2
From 5ef0bd554573be3e4a1ec79b6065e9d7acd5187e Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <peter@eisentraut.org>
Date: Fri, 11 Jan 2019 18:09:09 +0100
Subject: [PATCH v2] Unified logging system for command-line programs

This unifies the various ad hoc logging (message printing, error
printing) systems used throughout the command-line programs.
---
 src/backend/utils/misc/pg_controldata.c       |   8 +-
 src/bin/initdb/initdb.c                       | 262 +++++------
 src/bin/initdb/nls.mk                         |   5 +-
 src/bin/pg_archivecleanup/Makefile            |   4 +-
 src/bin/pg_archivecleanup/nls.mk              |   4 +-
 src/bin/pg_archivecleanup/pg_archivecleanup.c |  53 +--
 src/bin/pg_basebackup/nls.mk                  |   5 +-
 src/bin/pg_basebackup/pg_basebackup.c         | 411 +++++++-----------
 src/bin/pg_basebackup/pg_receivewal.c         | 124 +++---
 src/bin/pg_basebackup/pg_recvlogical.c        | 157 +++----
 src/bin/pg_basebackup/receivelog.c            | 216 ++++-----
 src/bin/pg_basebackup/streamutil.c            |  97 ++---
 src/bin/pg_basebackup/walmethods.c            |  16 +-
 src/bin/pg_controldata/Makefile               |   4 +-
 src/bin/pg_controldata/pg_controldata.c       |   5 +-
 src/bin/pg_ctl/Makefile                       |   4 +-
 src/bin/pg_ctl/pg_ctl.c                       |   4 +-
 src/bin/pg_dump/common.c                      | 124 ++----
 src/bin/pg_dump/compress_io.c                 |  46 +-
 src/bin/pg_dump/nls.mk                        |  13 +-
 src/bin/pg_dump/parallel.c                    |  60 +--
 src/bin/pg_dump/pg_backup_archiver.c          | 226 +++++-----
 src/bin/pg_dump/pg_backup_archiver.h          |  13 +-
 src/bin/pg_dump/pg_backup_custom.c            |  93 ++--
 src/bin/pg_dump/pg_backup_db.c                |  40 +-
 src/bin/pg_dump/pg_backup_directory.c         |  72 ++-
 src/bin/pg_dump/pg_backup_null.c              |   4 +-
 src/bin/pg_dump/pg_backup_tar.c               |  88 ++--
 src/bin/pg_dump/pg_backup_utils.c             |  22 +-
 src/bin/pg_dump/pg_backup_utils.h             |   4 +-
 src/bin/pg_dump/pg_dump.c                     | 330 +++++++-------
 src/bin/pg_dump/pg_dump.h                     |   1 -
 src/bin/pg_dump/pg_dump_sort.c                |  26 +-
 src/bin/pg_dump/pg_dumpall.c                  | 118 +++--
 src/bin/pg_dump/pg_restore.c                  |  36 +-
 src/bin/pg_dump/t/001_basic.pl                |  52 +--
 src/bin/pg_dump/t/002_pg_dump.pl              |  16 +-
 src/bin/pg_resetwal/Makefile                  |   4 +-
 src/bin/pg_resetwal/nls.mk                    |   4 +-
 src/bin/pg_resetwal/pg_resetwal.c             | 181 ++++----
 src/bin/pg_resetwal/t/002_corrupted.pl        |   4 +-
 src/bin/pg_rewind/Makefile                    |   4 +-
 src/bin/pg_rewind/copy_fetch.c                |  38 +-
 src/bin/pg_rewind/datapagemap.c               |   5 +-
 src/bin/pg_rewind/file_ops.c                  |  60 +--
 src/bin/pg_rewind/filemap.c                   |  34 +-
 src/bin/pg_rewind/libpq_fetch.c               |  36 +-
 src/bin/pg_rewind/logging.c                   |  69 +--
 src/bin/pg_rewind/logging.h                   |  18 +-
 src/bin/pg_rewind/nls.mk                      |   7 +-
 src/bin/pg_rewind/parsexlog.c                 |  22 +-
 src/bin/pg_rewind/pg_rewind.c                 |  70 +--
 src/bin/pg_rewind/pg_rewind.h                 |   1 -
 src/bin/pg_rewind/timeline.c                  |  17 +-
 src/bin/pg_test_fsync/Makefile                |   4 +-
 src/bin/pg_test_fsync/pg_test_fsync.c         |  19 +-
 src/bin/pg_upgrade/pg_upgrade.c               |   4 +-
 src/bin/pg_verify_checksums/Makefile          |   4 +-
 src/bin/pg_verify_checksums/nls.mk            |   4 +-
 .../pg_verify_checksums/pg_verify_checksums.c |  43 +-
 src/bin/pg_waldump/Makefile                   |   3 +-
 src/bin/pg_waldump/nls.mk                     |   6 +-
 src/bin/pg_waldump/pg_waldump.c               |  71 +--
 src/bin/pgbench/pgbench.c                     |  18 +-
 src/bin/psql/command.c                        | 157 +++----
 src/bin/psql/common.c                         |  81 ++--
 src/bin/psql/common.h                         |   2 -
 src/bin/psql/copy.c                           |  42 +-
 src/bin/psql/crosstabview.c                   |  19 +-
 src/bin/psql/describe.c                       |  75 ++--
 src/bin/psql/help.c                           |   3 +-
 src/bin/psql/input.c                          |  15 +-
 src/bin/psql/large_obj.c                      |  15 +-
 src/bin/psql/mainloop.c                       |  14 +-
 src/bin/psql/nls.mk                           |   8 +-
 src/bin/psql/psqlscanslash.l                  |  11 +-
 src/bin/psql/startup.c                        |  42 +-
 src/bin/psql/variables.c                      |  11 +-
 src/bin/scripts/clusterdb.c                   |  20 +-
 src/bin/scripts/common.c                      |  30 +-
 src/bin/scripts/createdb.c                    |  22 +-
 src/bin/scripts/createuser.c                  |  13 +-
 src/bin/scripts/dropdb.c                      |  11 +-
 src/bin/scripts/dropuser.c                    |  12 +-
 src/bin/scripts/nls.mk                        |   6 +-
 src/bin/scripts/pg_isready.c                  |  10 +-
 src/bin/scripts/reindexdb.c                   |  42 +-
 src/bin/scripts/vacuumdb.c                    |  40 +-
 src/common/controldata_utils.c                |  26 +-
 src/common/file_utils.c                       |  84 ++--
 src/common/pgfnames.c                         |  31 +-
 src/common/restricted_token.c                 |  23 +-
 src/common/rmtree.c                           |  27 +-
 src/fe_utils/Makefile                         |   2 +-
 src/fe_utils/logging.c                        | 165 +++++++
 src/fe_utils/psqlscan.l                       |   3 +-
 src/include/common/controldata_utils.h        |   2 +-
 src/include/common/file_utils.h               |  13 +-
 src/include/common/restricted_token.h         |   4 +-
 src/include/fe_utils/logging.h                |  94 ++++
 src/include/fe_utils/psqlscan.h               |   7 -
 src/interfaces/ecpg/test/Makefile             |   2 +
 src/nls-global.mk                             |   8 +
 src/test/isolation/Makefile                   |   3 +-
 src/test/regress/GNUmakefile                  |   4 +-
 src/test/regress/pg_regress.c                 |   6 +-
 106 files changed, 2178 insertions(+), 2540 deletions(-)
 create mode 100644 src/fe_utils/logging.c
 create mode 100644 src/include/fe_utils/logging.h

diff --git a/src/backend/utils/misc/pg_controldata.c b/src/backend/utils/misc/pg_controldata.c
index e6742dc24b..aed28d5bca 100644
--- a/src/backend/utils/misc/pg_controldata.c
+++ b/src/backend/utils/misc/pg_controldata.c
@@ -53,7 +53,7 @@ pg_control_system(PG_FUNCTION_ARGS)
 	tupdesc = BlessTupleDesc(tupdesc);
 
 	/* read the control file */
-	ControlFile = get_controlfile(DataDir, NULL, &crc_ok);
+	ControlFile = get_controlfile(DataDir, &crc_ok);
 	if (!crc_ok)
 		ereport(ERROR,
 				(errmsg("calculated CRC checksum does not match value stored in file")));
@@ -131,7 +131,7 @@ pg_control_checkpoint(PG_FUNCTION_ARGS)
 	tupdesc = BlessTupleDesc(tupdesc);
 
 	/* Read the control file. */
-	ControlFile = get_controlfile(DataDir, NULL, &crc_ok);
+	ControlFile = get_controlfile(DataDir, &crc_ok);
 	if (!crc_ok)
 		ereport(ERROR,
 				(errmsg("calculated CRC checksum does not match value stored in file")));
@@ -235,7 +235,7 @@ pg_control_recovery(PG_FUNCTION_ARGS)
 	tupdesc = BlessTupleDesc(tupdesc);
 
 	/* read the control file */
-	ControlFile = get_controlfile(DataDir, NULL, &crc_ok);
+	ControlFile = get_controlfile(DataDir, &crc_ok);
 	if (!crc_ok)
 		ereport(ERROR,
 				(errmsg("calculated CRC checksum does not match value stored in file")));
@@ -302,7 +302,7 @@ pg_control_init(PG_FUNCTION_ARGS)
 	tupdesc = BlessTupleDesc(tupdesc);
 
 	/* read the control file */
-	ControlFile = get_controlfile(DataDir, NULL, &crc_ok);
+	ControlFile = get_controlfile(DataDir, &crc_ok);
 	if (!crc_ok)
 		ereport(ERROR,
 				(errmsg("calculated CRC checksum does not match value stored in file")));
diff --git a/src/bin/initdb/initdb.c b/src/bin/initdb/initdb.c
index e55ba668ce..e8b83992ea 100644
--- a/src/bin/initdb/initdb.c
+++ b/src/bin/initdb/initdb.c
@@ -67,6 +67,7 @@
 #include "common/file_utils.h"
 #include "common/restricted_token.h"
 #include "common/username.h"
+#include "fe_utils/logging.h"
 #include "fe_utils/string_utils.h"
 #include "getaddrinfo.h"
 #include "getopt_long.h"
@@ -184,7 +185,7 @@ static const char *default_timezone = NULL;
 "# allows any local user to connect as any PostgreSQL user, including\n" \
 "# the database superuser.  If you do not trust all your local users,\n" \
 "# use another authentication method.\n"
-static char *authwarning = NULL;
+static bool	authwarning = false;
 
 /*
  * Centralized knowledge of switches to pass to backend
@@ -335,7 +336,7 @@ escape_quotes(const char *src)
 
 	if (!result)
 	{
-		fprintf(stderr, _("%s: out of memory\n"), progname);
+		pg_log_error("out of memory");
 		exit(1);
 	}
 	return result;
@@ -491,8 +492,7 @@ readfile(const char *path)
 
 	if ((infile = fopen(path, "r")) == NULL)
 	{
-		fprintf(stderr, _("%s: could not open file \"%s\" for reading: %s\n"),
-				progname, path, strerror(errno));
+		pg_log_error("could not open file \"%s\" for reading: %m", path);
 		exit(1);
 	}
 
@@ -547,24 +547,21 @@ writefile(char *path, char **lines)
 
 	if ((out_file = fopen(path, "w")) == NULL)
 	{
-		fprintf(stderr, _("%s: could not open file \"%s\" for writing: %s\n"),
-				progname, path, strerror(errno));
+		pg_log_error("could not open file \"%s\" for writing: %m", path);
 		exit(1);
 	}
 	for (line = lines; *line != NULL; line++)
 	{
 		if (fputs(*line, out_file) < 0)
 		{
-			fprintf(stderr, _("%s: could not write file \"%s\": %s\n"),
-					progname, path, strerror(errno));
+			pg_log_error("could not write file \"%s\": %m", path);
 			exit(1);
 		}
 		free(*line);
 	}
 	if (fclose(out_file))
 	{
-		fprintf(stderr, _("%s: could not write file \"%s\": %s\n"),
-				progname, path, strerror(errno));
+		pg_log_error("could not write file \"%s\": %m", path);
 		exit(1);
 	}
 }
@@ -582,8 +579,7 @@ popen_check(const char *command, const char *mode)
 	errno = 0;
 	cmdfd = popen(command, mode);
 	if (cmdfd == NULL)
-		fprintf(stderr, _("%s: could not execute command \"%s\": %s\n"),
-				progname, command, strerror(errno));
+		pg_log_error("could not execute command \"%s\": %m", command);
 	return cmdfd;
 }
 
@@ -601,52 +597,41 @@ cleanup_directories_atexit(void)
 	{
 		if (made_new_pgdata)
 		{
-			fprintf(stderr, _("%s: removing data directory \"%s\"\n"),
-					progname, pg_data);
+			pg_log_info("removing data directory \"%s\"", pg_data);
 			if (!rmtree(pg_data, true))
-				fprintf(stderr, _("%s: failed to remove data directory\n"),
-						progname);
+				pg_log_error("failed to remove data directory");
 		}
 		else if (found_existing_pgdata)
 		{
-			fprintf(stderr,
-					_("%s: removing contents of data directory \"%s\"\n"),
-					progname, pg_data);
+			pg_log_info("removing contents of data directory \"%s\"",
+						pg_data);
 			if (!rmtree(pg_data, false))
-				fprintf(stderr, _("%s: failed to remove contents of data directory\n"),
-						progname);
+				pg_log_error("failed to remove contents of data directory");
 		}
 
 		if (made_new_xlogdir)
 		{
-			fprintf(stderr, _("%s: removing WAL directory \"%s\"\n"),
-					progname, xlog_dir);
+			pg_log_info("removing WAL directory \"%s\"", xlog_dir);
 			if (!rmtree(xlog_dir, true))
-				fprintf(stderr, _("%s: failed to remove WAL directory\n"),
-						progname);
+				pg_log_error("failed to remove WAL directory");
 		}
 		else if (found_existing_xlogdir)
 		{
-			fprintf(stderr,
-					_("%s: removing contents of WAL directory \"%s\"\n"),
-					progname, xlog_dir);
+			pg_log_info("removing contents of WAL directory \"%s\"", xlog_dir);
 			if (!rmtree(xlog_dir, false))
-				fprintf(stderr, _("%s: failed to remove contents of WAL directory\n"),
-						progname);
+				pg_log_error("failed to remove contents of WAL directory");
 		}
 		/* otherwise died during startup, do nothing! */
 	}
 	else
 	{
 		if (made_new_pgdata || found_existing_pgdata)
-			fprintf(stderr,
-					_("%s: data directory \"%s\" not removed at user's request\n"),
-					progname, pg_data);
+			pg_log_info("data directory \"%s\" not removed at user's request",
+						pg_data);
 
 		if (made_new_xlogdir || found_existing_xlogdir)
-			fprintf(stderr,
-					_("%s: WAL directory \"%s\" not removed at user's request\n"),
-					progname, xlog_dir);
+			pg_log_info("WAL directory \"%s\" not removed at user's request",
+						xlog_dir);
 	}
 }
 
@@ -663,12 +648,10 @@ get_id(void)
 #ifndef WIN32
 	if (geteuid() == 0)			/* 0 is root's uid */
 	{
+		pg_log_error("cannot be run as root");
 		fprintf(stderr,
-				_("%s: cannot be run as root\n"
-				  "Please log in (using, e.g., \"su\") as the "
-				  "(unprivileged) user that will\n"
-				  "own the server process.\n"),
-				progname);
+				_("Please log in (using, e.g., \"su\") as the (unprivileged) user that will\n"
+				  "own the server process.\n"));
 		exit(1);
 	}
 #endif
@@ -700,8 +683,8 @@ get_encoding_id(const char *encoding_name)
 		if ((enc = pg_valid_server_encoding(encoding_name)) >= 0)
 			return enc;
 	}
-	fprintf(stderr, _("%s: \"%s\" is not a valid server encoding name\n"),
-			progname, encoding_name ? encoding_name : "(null)");
+	pg_log_error("\"%s\" is not a valid server encoding name",
+				 encoding_name ? encoding_name : "(null)");
 	exit(1);
 }
 
@@ -831,17 +814,14 @@ check_input(char *path)
 	{
 		if (errno == ENOENT)
 		{
-			fprintf(stderr,
-					_("%s: file \"%s\" does not exist\n"), progname, path);
+			pg_log_error("file \"%s\" does not exist", path);
 			fprintf(stderr,
 					_("This might mean you have a corrupted installation or identified\n"
 					  "the wrong directory with the invocation option -L.\n"));
 		}
 		else
 		{
-			fprintf(stderr,
-					_("%s: could not access file \"%s\": %s\n"), progname, path,
-					strerror(errno));
+			pg_log_error("could not access file \"%s\": %m", path);
 			fprintf(stderr,
 					_("This might mean you have a corrupted installation or identified\n"
 					  "the wrong directory with the invocation option -L.\n"));
@@ -850,8 +830,7 @@ check_input(char *path)
 	}
 	if (!S_ISREG(statbuf.st_mode))
 	{
-		fprintf(stderr,
-				_("%s: file \"%s\" is not a regular file\n"), progname, path);
+		pg_log_error("file \"%s\" is not a regular file", path);
 		fprintf(stderr,
 				_("This might mean you have a corrupted installation or identified\n"
 				  "the wrong directory with the invocation option -L.\n"));
@@ -876,15 +855,13 @@ write_version_file(const char *extrapath)
 
 	if ((version_file = fopen(path, PG_BINARY_W)) == NULL)
 	{
-		fprintf(stderr, _("%s: could not open file \"%s\" for writing: %s\n"),
-				progname, path, strerror(errno));
+		pg_log_error("could not open file \"%s\" for writing: %m", path);
 		exit(1);
 	}
 	if (fprintf(version_file, "%s\n", PG_MAJORVERSION) < 0 ||
 		fclose(version_file))
 	{
-		fprintf(stderr, _("%s: could not write file \"%s\": %s\n"),
-				progname, path, strerror(errno));
+		pg_log_error("could not write file \"%s\": %m", path);
 		exit(1);
 	}
 	free(path);
@@ -904,14 +881,12 @@ set_null_conf(void)
 	conf_file = fopen(path, PG_BINARY_W);
 	if (conf_file == NULL)
 	{
-		fprintf(stderr, _("%s: could not open file \"%s\" for writing: %s\n"),
-				progname, path, strerror(errno));
+		pg_log_error("could not open file \"%s\" for writing: %m", path);
 		exit(1);
 	}
 	if (fclose(conf_file))
 	{
-		fprintf(stderr, _("%s: could not write file \"%s\": %s\n"),
-				progname, path, strerror(errno));
+		pg_log_error("could not write file \"%s\": %m", path);
 		exit(1);
 	}
 	free(path);
@@ -1261,8 +1236,7 @@ setup_config(void)
 	writefile(path, conflines);
 	if (chmod(path, pg_file_create_mode) != 0)
 	{
-		fprintf(stderr, _("%s: could not change permissions of \"%s\": %s\n"),
-				progname, path, strerror(errno));
+		pg_log_error("could not change permissions of \"%s\": %m", path);
 		exit(1);
 	}
 
@@ -1281,8 +1255,7 @@ setup_config(void)
 	writefile(path, autoconflines);
 	if (chmod(path, pg_file_create_mode) != 0)
 	{
-		fprintf(stderr, _("%s: could not change permissions of \"%s\": %s\n"),
-				progname, path, strerror(errno));
+		pg_log_error("could not change permissions of \"%s\": %m", path);
 		exit(1);
 	}
 
@@ -1368,8 +1341,7 @@ setup_config(void)
 	writefile(path, conflines);
 	if (chmod(path, pg_file_create_mode) != 0)
 	{
-		fprintf(stderr, _("%s: could not change permissions of \"%s\": %s\n"),
-				progname, path, strerror(errno));
+		pg_log_error("could not change permissions of \"%s\": %m", path);
 		exit(1);
 	}
 
@@ -1384,8 +1356,7 @@ setup_config(void)
 	writefile(path, conflines);
 	if (chmod(path, pg_file_create_mode) != 0)
 	{
-		fprintf(stderr, _("%s: could not change permissions of \"%s\": %s\n"),
-				progname, path, strerror(errno));
+		pg_log_error("could not change permissions of \"%s\": %m", path);
 		exit(1);
 	}
 
@@ -1419,11 +1390,9 @@ bootstrap_template1(void)
 
 	if (strcmp(headerline, *bki_lines) != 0)
 	{
-		fprintf(stderr,
-				_("%s: input file \"%s\" does not belong to PostgreSQL %s\n"
-				  "Check your installation or specify the correct path "
-				  "using the option -L.\n"),
-				progname, bki_file, PG_VERSION);
+		pg_log_error("input file \"%s\" does not belong to PostgreSQL %s",
+					 bki_file, PG_VERSION);
+		fprintf(stderr, _("Check your installation or specify the correct path using the option -L.\n"));
 		exit(1);
 	}
 
@@ -1560,18 +1529,18 @@ get_su_pwd(void)
 
 		if (!pwf)
 		{
-			fprintf(stderr, _("%s: could not open file \"%s\" for reading: %s\n"),
-					progname, pwfilename, strerror(errno));
+			pg_log_error("could not open file \"%s\" for reading: %m",
+						 pwfilename);
 			exit(1);
 		}
 		if (!fgets(pwd1, sizeof(pwd1), pwf))
 		{
 			if (ferror(pwf))
-				fprintf(stderr, _("%s: could not read password from file \"%s\": %s\n"),
-						progname, pwfilename, strerror(errno));
+				pg_log_error("could not read password from file \"%s\": %m",
+							 pwfilename);
 			else
-				fprintf(stderr, _("%s: password file \"%s\" is empty\n"),
-						progname, pwfilename);
+				pg_log_error("password file \"%s\" is empty",
+							 pwfilename);
 			exit(1);
 		}
 		fclose(pwf);
@@ -2237,8 +2206,7 @@ check_locale_name(int category, const char *locale, char **canonname)
 	save = setlocale(category, NULL);
 	if (!save)
 	{
-		fprintf(stderr, _("%s: setlocale() failed\n"),
-				progname);
+		pg_log_error("setlocale() failed");
 		exit(1);
 	}
 
@@ -2259,8 +2227,7 @@ check_locale_name(int category, const char *locale, char **canonname)
 	/* restore old value. */
 	if (!setlocale(category, save))
 	{
-		fprintf(stderr, _("%s: failed to restore old locale \"%s\"\n"),
-				progname, save);
+		pg_log_error("failed to restore old locale \"%s\"", save);
 		exit(1);
 	}
 	free(save);
@@ -2269,8 +2236,7 @@ check_locale_name(int category, const char *locale, char **canonname)
 	if (res == NULL)
 	{
 		if (*locale)
-			fprintf(stderr, _("%s: invalid locale name \"%s\"\n"),
-					progname, locale);
+			pg_log_error("invalid locale name \"%s\"", locale);
 		else
 		{
 			/*
@@ -2281,8 +2247,7 @@ check_locale_name(int category, const char *locale, char **canonname)
 			 * setlocale's behavior is implementation-specific, it's hard to
 			 * be sure what it didn't like.  Print a safe generic message.
 			 */
-			fprintf(stderr, _("%s: invalid locale settings; check LANG and LC_* environment variables\n"),
-					progname);
+			pg_log_error("invalid locale settings; check LANG and LC_* environment variables");
 		}
 		exit(1);
 	}
@@ -2309,7 +2274,7 @@ check_locale_encoding(const char *locale, int user_enc)
 #endif
 		  user_enc == PG_SQL_ASCII))
 	{
-		fprintf(stderr, _("%s: encoding mismatch\n"), progname);
+		pg_log_error("encoding mismatch");
 		fprintf(stderr,
 				_("The encoding you selected (%s) and the encoding that the\n"
 				  "selected locale uses (%s) do not match.  This would lead to\n"
@@ -2427,9 +2392,7 @@ check_authmethod_unspecified(const char **authmethod)
 {
 	if (*authmethod == NULL)
 	{
-		authwarning = _("\nWARNING: enabling \"trust\" authentication for local connections\n"
-						"You can change this by editing pg_hba.conf or using the option -A, or\n"
-						"--auth-local and --auth-host, the next time you run initdb.\n");
+		authwarning = true;
 		*authmethod = "trust";
 	}
 }
@@ -2449,8 +2412,8 @@ check_authmethod_valid(const char *authmethod, const char *const *valid_methods,
 				return;
 	}
 
-	fprintf(stderr, _("%s: invalid authentication method \"%s\" for \"%s\" connections\n"),
-			progname, authmethod, conntype);
+	pg_log_error("invalid authentication method \"%s\" for \"%s\" connections",
+				 authmethod, conntype);
 	exit(1);
 }
 
@@ -2465,7 +2428,7 @@ check_need_password(const char *authmethodlocal, const char *authmethodhost)
 		 strcmp(authmethodhost, "scram-sha-256") == 0) &&
 		!(pwprompt || pwfilename))
 	{
-		fprintf(stderr, _("%s: must specify a password for the superuser to enable %s authentication\n"), progname,
+		pg_log_error("must specify a password for the superuser to enable %s authentication",
 				(strcmp(authmethodlocal, "md5") == 0 ||
 				 strcmp(authmethodlocal, "password") == 0 ||
 				 strcmp(authmethodlocal, "scram-sha-256") == 0)
@@ -2492,12 +2455,11 @@ setup_pgdata(void)
 		}
 		else
 		{
+			pg_log_error("no data directory specified");
 			fprintf(stderr,
-					_("%s: no data directory specified\n"
-					  "You must identify the directory where the data for this database system\n"
+					_("You must identify the directory where the data for this database system\n"
 					  "will reside.  Do this with either the invocation option -D or the\n"
-					  "environment variable PGDATA.\n"),
-					progname);
+					  "environment variable PGDATA.\n"));
 			exit(1);
 		}
 	}
@@ -2530,18 +2492,15 @@ setup_bin_paths(const char *argv0)
 			strlcpy(full_path, progname, sizeof(full_path));
 
 		if (ret == -1)
-			fprintf(stderr,
-					_("The program \"postgres\" is needed by %s "
-					  "but was not found in the\n"
-					  "same directory as \"%s\".\n"
-					  "Check your installation.\n"),
-					progname, full_path);
+			pg_log_error("The program \"postgres\" is needed by %s but was not found in the\n"
+						 "same directory as \"%s\".\n"
+						 "Check your installation.",
+						 full_path, progname);
 		else
-			fprintf(stderr,
-					_("The program \"postgres\" was found by \"%s\"\n"
-					  "but was not the same version as %s.\n"
-					  "Check your installation.\n"),
-					full_path, progname);
+			pg_log_error("The program \"postgres\" was found by \"%s\"\n"
+						 "but was not the same version as %s.\n"
+						 "Check your installation.",
+						 full_path, progname);
 		exit(1);
 	}
 
@@ -2557,7 +2516,7 @@ setup_bin_paths(const char *argv0)
 	}
 	else if (!is_absolute_path(share_path))
 	{
-		fprintf(stderr, _("%s: input file location must be an absolute path\n"), progname);
+		pg_log_error("input file location must be an absolute path");
 		exit(1);
 	}
 
@@ -2601,8 +2560,8 @@ setup_locale_encoding(void)
 		if (ctype_enc == -1)
 		{
 			/* Couldn't recognize the locale's codeset */
-			fprintf(stderr, _("%s: could not find suitable encoding for locale \"%s\"\n"),
-					progname, lc_ctype);
+			pg_log_error("could not find suitable encoding for locale \"%s\"",
+						 lc_ctype);
 			fprintf(stderr, _("Rerun %s with the -E option.\n"), progname);
 			fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
 					progname);
@@ -2622,9 +2581,8 @@ setup_locale_encoding(void)
 				   pg_encoding_to_char(ctype_enc),
 				   pg_encoding_to_char(encodingid));
 #else
-			fprintf(stderr,
-					_("%s: locale \"%s\" requires unsupported encoding \"%s\"\n"),
-					progname, lc_ctype, pg_encoding_to_char(ctype_enc));
+			pg_log_error("locale \"%s\" requires unsupported encoding \"%s\"",
+						 lc_ctype, pg_encoding_to_char(ctype_enc));
 			fprintf(stderr,
 					_("Encoding \"%s\" is not allowed as a server-side encoding.\n"
 					  "Rerun %s with a different locale selection.\n"),
@@ -2774,8 +2732,7 @@ create_data_directory(void)
 
 			if (pg_mkdir_p(pg_data, pg_dir_create_mode) != 0)
 			{
-				fprintf(stderr, _("%s: could not create directory \"%s\": %s\n"),
-						progname, pg_data, strerror(errno));
+				pg_log_error("could not create directory \"%s\": %m", pg_data);
 				exit(1);
 			}
 			else
@@ -2792,8 +2749,8 @@ create_data_directory(void)
 
 			if (chmod(pg_data, pg_dir_create_mode) != 0)
 			{
-				fprintf(stderr, _("%s: could not change permissions of directory \"%s\": %s\n"),
-						progname, pg_data, strerror(errno));
+				pg_log_error("could not change permissions of directory \"%s\": %m",
+							 pg_data);
 				exit(1);
 			}
 			else
@@ -2806,9 +2763,7 @@ create_data_directory(void)
 		case 3:
 		case 4:
 			/* Present and not empty */
-			fprintf(stderr,
-					_("%s: directory \"%s\" exists but is not empty\n"),
-					progname, pg_data);
+			pg_log_error("directory \"%s\" exists but is not empty", pg_data);
 			if (ret != 4)
 				warn_on_mount_point(ret);
 			else
@@ -2821,8 +2776,7 @@ create_data_directory(void)
 
 		default:
 			/* Trouble accessing directory */
-			fprintf(stderr, _("%s: could not access directory \"%s\": %s\n"),
-					progname, pg_data, strerror(errno));
+			pg_log_error("could not access directory \"%s\": %m", pg_data);
 			exit(1);
 	}
 }
@@ -2845,7 +2799,7 @@ create_xlog_or_symlink(void)
 		canonicalize_path(xlog_dir);
 		if (!is_absolute_path(xlog_dir))
 		{
-			fprintf(stderr, _("%s: WAL directory location must be an absolute path\n"), progname);
+			pg_log_error("WAL directory location must be an absolute path");
 			exit(1);
 		}
 
@@ -2860,8 +2814,8 @@ create_xlog_or_symlink(void)
 
 				if (pg_mkdir_p(xlog_dir, pg_dir_create_mode) != 0)
 				{
-					fprintf(stderr, _("%s: could not create directory \"%s\": %s\n"),
-							progname, xlog_dir, strerror(errno));
+					pg_log_error("could not create directory \"%s\": %m",
+								 xlog_dir);
 					exit(1);
 				}
 				else
@@ -2878,8 +2832,8 @@ create_xlog_or_symlink(void)
 
 				if (chmod(xlog_dir, pg_dir_create_mode) != 0)
 				{
-					fprintf(stderr, _("%s: could not change permissions of directory \"%s\": %s\n"),
-							progname, xlog_dir, strerror(errno));
+					pg_log_error("could not change permissions of directory \"%s\": %m",
+								 xlog_dir);
 					exit(1);
 				}
 				else
@@ -2892,9 +2846,7 @@ create_xlog_or_symlink(void)
 			case 3:
 			case 4:
 				/* Present and not empty */
-				fprintf(stderr,
-						_("%s: directory \"%s\" exists but is not empty\n"),
-						progname, xlog_dir);
+				pg_log_error("directory \"%s\" exists but is not empty", xlog_dir);
 				if (ret != 4)
 					warn_on_mount_point(ret);
 				else
@@ -2906,20 +2858,19 @@ create_xlog_or_symlink(void)
 
 			default:
 				/* Trouble accessing directory */
-				fprintf(stderr, _("%s: could not access directory \"%s\": %s\n"),
-						progname, xlog_dir, strerror(errno));
+				pg_log_error("could not access directory \"%s\": %m", xlog_dir);
 				exit(1);
 		}
 
 #ifdef HAVE_SYMLINK
 		if (symlink(xlog_dir, subdirloc) != 0)
 		{
-			fprintf(stderr, _("%s: could not create symbolic link \"%s\": %s\n"),
-					progname, subdirloc, strerror(errno));
+			pg_log_error("could not create symbolic link \"%s\": %m",
+						 subdirloc);
 			exit(1);
 		}
 #else
-		fprintf(stderr, _("%s: symlinks are not supported on this platform\n"), progname);
+		pg_log_error("symlinks are not supported on this platform");
 		exit(1);
 #endif
 	}
@@ -2928,8 +2879,8 @@ create_xlog_or_symlink(void)
 		/* Without -X option, just make the subdirectory normally */
 		if (mkdir(subdirloc, pg_dir_create_mode) < 0)
 		{
-			fprintf(stderr, _("%s: could not create directory \"%s\": %s\n"),
-					progname, subdirloc, strerror(errno));
+			pg_log_error("could not create directory \"%s\": %m",
+						 subdirloc);
 			exit(1);
 		}
 	}
@@ -2990,8 +2941,7 @@ initialize_data_directory(void)
 		 */
 		if (mkdir(path, pg_dir_create_mode) < 0)
 		{
-			fprintf(stderr, _("%s: could not create directory \"%s\": %s\n"),
-					progname, path, strerror(errno));
+			pg_log_error("could not create directory \"%s\": %m", path);
 			exit(1);
 		}
 
@@ -3125,6 +3075,7 @@ main(int argc, char *argv[])
 
 	progname = get_progname(argv[0]);
 	set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("initdb"));
+	pg_logging_init(argv[0]);
 
 	if (argc > 1)
 	{
@@ -3260,8 +3211,8 @@ main(int argc, char *argv[])
 
 	if (optind < argc)
 	{
-		fprintf(stderr, _("%s: too many command-line arguments (first is \"%s\")\n"),
-				progname, argv[optind]);
+		pg_log_error("too many command-line arguments (first is \"%s\")",
+					 argv[optind]);
 		fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
 				progname);
 		exit(1);
@@ -3277,21 +3228,20 @@ main(int argc, char *argv[])
 		/* must check that directory is readable */
 		if (pg_check_dir(pg_data) <= 0)
 		{
-			fprintf(stderr, _("%s: could not access directory \"%s\": %s\n"),
-					progname, pg_data, strerror(errno));
+			pg_log_error("could not access directory \"%s\": %m", pg_data);
 			exit(1);
 		}
 
 		fputs(_("syncing data to disk ... "), stdout);
 		fflush(stdout);
-		fsync_pgdata(pg_data, progname, PG_VERSION_NUM);
+		fsync_pgdata(pg_data, PG_VERSION_NUM);
 		check_ok();
 		return 0;
 	}
 
 	if (pwprompt && pwfilename)
 	{
-		fprintf(stderr, _("%s: password prompt and password file cannot be specified together\n"), progname);
+		pg_log_error("password prompt and password file cannot be specified together");
 		exit(1);
 	}
 
@@ -3316,21 +3266,17 @@ main(int argc, char *argv[])
 		/* verify that wal segment size is valid */
 		if (endptr == str_wal_segment_size_mb || *endptr != '\0')
 		{
-			fprintf(stderr,
-					_("%s: argument of --wal-segsize must be a number\n"),
-					progname);
+			pg_log_error("argument of --wal-segsize must be a number");
 			exit(1);
 		}
 		if (!IsValidWalSegSize(wal_segment_size_mb * 1024 * 1024))
 		{
-			fprintf(stderr,
-					_("%s: argument of --wal-segsize must be a power of 2 between 1 and 1024\n"),
-					progname);
+			pg_log_error("argument of --wal-segsize must be a power of 2 between 1 and 1024");
 			exit(1);
 		}
 	}
 
-	get_restricted_token(progname);
+	get_restricted_token();
 
 	setup_pgdata();
 
@@ -3342,7 +3288,7 @@ main(int argc, char *argv[])
 
 	if (strncmp(username, "pg_", 3) == 0)
 	{
-		fprintf(stderr, _("%s: superuser name \"%s\" is disallowed; role names cannot begin with \"pg_\"\n"), progname, username);
+		pg_log_error("superuser name \"%s\" is disallowed; role names cannot begin with \"pg_\"", username);
 		exit(1);
 	}
 
@@ -3377,14 +3323,18 @@ main(int argc, char *argv[])
 	{
 		fputs(_("syncing data to disk ... "), stdout);
 		fflush(stdout);
-		fsync_pgdata(pg_data, progname, PG_VERSION_NUM);
+		fsync_pgdata(pg_data, PG_VERSION_NUM);
 		check_ok();
 	}
 	else
 		printf(_("\nSync to disk skipped.\nThe data directory might become corrupt if the operating system crashes.\n"));
 
-	if (authwarning != NULL)
-		fprintf(stderr, "%s", authwarning);
+	if (authwarning)
+	{
+		pg_log_warning("enabling \"trust\" authentication for local connections");
+		fprintf(stderr, _("You can change this by editing pg_hba.conf or using the option -A, or\n"
+						  "--auth-local and --auth-host, the next time you run initdb.\n"));
+	}
 
 	/*
 	 * Build up a shell command to tell the user how to start the server
diff --git a/src/bin/initdb/nls.mk b/src/bin/initdb/nls.mk
index b0ce62980a..803388d4c7 100644
--- a/src/bin/initdb/nls.mk
+++ b/src/bin/initdb/nls.mk
@@ -1,5 +1,6 @@
 # src/bin/initdb/nls.mk
 CATALOG_NAME     = initdb
 AVAIL_LANGUAGES  = cs de es fr he it ja ko pl pt_BR ru sv tr vi zh_CN
-GETTEXT_FILES    = findtimezone.c initdb.c ../../common/exec.c ../../common/fe_memutils.c ../../common/file_utils.c ../../common/pgfnames.c ../../common/restricted_token.c ../../common/rmtree.c ../../common/username.c ../../common/wait_error.c ../../port/dirmod.c
-GETTEXT_TRIGGERS = simple_prompt
+GETTEXT_FILES    = $(FRONTEND_COMMON_GETTEXT_FILES) findtimezone.c initdb.c ../../common/exec.c ../../common/fe_memutils.c ../../common/file_utils.c ../../common/pgfnames.c ../../common/restricted_token.c ../../common/rmtree.c ../../common/username.c ../../common/wait_error.c ../../port/dirmod.c
+GETTEXT_TRIGGERS = $(FRONTEND_COMMON_GETTEXT_TRIGGERS) simple_prompt
+GETTEXT_FLAGS    = $(FRONTEND_COMMON_GETTEXT_FLAGS)
diff --git a/src/bin/pg_archivecleanup/Makefile b/src/bin/pg_archivecleanup/Makefile
index c5bf99db0f..14e834677b 100644
--- a/src/bin/pg_archivecleanup/Makefile
+++ b/src/bin/pg_archivecleanup/Makefile
@@ -7,11 +7,13 @@ subdir = src/bin/pg_archivecleanup
 top_builddir = ../../..
 include $(top_builddir)/src/Makefile.global
 
+LDFLAGS_INTERNAL += -L$(top_builddir)/src/fe_utils -lpgfeutils
+
 OBJS	= pg_archivecleanup.o $(WIN32RES)
 
 all: pg_archivecleanup
 
-pg_archivecleanup: $(OBJS) | submake-libpgport
+pg_archivecleanup: $(OBJS) | submake-libpgport submake-libpgfeutils
 	$(CC) $(CFLAGS) $^ $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@$(X)
 
 install: all installdirs
diff --git a/src/bin/pg_archivecleanup/nls.mk b/src/bin/pg_archivecleanup/nls.mk
index 2cd81d32a7..c2d625c52f 100644
--- a/src/bin/pg_archivecleanup/nls.mk
+++ b/src/bin/pg_archivecleanup/nls.mk
@@ -1,4 +1,6 @@
 # src/bin/pg_archivecleanup/nls.mk
 CATALOG_NAME     = pg_archivecleanup
 AVAIL_LANGUAGES  =de es fr ja ko pl ru sv tr vi
-GETTEXT_FILES    = pg_archivecleanup.c
+GETTEXT_FILES    = $(FRONTEND_COMMON_GETTEXT_FILES) pg_archivecleanup.c
+GETTEXT_TRIGGERS = $(FRONTEND_COMMON_GETTEXT_TRIGGERS)
+GETTEXT_FLAGS    = $(FRONTEND_COMMON_GETTEXT_FLAGS)
diff --git a/src/bin/pg_archivecleanup/pg_archivecleanup.c b/src/bin/pg_archivecleanup/pg_archivecleanup.c
index c62478dbd6..903965cc8b 100644
--- a/src/bin/pg_archivecleanup/pg_archivecleanup.c
+++ b/src/bin/pg_archivecleanup/pg_archivecleanup.c
@@ -17,18 +17,18 @@
 
 #include "pg_getopt.h"
 
+#include "fe_utils/logging.h"
+
 #include "access/xlog_internal.h"
 
 const char *progname;
 
 /* Options and defaults */
-bool		debug = false;		/* are we debugging? */
 bool		dryrun = false;		/* are we performing a dry-run operation? */
 char	   *additional_ext = NULL;	/* Extension to remove from filenames */
 
 char	   *archiveLocation;	/* where to find the archive? */
 char	   *restartWALFileName; /* the file from which we can restart restore */
-char		WALFilePath[MAXPGPATH * 2]; /* the file path including archive */
 char		exclusiveCleanupFileName[MAXFNAMELEN];	/* the oldest file we want
 													 * to remain in archive */
 
@@ -65,8 +65,8 @@ Initialize(void)
 	if (stat(archiveLocation, &stat_buf) != 0 ||
 		!S_ISDIR(stat_buf.st_mode))
 	{
-		fprintf(stderr, _("%s: archive location \"%s\" does not exist\n"),
-				progname, archiveLocation);
+		pg_log_error("archive location \"%s\" does not exist",
+					 archiveLocation);
 		exit(2);
 	}
 }
@@ -123,6 +123,8 @@ CleanupPriorWALFiles(void)
 			if ((IsXLogFileName(walfile) || IsPartialXLogFileName(walfile)) &&
 				strcmp(walfile + 8, exclusiveCleanupFileName + 8) < 0)
 			{
+				char		WALFilePath[MAXPGPATH * 2]; /* the file path including archive */
+
 				/*
 				 * Use the original file name again now, including any
 				 * extension that might have been chopped off before testing
@@ -139,37 +141,32 @@ CleanupPriorWALFiles(void)
 					 * user can pipe the output into some other program.
 					 */
 					printf("%s\n", WALFilePath);
-					if (debug)
-						fprintf(stderr,
-								_("%s: file \"%s\" would be removed\n"),
-								progname, WALFilePath);
+					pg_log_debug("file \"%s\" would be removed", WALFilePath);
 					continue;
 				}
 
-				if (debug)
-					fprintf(stderr, _("%s: removing file \"%s\"\n"),
-							progname, WALFilePath);
+				pg_log_debug("removing file \"%s\"", WALFilePath);
 
 				rc = unlink(WALFilePath);
 				if (rc != 0)
 				{
-					fprintf(stderr, _("%s: ERROR: could not remove file \"%s\": %s\n"),
-							progname, WALFilePath, strerror(errno));
+					pg_log_error("could not remove file \"%s\": %m",
+								 WALFilePath);
 					break;
 				}
 			}
 		}
 
 		if (errno)
-			fprintf(stderr, _("%s: could not read archive location \"%s\": %s\n"),
-					progname, archiveLocation, strerror(errno));
+			pg_log_error("could not read archive location \"%s\": %m",
+						 archiveLocation);
 		if (closedir(xldir))
-			fprintf(stderr, _("%s: could not close archive location \"%s\": %s\n"),
-					progname, archiveLocation, strerror(errno));
+			pg_log_error("could not close archive location \"%s\": %m",
+						 archiveLocation);
 	}
 	else
-		fprintf(stderr, _("%s: could not open archive location \"%s\": %s\n"),
-				progname, archiveLocation, strerror(errno));
+		pg_log_error("could not open archive location \"%s\": %m",
+					 archiveLocation);
 }
 
 /*
@@ -241,7 +238,7 @@ SetWALFileNameForCleanup(void)
 
 	if (!fnameOK)
 	{
-		fprintf(stderr, _("%s: invalid file name argument\n"), progname);
+		pg_log_error("invalid file name argument");
 		fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
 		exit(2);
 	}
@@ -283,6 +280,7 @@ main(int argc, char **argv)
 	int			c;
 
 	set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_archivecleanup"));
+	pg_logging_init(argv[0]);
 	progname = get_progname(argv[0]);
 
 	if (argc > 1)
@@ -304,7 +302,7 @@ main(int argc, char **argv)
 		switch (c)
 		{
 			case 'd':			/* Debug mode */
-				debug = true;
+				pg_logging_set_level(PG_LOG_DEBUG);
 				break;
 			case 'n':			/* Dry-Run mode */
 				dryrun = true;
@@ -334,7 +332,7 @@ main(int argc, char **argv)
 	}
 	else
 	{
-		fprintf(stderr, _("%s: must specify archive location\n"), progname);
+		pg_log_error("must specify archive location");
 		fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
 		exit(2);
 	}
@@ -346,14 +344,14 @@ main(int argc, char **argv)
 	}
 	else
 	{
-		fprintf(stderr, _("%s: must specify oldest kept WAL file\n"), progname);
+		pg_log_error("must specify oldest kept WAL file");
 		fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
 		exit(2);
 	}
 
 	if (optind < argc)
 	{
-		fprintf(stderr, _("%s: too many command-line arguments\n"), progname);
+		pg_log_error("too many command-line arguments");
 		fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
 		exit(2);
 	}
@@ -368,13 +366,8 @@ main(int argc, char **argv)
 	 */
 	SetWALFileNameForCleanup();
 
-	if (debug)
-	{
-		snprintf(WALFilePath, MAXPGPATH, "%s/%s",
+	pg_log_debug("keeping WAL file \"%s/%s\" and later",
 				 archiveLocation, exclusiveCleanupFileName);
-		fprintf(stderr, _("%s: keeping WAL file \"%s\" and later\n"),
-				progname, WALFilePath);
-	}
 
 	/*
 	 * Remove WAL files older than cut-off
diff --git a/src/bin/pg_basebackup/nls.mk b/src/bin/pg_basebackup/nls.mk
index f7694343fc..fece5551bd 100644
--- a/src/bin/pg_basebackup/nls.mk
+++ b/src/bin/pg_basebackup/nls.mk
@@ -1,5 +1,6 @@
 # src/bin/pg_basebackup/nls.mk
 CATALOG_NAME     = pg_basebackup
 AVAIL_LANGUAGES  = de es fr he it ja ko pl pt_BR ru sv tr vi zh_CN
-GETTEXT_FILES    = pg_basebackup.c pg_receivewal.c pg_recvlogical.c receivelog.c streamutil.c walmethods.c ../../common/fe_memutils.c ../../common/file_utils.c
-GETTEXT_TRIGGERS = simple_prompt tar_set_error
+GETTEXT_FILES    = $(FRONTEND_COMMON_GETTEXT_FILES) pg_basebackup.c pg_receivewal.c pg_recvlogical.c receivelog.c streamutil.c walmethods.c ../../common/fe_memutils.c ../../common/file_utils.c
+GETTEXT_TRIGGERS = $(FRONTEND_COMMON_GETTEXT_TRIGGERS) simple_prompt tar_set_error
+GETTEXT_FLAGS    = $(FRONTEND_COMMON_GETTEXT_FLAGS)
diff --git a/src/bin/pg_basebackup/pg_basebackup.c b/src/bin/pg_basebackup/pg_basebackup.c
index e51ef91d66..a6c06432de 100644
--- a/src/bin/pg_basebackup/pg_basebackup.c
+++ b/src/bin/pg_basebackup/pg_basebackup.c
@@ -30,6 +30,7 @@
 #include "common/file_perm.h"
 #include "common/file_utils.h"
 #include "common/string.h"
+#include "fe_utils/logging.h"
 #include "fe_utils/string_utils.h"
 #include "getopt_long.h"
 #include "libpq-fe.h"
@@ -162,57 +163,41 @@ cleanup_directories_atexit(void)
 	{
 		if (made_new_pgdata)
 		{
-			fprintf(stderr, _("%s: removing data directory \"%s\"\n"),
-					progname, basedir);
+			pg_log_info("removing data directory \"%s\"", basedir);
 			if (!rmtree(basedir, true))
-				fprintf(stderr, _("%s: failed to remove data directory\n"),
-						progname);
+				pg_log_error("failed to remove data directory");
 		}
 		else if (found_existing_pgdata)
 		{
-			fprintf(stderr,
-					_("%s: removing contents of data directory \"%s\"\n"),
-					progname, basedir);
+			pg_log_info("removing contents of data directory \"%s\"", basedir);
 			if (!rmtree(basedir, false))
-				fprintf(stderr, _("%s: failed to remove contents of data directory\n"),
-						progname);
+				pg_log_error("failed to remove contents of data directory");
 		}
 
 		if (made_new_xlogdir)
 		{
-			fprintf(stderr, _("%s: removing WAL directory \"%s\"\n"),
-					progname, xlog_dir);
+			pg_log_info("removing WAL directory \"%s\"", xlog_dir);
 			if (!rmtree(xlog_dir, true))
-				fprintf(stderr, _("%s: failed to remove WAL directory\n"),
-						progname);
+				pg_log_error("failed to remove WAL directory");
 		}
 		else if (found_existing_xlogdir)
 		{
-			fprintf(stderr,
-					_("%s: removing contents of WAL directory \"%s\"\n"),
-					progname, xlog_dir);
+			pg_log_info("removing contents of WAL directory \"%s\"", xlog_dir);
 			if (!rmtree(xlog_dir, false))
-				fprintf(stderr, _("%s: failed to remove contents of WAL directory\n"),
-						progname);
+				pg_log_error("failed to remove contents of WAL directory");
 		}
 	}
 	else
 	{
 		if ((made_new_pgdata || found_existing_pgdata) && !checksum_failure)
-			fprintf(stderr,
-					_("%s: data directory \"%s\" not removed at user's request\n"),
-					progname, basedir);
+			pg_log_info("data directory \"%s\" not removed at user's request", basedir);
 
 		if (made_new_xlogdir || found_existing_xlogdir)
-			fprintf(stderr,
-					_("%s: WAL directory \"%s\" not removed at user's request\n"),
-					progname, xlog_dir);
+			pg_log_info("WAL directory \"%s\" not removed at user's request", xlog_dir);
 	}
 
 	if ((made_tablespace_dirs || found_tablespace_dirs) && !checksum_failure)
-		fprintf(stderr,
-				_("%s: changes to tablespace directories will not be undone\n"),
-				progname);
+		pg_log_info("changes to tablespace directories will not be undone");
 }
 
 static void
@@ -253,7 +238,7 @@ tablespace_list_append(const char *arg)
 	{
 		if (dst_ptr - dst >= MAXPGPATH)
 		{
-			fprintf(stderr, _("%s: directory name too long\n"), progname);
+			pg_log_error("directory name too long");
 			exit(1);
 		}
 
@@ -263,7 +248,7 @@ tablespace_list_append(const char *arg)
 		{
 			if (*cell->new_dir)
 			{
-				fprintf(stderr, _("%s: multiple \"=\" signs in tablespace mapping\n"), progname);
+				pg_log_error("multiple \"=\" signs in tablespace mapping");
 				exit(1);
 			}
 			else
@@ -275,9 +260,7 @@ tablespace_list_append(const char *arg)
 
 	if (!*cell->old_dir || !*cell->new_dir)
 	{
-		fprintf(stderr,
-				_("%s: invalid tablespace mapping format \"%s\", must be \"OLDDIR=NEWDIR\"\n"),
-				progname, arg);
+		pg_log_error("invalid tablespace mapping format \"%s\", must be \"OLDDIR=NEWDIR\"", arg);
 		exit(1);
 	}
 
@@ -289,15 +272,15 @@ tablespace_list_append(const char *arg)
 	 */
 	if (!is_absolute_path(cell->old_dir))
 	{
-		fprintf(stderr, _("%s: old directory is not an absolute path in tablespace mapping: %s\n"),
-				progname, cell->old_dir);
+		pg_log_error("old directory is not an absolute path in tablespace mapping: %s",
+					 cell->old_dir);
 		exit(1);
 	}
 
 	if (!is_absolute_path(cell->new_dir))
 	{
-		fprintf(stderr, _("%s: new directory is not an absolute path in tablespace mapping: %s\n"),
-				progname, cell->new_dir);
+		pg_log_error("new directory is not an absolute path in tablespace mapping: %s",
+					 cell->new_dir);
 		exit(1);
 	}
 
@@ -420,16 +403,14 @@ reached_end_position(XLogRecPtr segendpos, uint32 timeline,
 			r = read(bgpipe[0], xlogend, sizeof(xlogend) - 1);
 			if (r < 0)
 			{
-				fprintf(stderr, _("%s: could not read from ready pipe: %s\n"),
-						progname, strerror(errno));
+				pg_log_error("could not read from ready pipe: %m");
 				exit(1);
 			}
 
 			if (sscanf(xlogend, "%X/%X", &hi, &lo) != 2)
 			{
-				fprintf(stderr,
-						_("%s: could not parse write-ahead log location \"%s\"\n"),
-						progname, xlogend);
+				pg_log_error("could not parse write-ahead log location \"%s\"",
+							 xlogend);
 				exit(1);
 			}
 			xlogendptr = ((uint64) hi) << 32 | lo;
@@ -521,9 +502,7 @@ LogStreamerMain(logstreamer_param *param)
 
 	if (!stream.walmethod->finish())
 	{
-		fprintf(stderr,
-				_("%s: could not finish writing WAL files: %s\n"),
-				progname, strerror(errno));
+		pg_log_error("could not finish writing WAL files: %m");
 		return 1;
 	}
 
@@ -558,9 +537,8 @@ StartLogStreamer(char *startpos, uint32 timeline, char *sysidentifier)
 	/* Convert the starting position */
 	if (sscanf(startpos, "%X/%X", &hi, &lo) != 2)
 	{
-		fprintf(stderr,
-				_("%s: could not parse write-ahead log location \"%s\"\n"),
-				progname, startpos);
+		pg_log_error("could not parse write-ahead log location \"%s\"",
+					 startpos);
 		exit(1);
 	}
 	param->startptr = ((uint64) hi) << 32 | lo;
@@ -571,9 +549,7 @@ StartLogStreamer(char *startpos, uint32 timeline, char *sysidentifier)
 	/* Create our background pipe */
 	if (pipe(bgpipe) < 0)
 	{
-		fprintf(stderr,
-				_("%s: could not create pipe for background process: %s\n"),
-				progname, strerror(errno));
+		pg_log_error("could not create pipe for background process: %m");
 		exit(1);
 	}
 #endif
@@ -608,11 +584,11 @@ StartLogStreamer(char *startpos, uint32 timeline, char *sysidentifier)
 		if (verbose)
 		{
 			if (temp_replication_slot)
-				fprintf(stderr, _("%s: created temporary replication slot \"%s\"\n"),
-						progname, replication_slot);
+				pg_log_info("created temporary replication slot \"%s\"",
+							replication_slot);
 			else
-				fprintf(stderr, _("%s: created replication slot \"%s\"\n"),
-						progname, replication_slot);
+				pg_log_info("created replication slot \"%s\"",
+							replication_slot);
 		}
 	}
 
@@ -631,9 +607,7 @@ StartLogStreamer(char *startpos, uint32 timeline, char *sysidentifier)
 
 		if (pg_mkdir_p(statusdir, pg_dir_create_mode) != 0 && errno != EEXIST)
 		{
-			fprintf(stderr,
-					_("%s: could not create directory \"%s\": %s\n"),
-					progname, statusdir, strerror(errno));
+			pg_log_error("could not create directory \"%s\": %m", statusdir);
 			exit(1);
 		}
 	}
@@ -651,8 +625,7 @@ StartLogStreamer(char *startpos, uint32 timeline, char *sysidentifier)
 	}
 	else if (bgchild < 0)
 	{
-		fprintf(stderr, _("%s: could not create background process: %s\n"),
-				progname, strerror(errno));
+		pg_log_error("could not create background process: %m");
 		exit(1);
 	}
 
@@ -664,8 +637,7 @@ StartLogStreamer(char *startpos, uint32 timeline, char *sysidentifier)
 	bgchild = _beginthreadex(NULL, 0, (void *) LogStreamerMain, param, 0, NULL);
 	if (bgchild == 0)
 	{
-		fprintf(stderr, _("%s: could not create background thread: %s\n"),
-				progname, strerror(errno));
+		pg_log_error("could not create background thread: %m");
 		exit(1);
 	}
 #endif
@@ -688,9 +660,7 @@ verify_dir_is_empty_or_create(char *dirname, bool *created, bool *found)
 			 */
 			if (pg_mkdir_p(dirname, pg_dir_create_mode) == -1)
 			{
-				fprintf(stderr,
-						_("%s: could not create directory \"%s\": %s\n"),
-						progname, dirname, strerror(errno));
+				pg_log_error("could not create directory \"%s\": %m", dirname);
 				exit(1);
 			}
 			if (created)
@@ -711,17 +681,14 @@ verify_dir_is_empty_or_create(char *dirname, bool *created, bool *found)
 			/*
 			 * Exists, not empty
 			 */
-			fprintf(stderr,
-					_("%s: directory \"%s\" exists but is not empty\n"),
-					progname, dirname);
+			pg_log_error("directory \"%s\" exists but is not empty", dirname);
 			exit(1);
 		case -1:
 
 			/*
 			 * Access problem
 			 */
-			fprintf(stderr, _("%s: could not access directory \"%s\": %s\n"),
-					progname, dirname, strerror(errno));
+			pg_log_error("could not access directory \"%s\": %m", dirname);
 			exit(1);
 	}
 }
@@ -834,16 +801,12 @@ parse_max_rate(char *src)
 	result = strtod(src, &after_num);
 	if (src == after_num)
 	{
-		fprintf(stderr,
-				_("%s: transfer rate \"%s\" is not a valid value\n"),
-				progname, src);
+		pg_log_error("transfer rate \"%s\" is not a valid value", src);
 		exit(1);
 	}
 	if (errno != 0)
 	{
-		fprintf(stderr,
-				_("%s: invalid transfer rate \"%s\": %s\n"),
-				progname, src, strerror(errno));
+		pg_log_error("invalid transfer rate \"%s\": %m", src);
 		exit(1);
 	}
 
@@ -852,8 +815,7 @@ parse_max_rate(char *src)
 		/*
 		 * Reject obviously wrong values here.
 		 */
-		fprintf(stderr, _("%s: transfer rate must be greater than zero\n"),
-				progname);
+		pg_log_error("transfer rate must be greater than zero");
 		exit(1);
 	}
 
@@ -885,18 +847,14 @@ parse_max_rate(char *src)
 
 	if (*after_num != '\0')
 	{
-		fprintf(stderr,
-				_("%s: invalid --max-rate unit: \"%s\"\n"),
-				progname, suffix);
+		pg_log_error("invalid --max-rate unit: \"%s\"", suffix);
 		exit(1);
 	}
 
 	/* Valid integer? */
 	if ((uint64) result != (uint64) ((uint32) result))
 	{
-		fprintf(stderr,
-				_("%s: transfer rate \"%s\" exceeds integer range\n"),
-				progname, src);
+		pg_log_error("transfer rate \"%s\" exceeds integer range", src);
 		exit(1);
 	}
 
@@ -906,9 +864,7 @@ parse_max_rate(char *src)
 	 */
 	if (result < MAX_RATE_LOWER || result > MAX_RATE_UPPER)
 	{
-		fprintf(stderr,
-				_("%s: transfer rate \"%s\" is out of range\n"),
-				progname, src);
+		pg_log_error("transfer rate \"%s\" is out of range", src);
 		exit(1);
 	}
 
@@ -930,9 +886,8 @@ writeTarData(
 	{
 		if (gzwrite(ztarfile, buf, r) != r)
 		{
-			fprintf(stderr,
-					_("%s: could not write to compressed file \"%s\": %s\n"),
-					progname, current_file, get_gz_error(ztarfile));
+			pg_log_error("could not write to compressed file \"%s\": %s",
+						 current_file, get_gz_error(ztarfile));
 			exit(1);
 		}
 	}
@@ -941,8 +896,7 @@ writeTarData(
 	{
 		if (fwrite(buf, r, 1, tarfile) != 1)
 		{
-			fprintf(stderr, _("%s: could not write to file \"%s\": %s\n"),
-					progname, current_file, strerror(errno));
+			pg_log_error("could not write to file \"%s\": %m", current_file);
 			exit(1);
 		}
 	}
@@ -1002,9 +956,8 @@ ReceiveTarFile(PGconn *conn, PGresult *res, int rownum)
 				if (gzsetparams(ztarfile, compresslevel,
 								Z_DEFAULT_STRATEGY) != Z_OK)
 				{
-					fprintf(stderr,
-							_("%s: could not set compression level %d: %s\n"),
-							progname, compresslevel, get_gz_error(ztarfile));
+					pg_log_error("could not set compression level %d: %s",
+								 compresslevel, get_gz_error(ztarfile));
 					exit(1);
 				}
 			}
@@ -1023,9 +976,8 @@ ReceiveTarFile(PGconn *conn, PGresult *res, int rownum)
 				if (gzsetparams(ztarfile, compresslevel,
 								Z_DEFAULT_STRATEGY) != Z_OK)
 				{
-					fprintf(stderr,
-							_("%s: could not set compression level %d: %s\n"),
-							progname, compresslevel, get_gz_error(ztarfile));
+					pg_log_error("could not set compression level %d: %s",
+								 compresslevel, get_gz_error(ztarfile));
 					exit(1);
 				}
 			}
@@ -1051,9 +1003,8 @@ ReceiveTarFile(PGconn *conn, PGresult *res, int rownum)
 			if (gzsetparams(ztarfile, compresslevel,
 							Z_DEFAULT_STRATEGY) != Z_OK)
 			{
-				fprintf(stderr,
-						_("%s: could not set compression level %d: %s\n"),
-						progname, compresslevel, get_gz_error(ztarfile));
+				pg_log_error("could not set compression level %d: %s",
+							 compresslevel, get_gz_error(ztarfile));
 				exit(1);
 			}
 		}
@@ -1072,9 +1023,8 @@ ReceiveTarFile(PGconn *conn, PGresult *res, int rownum)
 		if (!ztarfile)
 		{
 			/* Compression is in use */
-			fprintf(stderr,
-					_("%s: could not create compressed file \"%s\": %s\n"),
-					progname, filename, get_gz_error(ztarfile));
+			pg_log_error("could not create compressed file \"%s\": %s",
+						 filename, get_gz_error(ztarfile));
 			exit(1);
 		}
 	}
@@ -1084,8 +1034,7 @@ ReceiveTarFile(PGconn *conn, PGresult *res, int rownum)
 		/* Either no zlib support, or zlib support but compresslevel = 0 */
 		if (!tarfile)
 		{
-			fprintf(stderr, _("%s: could not create file \"%s\": %s\n"),
-					progname, filename, strerror(errno));
+			pg_log_error("could not create file \"%s\": %m", filename);
 			exit(1);
 		}
 	}
@@ -1096,8 +1045,8 @@ ReceiveTarFile(PGconn *conn, PGresult *res, int rownum)
 	res = PQgetResult(conn);
 	if (PQresultStatus(res) != PGRES_COPY_OUT)
 	{
-		fprintf(stderr, _("%s: could not get COPY data stream: %s"),
-				progname, PQerrorMessage(conn));
+		pg_log_error("could not get COPY data stream: %s",
+					 PQerrorMessage(conn));
 		exit(1);
 	}
 
@@ -1164,9 +1113,8 @@ ReceiveTarFile(PGconn *conn, PGresult *res, int rownum)
 			{
 				if (gzclose(ztarfile) != 0)
 				{
-					fprintf(stderr,
-							_("%s: could not close compressed file \"%s\": %s\n"),
-							progname, filename, get_gz_error(ztarfile));
+					pg_log_error("could not close compressed file \"%s\": %s",
+								 filename, get_gz_error(ztarfile));
 					exit(1);
 				}
 			}
@@ -1177,9 +1125,8 @@ ReceiveTarFile(PGconn *conn, PGresult *res, int rownum)
 				{
 					if (fclose(tarfile) != 0)
 					{
-						fprintf(stderr,
-								_("%s: could not close file \"%s\": %s\n"),
-								progname, filename, strerror(errno));
+						pg_log_error("could not close file \"%s\": %m",
+									 filename);
 						exit(1);
 					}
 				}
@@ -1189,8 +1136,8 @@ ReceiveTarFile(PGconn *conn, PGresult *res, int rownum)
 		}
 		else if (r == -2)
 		{
-			fprintf(stderr, _("%s: could not read COPY data: %s"),
-					progname, PQerrorMessage(conn));
+			pg_log_error("could not read COPY data: %s",
+						 PQerrorMessage(conn));
 			exit(1);
 		}
 
@@ -1364,7 +1311,7 @@ ReceiveTarFile(PGconn *conn, PGresult *res, int rownum)
 
 	/* sync the resulting tar file, errors are not considered fatal */
 	if (do_sync && strcmp(basedir, "-") != 0)
-		(void) fsync_fname(filename, false, progname);
+		(void) fsync_fname(filename, false);
 }
 
 
@@ -1425,8 +1372,8 @@ ReceiveAndUnpackTarFile(PGconn *conn, PGresult *res, int rownum)
 	res = PQgetResult(conn);
 	if (PQresultStatus(res) != PGRES_COPY_OUT)
 	{
-		fprintf(stderr, _("%s: could not get COPY data stream: %s"),
-				progname, PQerrorMessage(conn));
+		pg_log_error("could not get COPY data stream: %s",
+					 PQerrorMessage(conn));
 		exit(1);
 	}
 
@@ -1454,8 +1401,8 @@ ReceiveAndUnpackTarFile(PGconn *conn, PGresult *res, int rownum)
 		}
 		else if (r == -2)
 		{
-			fprintf(stderr, _("%s: could not read COPY data: %s"),
-					progname, PQerrorMessage(conn));
+			pg_log_error("could not read COPY data: %s",
+						 PQerrorMessage(conn));
 			exit(1);
 		}
 
@@ -1468,8 +1415,7 @@ ReceiveAndUnpackTarFile(PGconn *conn, PGresult *res, int rownum)
 			 */
 			if (r != 512)
 			{
-				fprintf(stderr, _("%s: invalid tar block header size: %d\n"),
-						progname, r);
+				pg_log_error("invalid tar block header size: %d", r);
 				exit(1);
 			}
 			totaldone += 512;
@@ -1517,17 +1463,15 @@ ReceiveAndUnpackTarFile(PGconn *conn, PGresult *res, int rownum)
 							   pg_str_endswith(filename, "/archive_status")) &&
 							  errno == EEXIST))
 						{
-							fprintf(stderr,
-									_("%s: could not create directory \"%s\": %s\n"),
-									progname, filename, strerror(errno));
+							pg_log_error("could not create directory \"%s\": %m",
+										 filename);
 							exit(1);
 						}
 					}
 #ifndef WIN32
 					if (chmod(filename, (mode_t) filemode))
-						fprintf(stderr,
-								_("%s: could not set permissions on directory \"%s\": %s\n"),
-								progname, filename, strerror(errno));
+						pg_log_error("could not set permissions on directory \"%s\": %m",
+									 filename);
 #endif
 				}
 				else if (copybuf[156] == '2')
@@ -1549,18 +1493,15 @@ ReceiveAndUnpackTarFile(PGconn *conn, PGresult *res, int rownum)
 					mapped_tblspc_path = get_tablespace_mapping(&copybuf[157]);
 					if (symlink(mapped_tblspc_path, filename) != 0)
 					{
-						fprintf(stderr,
-								_("%s: could not create symbolic link from \"%s\" to \"%s\": %s\n"),
-								progname, filename, mapped_tblspc_path,
-								strerror(errno));
+						pg_log_error("could not create symbolic link from \"%s\" to \"%s\": %m",
+									 filename, mapped_tblspc_path);
 						exit(1);
 					}
 				}
 				else
 				{
-					fprintf(stderr,
-							_("%s: unrecognized link indicator \"%c\"\n"),
-							progname, copybuf[156]);
+					pg_log_error("unrecognized link indicator \"%c\"",
+								 copybuf[156]);
 					exit(1);
 				}
 				continue;		/* directory or link handled */
@@ -1572,15 +1513,14 @@ ReceiveAndUnpackTarFile(PGconn *conn, PGresult *res, int rownum)
 			file = fopen(filename, "wb");
 			if (!file)
 			{
-				fprintf(stderr, _("%s: could not create file \"%s\": %s\n"),
-						progname, filename, strerror(errno));
+				pg_log_error("could not create file \"%s\": %m", filename);
 				exit(1);
 			}
 
 #ifndef WIN32
 			if (chmod(filename, (mode_t) filemode))
-				fprintf(stderr, _("%s: could not set permissions on file \"%s\": %s\n"),
-						progname, filename, strerror(errno));
+				pg_log_error("could not set permissions on file \"%s\": %m",
+							 filename);
 #endif
 
 			if (current_len_left == 0)
@@ -1612,8 +1552,7 @@ ReceiveAndUnpackTarFile(PGconn *conn, PGresult *res, int rownum)
 
 			if (fwrite(copybuf, r, 1, file) != 1)
 			{
-				fprintf(stderr, _("%s: could not write to file \"%s\": %s\n"),
-						progname, filename, strerror(errno));
+				pg_log_error("could not write to file \"%s\": %m", filename);
 				exit(1);
 			}
 			totaldone += r;
@@ -1637,9 +1576,7 @@ ReceiveAndUnpackTarFile(PGconn *conn, PGresult *res, int rownum)
 
 	if (file != NULL)
 	{
-		fprintf(stderr,
-				_("%s: COPY stream ended before last file was finished\n"),
-				progname);
+		pg_log_error("COPY stream ended before last file was finished");
 		exit(1);
 	}
 
@@ -1666,7 +1603,7 @@ escape_quotes(const char *src)
 
 	if (!result)
 	{
-		fprintf(stderr, _("%s: out of memory\n"), progname);
+		pg_log_error("out of memory");
 		exit(1);
 	}
 	return result;
@@ -1686,14 +1623,14 @@ GenerateRecoveryConf(PGconn *conn)
 	recoveryconfcontents = createPQExpBuffer();
 	if (!recoveryconfcontents)
 	{
-		fprintf(stderr, _("%s: out of memory\n"), progname);
+		pg_log_error("out of memory");
 		exit(1);
 	}
 
 	connOptions = PQconninfo(conn);
 	if (connOptions == NULL)
 	{
-		fprintf(stderr, _("%s: out of memory\n"), progname);
+		pg_log_error("out of memory");
 		exit(1);
 	}
 
@@ -1744,7 +1681,7 @@ GenerateRecoveryConf(PGconn *conn)
 	if (PQExpBufferBroken(recoveryconfcontents) ||
 		PQExpBufferDataBroken(conninfo_buf))
 	{
-		fprintf(stderr, _("%s: out of memory\n"), progname);
+		pg_log_error("out of memory");
 		exit(1);
 	}
 
@@ -1770,15 +1707,13 @@ WriteRecoveryConf(void)
 	cf = fopen(filename, "a");
 	if (cf == NULL)
 	{
-		fprintf(stderr, _("%s: could not open file \"%s\": %s\n"), progname, filename, strerror(errno));
+		pg_log_error("could not open file \"%s\": %m", filename);
 		exit(1);
 	}
 
 	if (fwrite(recoveryconfcontents->data, recoveryconfcontents->len, 1, cf) != 1)
 	{
-		fprintf(stderr,
-				_("%s: could not write to file \"%s\": %s\n"),
-				progname, filename, strerror(errno));
+		pg_log_error("could not write to file \"%s\": %m", filename);
 		exit(1);
 	}
 
@@ -1788,7 +1723,7 @@ WriteRecoveryConf(void)
 	cf = fopen(filename, "w");
 	if (cf == NULL)
 	{
-		fprintf(stderr, _("%s: could not create file \"%s\": %s\n"), progname, filename, strerror(errno));
+		pg_log_error("could not create file \"%s\": %m", filename);
 		exit(1);
 	}
 
@@ -1828,8 +1763,8 @@ BaseBackup(void)
 	{
 		const char *serverver = PQparameterStatus(conn, "server_version");
 
-		fprintf(stderr, _("%s: incompatible server version %s\n"),
-				progname, serverver ? serverver : "'unknown'");
+		pg_log_error("incompatible server version %s",
+					 serverver ? serverver : "'unknown'");
 		exit(1);
 	}
 
@@ -1843,7 +1778,7 @@ BaseBackup(void)
 		 * Error message already written in CheckServerVersionForStreaming(),
 		 * but add a hint about using -X none.
 		 */
-		fprintf(stderr, _("HINT: use -X none or -X fetch to disable log streaming\n"));
+		pg_log_info("HINT: use -X none or -X fetch to disable log streaming");
 		exit(1);
 	}
 
@@ -1868,9 +1803,7 @@ BaseBackup(void)
 		maxrate_clause = psprintf("MAX_RATE %u", maxrate);
 
 	if (verbose)
-		fprintf(stderr,
-				_("%s: initiating base backup, waiting for checkpoint to complete\n"),
-				progname);
+		pg_log_info("initiating base backup, waiting for checkpoint to complete");
 
 	if (showprogress && !verbose)
 	{
@@ -1894,8 +1827,8 @@ BaseBackup(void)
 
 	if (PQsendQuery(conn, basebkp) == 0)
 	{
-		fprintf(stderr, _("%s: could not send replication command \"%s\": %s"),
-				progname, "BASE_BACKUP", PQerrorMessage(conn));
+		pg_log_error("could not send replication command \"%s\": %s",
+					 "BASE_BACKUP", PQerrorMessage(conn));
 		exit(1);
 	}
 
@@ -1905,22 +1838,21 @@ BaseBackup(void)
 	res = PQgetResult(conn);
 	if (PQresultStatus(res) != PGRES_TUPLES_OK)
 	{
-		fprintf(stderr, _("%s: could not initiate base backup: %s"),
-				progname, PQerrorMessage(conn));
+		pg_log_error("could not initiate base backup: %s",
+					 PQerrorMessage(conn));
 		exit(1);
 	}
 	if (PQntuples(res) != 1)
 	{
-		fprintf(stderr,
-				_("%s: server returned unexpected response to BASE_BACKUP command; got %d rows and %d fields, expected %d rows and %d fields\n"),
-				progname, PQntuples(res), PQnfields(res), 1, 2);
+		pg_log_error("server returned unexpected response to BASE_BACKUP command; got %d rows and %d fields, expected %d rows and %d fields",
+					 PQntuples(res), PQnfields(res), 1, 2);
 		exit(1);
 	}
 
 	strlcpy(xlogstart, PQgetvalue(res, 0, 0), sizeof(xlogstart));
 
 	if (verbose)
-		fprintf(stderr, _("%s: checkpoint completed\n"), progname);
+		pg_log_info("checkpoint completed");
 
 	/*
 	 * 9.3 and later sends the TLI of the starting point. With older servers,
@@ -1935,8 +1867,8 @@ BaseBackup(void)
 	MemSet(xlogend, 0, sizeof(xlogend));
 
 	if (verbose && includewal != NO_WAL)
-		fprintf(stderr, _("%s: write-ahead log start point: %s on timeline %u\n"),
-				progname, xlogstart, starttli);
+		pg_log_info("write-ahead log start point: %s on timeline %u",
+					xlogstart, starttli);
 
 	/*
 	 * Get the header
@@ -1944,13 +1876,13 @@ BaseBackup(void)
 	res = PQgetResult(conn);
 	if (PQresultStatus(res) != PGRES_TUPLES_OK)
 	{
-		fprintf(stderr, _("%s: could not get backup header: %s"),
-				progname, PQerrorMessage(conn));
+		pg_log_error("could not get backup header: %s",
+					 PQerrorMessage(conn));
 		exit(1);
 	}
 	if (PQntuples(res) < 1)
 	{
-		fprintf(stderr, _("%s: no data returned from server\n"), progname);
+		pg_log_error("no data returned from server");
 		exit(1);
 	}
 
@@ -1981,9 +1913,8 @@ BaseBackup(void)
 	 */
 	if (format == 't' && strcmp(basedir, "-") == 0 && PQntuples(res) > 1)
 	{
-		fprintf(stderr,
-				_("%s: can only write single tablespace to stdout, database has %d\n"),
-				progname, PQntuples(res));
+		pg_log_error("can only write single tablespace to stdout, database has %d",
+					 PQntuples(res));
 		exit(1);
 	}
 
@@ -1994,8 +1925,7 @@ BaseBackup(void)
 	if (includewal == STREAM_WAL)
 	{
 		if (verbose)
-			fprintf(stderr, _("%s: starting background WAL receiver\n"),
-					progname);
+			pg_log_info("starting background WAL receiver");
 		StartLogStreamer(xlogstart, starttli, sysidentifier);
 	}
 
@@ -2025,21 +1955,18 @@ BaseBackup(void)
 	res = PQgetResult(conn);
 	if (PQresultStatus(res) != PGRES_TUPLES_OK)
 	{
-		fprintf(stderr,
-				_("%s: could not get write-ahead log end position from server: %s"),
-				progname, PQerrorMessage(conn));
+		pg_log_error("could not get write-ahead log end position from server: %s",
+					 PQerrorMessage(conn));
 		exit(1);
 	}
 	if (PQntuples(res) != 1)
 	{
-		fprintf(stderr,
-				_("%s: no write-ahead log end position returned from server\n"),
-				progname);
+		pg_log_error("no write-ahead log end position returned from server");
 		exit(1);
 	}
 	strlcpy(xlogend, PQgetvalue(res, 0, 0), sizeof(xlogend));
 	if (verbose && includewal != NO_WAL)
-		fprintf(stderr, _("%s: write-ahead log end point: %s\n"), progname, xlogend);
+		pg_log_info("write-ahead log end point: %s", xlogend);
 	PQclear(res);
 
 	res = PQgetResult(conn);
@@ -2050,14 +1977,13 @@ BaseBackup(void)
 		if (sqlstate &&
 			strcmp(sqlstate, ERRCODE_DATA_CORRUPTED) == 0)
 		{
-			fprintf(stderr, _("%s: checksum error occurred\n"),
-					progname);
+			pg_log_error("checksum error occurred");
 			checksum_failure = true;
 		}
 		else
 		{
-			fprintf(stderr, _("%s: final receive failed: %s"),
-					progname, PQerrorMessage(conn));
+			pg_log_error("final receive failed: %s",
+						 PQerrorMessage(conn));
 		}
 		exit(1);
 	}
@@ -2080,15 +2006,12 @@ BaseBackup(void)
 #endif
 
 		if (verbose)
-			fprintf(stderr,
-					_("%s: waiting for background process to finish streaming ...\n"), progname);
+			pg_log_info("waiting for background process to finish streaming ...");
 
 #ifndef WIN32
 		if (write(bgpipe[1], xlogend, strlen(xlogend)) != strlen(xlogend))
 		{
-			fprintf(stderr,
-					_("%s: could not send command to background pipe: %s\n"),
-					progname, strerror(errno));
+			pg_log_info("could not send command to background pipe: %m");
 			exit(1);
 		}
 
@@ -2096,20 +2019,17 @@ BaseBackup(void)
 		r = waitpid(bgchild, &status, 0);
 		if (r == (pid_t) -1)
 		{
-			fprintf(stderr, _("%s: could not wait for child process: %s\n"),
-					progname, strerror(errno));
+			pg_log_error("could not wait for child process: %m");
 			exit(1);
 		}
 		if (r != bgchild)
 		{
-			fprintf(stderr, _("%s: child %d died, expected %d\n"),
-					progname, (int) r, (int) bgchild);
+			pg_log_error("child %d died, expected %d", (int) r, (int) bgchild);
 			exit(1);
 		}
 		if (status != 0)
 		{
-			fprintf(stderr, "%s: %s\n",
-					progname, wait_result_to_str(status));
+			pg_log_error("%s", wait_result_to_str(status));
 			exit(1);
 		}
 		/* Exited normally, we're happy! */
@@ -2122,9 +2042,8 @@ BaseBackup(void)
 		 */
 		if (sscanf(xlogend, "%X/%X", &hi, &lo) != 2)
 		{
-			fprintf(stderr,
-					_("%s: could not parse write-ahead log location \"%s\"\n"),
-					progname, xlogend);
+			pg_log_error("could not parse write-ahead log location \"%s\"",
+						 xlogend);
 			exit(1);
 		}
 		xlogendptr = ((uint64) hi) << 32 | lo;
@@ -2135,21 +2054,19 @@ BaseBackup(void)
 			WAIT_OBJECT_0)
 		{
 			_dosmaperr(GetLastError());
-			fprintf(stderr, _("%s: could not wait for child thread: %s\n"),
-					progname, strerror(errno));
+			pg_log_error("could not wait for child thread: %m");
 			exit(1);
 		}
 		if (GetExitCodeThread((HANDLE) bgchild_handle, &status) == 0)
 		{
 			_dosmaperr(GetLastError());
-			fprintf(stderr, _("%s: could not get child thread exit status: %s\n"),
-					progname, strerror(errno));
+			pg_log_error("could not get child thread exit status: %m");
 			exit(1);
 		}
 		if (status != 0)
 		{
-			fprintf(stderr, _("%s: child thread exited with error %u\n"),
-					progname, (unsigned int) status);
+			pg_log_error("child thread exited with error %u",
+						 (unsigned int) status);
 			exit(1);
 		}
 		/* Exited normally, we're happy */
@@ -2176,21 +2093,20 @@ BaseBackup(void)
 	if (do_sync)
 	{
 		if (verbose)
-			fprintf(stderr,
-					_("%s: syncing data to disk ...\n"), progname);
+			pg_log_info("syncing data to disk ...");
 		if (format == 't')
 		{
 			if (strcmp(basedir, "-") != 0)
-				(void) fsync_fname(basedir, true, progname);
+				(void) fsync_fname(basedir, true);
 		}
 		else
 		{
-			(void) fsync_pgdata(basedir, progname, serverVersion);
+			(void) fsync_pgdata(basedir, serverVersion);
 		}
 	}
 
 	if (verbose)
-		fprintf(stderr, _("%s: base backup completed\n"), progname);
+		pg_log_info("base backup completed");
 }
 
 
@@ -2234,6 +2150,7 @@ main(int argc, char **argv)
 
 	progname = get_progname(argv[0]);
 	set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_basebackup"));
+	pg_logging_init(argv[0]);
 
 	if (argc > 1)
 	{
@@ -2270,9 +2187,8 @@ main(int argc, char **argv)
 					format = 't';
 				else
 				{
-					fprintf(stderr,
-							_("%s: invalid output format \"%s\", must be \"plain\" or \"tar\"\n"),
-							progname, optarg);
+					pg_log_error("invalid output format \"%s\", must be \"plain\" or \"tar\"\n",
+								 optarg);
 					exit(1);
 				}
 				break;
@@ -2315,9 +2231,8 @@ main(int argc, char **argv)
 				}
 				else
 				{
-					fprintf(stderr,
-							_("%s: invalid wal-method option \"%s\", must be \"fetch\", \"stream\", or \"none\"\n"),
-							progname, optarg);
+					pg_log_error("invalid wal-method option \"%s\", must be \"fetch\", \"stream\", or \"none\"",
+								 optarg);
 					exit(1);
 				}
 				break;
@@ -2344,8 +2259,7 @@ main(int argc, char **argv)
 				compresslevel = atoi(optarg);
 				if (compresslevel < 0 || compresslevel > 9)
 				{
-					fprintf(stderr, _("%s: invalid compression level \"%s\"\n"),
-							progname, optarg);
+					pg_log_error("invalid compression level \"%s\"\n", optarg);
 					exit(1);
 				}
 				break;
@@ -2356,8 +2270,8 @@ main(int argc, char **argv)
 					fastcheckpoint = false;
 				else
 				{
-					fprintf(stderr, _("%s: invalid checkpoint argument \"%s\", must be \"fast\" or \"spread\"\n"),
-							progname, optarg);
+					pg_log_error("invalid checkpoint argument \"%s\", must be \"fast\" or \"spread\"",
+								 optarg);
 					exit(1);
 				}
 				break;
@@ -2383,8 +2297,7 @@ main(int argc, char **argv)
 				standby_message_timeout = atoi(optarg) * 1000;
 				if (standby_message_timeout < 0)
 				{
-					fprintf(stderr, _("%s: invalid status interval \"%s\"\n"),
-							progname, optarg);
+					pg_log_error("invalid status interval \"%s\"", optarg);
 					exit(1);
 				}
 				break;
@@ -2413,9 +2326,8 @@ main(int argc, char **argv)
 	 */
 	if (optind < argc)
 	{
-		fprintf(stderr,
-				_("%s: too many command-line arguments (first is \"%s\")\n"),
-				progname, argv[optind]);
+		pg_log_error("too many command-line arguments (first is \"%s\")",
+					 argv[optind]);
 		fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
 				progname);
 		exit(1);
@@ -2426,7 +2338,7 @@ main(int argc, char **argv)
 	 */
 	if (basedir == NULL)
 	{
-		fprintf(stderr, _("%s: no target directory specified\n"), progname);
+		pg_log_error("no target directory specified");
 		fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
 				progname);
 		exit(1);
@@ -2437,9 +2349,7 @@ main(int argc, char **argv)
 	 */
 	if (format == 'p' && compresslevel != 0)
 	{
-		fprintf(stderr,
-				_("%s: only tar mode backups can be compressed\n"),
-				progname);
+		pg_log_error("only tar mode backups can be compressed");
 		fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
 				progname);
 		exit(1);
@@ -2447,9 +2357,7 @@ main(int argc, char **argv)
 
 	if (format == 't' && includewal == STREAM_WAL && strcmp(basedir, "-") == 0)
 	{
-		fprintf(stderr,
-				_("%s: cannot stream write-ahead logs in tar mode to stdout\n"),
-				progname);
+		pg_log_error("cannot stream write-ahead logs in tar mode to stdout");
 		fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
 				progname);
 		exit(1);
@@ -2457,9 +2365,7 @@ main(int argc, char **argv)
 
 	if (replication_slot && includewal != STREAM_WAL)
 	{
-		fprintf(stderr,
-				_("%s: replication slots can only be used with WAL streaming\n"),
-				progname);
+		pg_log_error("replication slots can only be used with WAL streaming");
 		fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
 				progname);
 		exit(1);
@@ -2469,9 +2375,7 @@ main(int argc, char **argv)
 	{
 		if (replication_slot)
 		{
-			fprintf(stderr,
-					_("%s: --no-slot cannot be used with slot name\n"),
-					progname);
+			pg_log_error("--no-slot cannot be used with slot name");
 			fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
 					progname);
 			exit(1);
@@ -2483,9 +2387,8 @@ main(int argc, char **argv)
 	{
 		if (!replication_slot)
 		{
-			fprintf(stderr,
-					_("%s: %s needs a slot to be specified using --slot\n"),
-					progname, "--create-slot");
+			pg_log_error("%s needs a slot to be specified using --slot",
+						 "--create-slot");
 			fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
 					progname);
 			exit(1);
@@ -2493,9 +2396,7 @@ main(int argc, char **argv)
 
 		if (no_slot)
 		{
-			fprintf(stderr,
-					_("%s: --create-slot and --no-slot are incompatible options\n"),
-					progname);
+			pg_log_error("--create-slot and --no-slot are incompatible options");
 			fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
 					progname);
 			exit(1);
@@ -2506,9 +2407,7 @@ main(int argc, char **argv)
 	{
 		if (format != 'p')
 		{
-			fprintf(stderr,
-					_("%s: WAL directory location can only be specified in plain mode\n"),
-					progname);
+			pg_log_error("WAL directory location can only be specified in plain mode");
 			fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
 					progname);
 			exit(1);
@@ -2518,8 +2417,7 @@ main(int argc, char **argv)
 		canonicalize_path(xlog_dir);
 		if (!is_absolute_path(xlog_dir))
 		{
-			fprintf(stderr, _("%s: WAL directory location must be "
-							  "an absolute path\n"), progname);
+			pg_log_error("WAL directory location must be an absolute path");
 			fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
 					progname);
 			exit(1);
@@ -2529,9 +2427,7 @@ main(int argc, char **argv)
 #ifndef HAVE_LIBZ
 	if (compresslevel != 0)
 	{
-		fprintf(stderr,
-				_("%s: this build does not support compression\n"),
-				progname);
+		pg_log_error("this build does not support compression");
 		exit(1);
 	}
 #endif
@@ -2585,12 +2481,11 @@ main(int argc, char **argv)
 #ifdef HAVE_SYMLINK
 		if (symlink(xlog_dir, linkloc) != 0)
 		{
-			fprintf(stderr, _("%s: could not create symbolic link \"%s\": %s\n"),
-					progname, linkloc, strerror(errno));
+			pg_log_error("could not create symbolic link \"%s\": %m", linkloc);
 			exit(1);
 		}
 #else
-		fprintf(stderr, _("%s: symlinks are not supported on this platform\n"), progname);
+		pg_log_error("symlinks are not supported on this platform");
 		exit(1);
 #endif
 		free(linkloc);
diff --git a/src/bin/pg_basebackup/pg_receivewal.c b/src/bin/pg_basebackup/pg_receivewal.c
index dc6705c330..0c9d6b2a8a 100644
--- a/src/bin/pg_basebackup/pg_receivewal.c
+++ b/src/bin/pg_basebackup/pg_receivewal.c
@@ -20,6 +20,7 @@
 #include <unistd.h>
 
 #include "common/file_perm.h"
+#include "fe_utils/logging.h"
 #include "libpq-fe.h"
 #include "access/xlog_internal.h"
 #include "getopt_long.h"
@@ -114,16 +115,16 @@ stop_streaming(XLogRecPtr xlogpos, uint32 timeline, bool segment_finished)
 
 	/* we assume that we get called once at the end of each segment */
 	if (verbose && segment_finished)
-		fprintf(stderr, _("%s: finished segment at %X/%X (timeline %u)\n"),
-				progname, (uint32) (xlogpos >> 32), (uint32) xlogpos,
-				timeline);
+		pg_log_info("finished segment at %X/%X (timeline %u)",
+					(uint32) (xlogpos >> 32), (uint32) xlogpos,
+					timeline);
 
 	if (!XLogRecPtrIsInvalid(endpos) && endpos < xlogpos)
 	{
 		if (verbose)
-			fprintf(stderr, _("%s: stopped log streaming at %X/%X (timeline %u)\n"),
-					progname, (uint32) (xlogpos >> 32), (uint32) xlogpos,
-					timeline);
+			pg_log_info("stopped log streaming at %X/%X (timeline %u)",
+						(uint32) (xlogpos >> 32), (uint32) xlogpos,
+						timeline);
 		time_to_stop = true;
 		return true;
 	}
@@ -137,9 +138,9 @@ stop_streaming(XLogRecPtr xlogpos, uint32 timeline, bool segment_finished)
 	 * timeline, but it's close enough for reporting purposes.
 	 */
 	if (verbose && prevtimeline != 0 && prevtimeline != timeline)
-		fprintf(stderr, _("%s: switched to timeline %u at %X/%X\n"),
-				progname, timeline,
-				(uint32) (prevpos >> 32), (uint32) prevpos);
+		pg_log_info("switched to timeline %u at %X/%X",
+					timeline,
+					(uint32) (prevpos >> 32), (uint32) prevpos);
 
 	prevtimeline = timeline;
 	prevpos = xlogpos;
@@ -147,8 +148,7 @@ stop_streaming(XLogRecPtr xlogpos, uint32 timeline, bool segment_finished)
 	if (time_to_stop)
 	{
 		if (verbose)
-			fprintf(stderr, _("%s: received interrupt signal, exiting\n"),
-					progname);
+			pg_log_info("received interrupt signal, exiting");
 		return true;
 	}
 	return false;
@@ -167,8 +167,7 @@ get_destination_dir(char *dest_folder)
 	dir = opendir(dest_folder);
 	if (dir == NULL)
 	{
-		fprintf(stderr, _("%s: could not open directory \"%s\": %s\n"),
-				progname, basedir, strerror(errno));
+		pg_log_error("could not open directory \"%s\": %m", basedir);
 		exit(1);
 	}
 
@@ -185,8 +184,7 @@ close_destination_dir(DIR *dest_dir, char *dest_folder)
 	Assert(dest_dir != NULL && dest_folder != NULL);
 	if (closedir(dest_dir))
 	{
-		fprintf(stderr, _("%s: could not close directory \"%s\": %s\n"),
-				progname, dest_folder, strerror(errno));
+		pg_log_error("could not close directory \"%s\": %m", dest_folder);
 		exit(1);
 	}
 }
@@ -266,16 +264,14 @@ FindStreamingStart(uint32 *tli)
 			snprintf(fullpath, sizeof(fullpath), "%s/%s", basedir, dirent->d_name);
 			if (stat(fullpath, &statbuf) != 0)
 			{
-				fprintf(stderr, _("%s: could not stat file \"%s\": %s\n"),
-						progname, fullpath, strerror(errno));
+				pg_log_error("could not stat file \"%s\": %m", fullpath);
 				exit(1);
 			}
 
 			if (statbuf.st_size != WalSegSz)
 			{
-				fprintf(stderr,
-						_("%s: segment file \"%s\" has incorrect size %d, skipping\n"),
-						progname, dirent->d_name, (int) statbuf.st_size);
+				pg_log_warning("segment file \"%s\" has incorrect size %d, skipping",
+							   dirent->d_name, (int) statbuf.st_size);
 				continue;
 			}
 		}
@@ -292,25 +288,25 @@ FindStreamingStart(uint32 *tli)
 			fd = open(fullpath, O_RDONLY | PG_BINARY, 0);
 			if (fd < 0)
 			{
-				fprintf(stderr, _("%s: could not open compressed file \"%s\": %s\n"),
-						progname, fullpath, strerror(errno));
+				pg_log_error("could not open compressed file \"%s\": %m",
+							 fullpath);
 				exit(1);
 			}
 			if (lseek(fd, (off_t) (-4), SEEK_END) < 0)
 			{
-				fprintf(stderr, _("%s: could not seek in compressed file \"%s\": %s\n"),
-						progname, fullpath, strerror(errno));
+				pg_log_error("could not seek in compressed file \"%s\": %m",
+							 fullpath);
 				exit(1);
 			}
 			r = read(fd, (char *) buf, sizeof(buf));
 			if (r != sizeof(buf))
 			{
 				if (r < 0)
-					fprintf(stderr, _("%s: could not read compressed file \"%s\": %s\n"),
-							progname, fullpath, strerror(errno));
+					pg_log_error("could not read compressed file \"%s\": %m",
+								 fullpath);
 				else
-					fprintf(stderr, _("%s: could not read compressed file \"%s\": read %d of %zu\n"),
-							progname, fullpath, r, sizeof(buf));
+					pg_log_error("could not read compressed file \"%s\": read %d of %zu",
+								 fullpath, r, sizeof(buf));
 				exit(1);
 			}
 
@@ -320,9 +316,8 @@ FindStreamingStart(uint32 *tli)
 
 			if (bytes_out != WalSegSz)
 			{
-				fprintf(stderr,
-						_("%s: compressed segment file \"%s\" has incorrect uncompressed size %d, skipping\n"),
-						progname, dirent->d_name, bytes_out);
+				pg_log_warning("compressed segment file \"%s\" has incorrect uncompressed size %d, skipping",
+							   dirent->d_name, bytes_out);
 				continue;
 			}
 		}
@@ -340,8 +335,7 @@ FindStreamingStart(uint32 *tli)
 
 	if (errno)
 	{
-		fprintf(stderr, _("%s: could not read directory \"%s\": %s\n"),
-				progname, basedir, strerror(errno));
+		pg_log_error("could not read directory \"%s\": %m", basedir);
 		exit(1);
 	}
 
@@ -426,10 +420,9 @@ StreamLog(void)
 	 * Start the replication
 	 */
 	if (verbose)
-		fprintf(stderr,
-				_("%s: starting log streaming at %X/%X (timeline %u)\n"),
-				progname, (uint32) (stream.startpos >> 32), (uint32) stream.startpos,
-				stream.timeline);
+		pg_log_info("starting log streaming at %X/%X (timeline %u)",
+					(uint32) (stream.startpos >> 32), (uint32) stream.startpos,
+					stream.timeline);
 
 	stream.stream_stop = stop_streaming;
 	stream.stop_socket = PGINVALID_SOCKET;
@@ -446,9 +439,7 @@ StreamLog(void)
 
 	if (!stream.walmethod->finish())
 	{
-		fprintf(stderr,
-				_("%s: could not finish writing WAL files: %s\n"),
-				progname, strerror(errno));
+		pg_log_info("could not finish writing WAL files: %m");
 		return;
 	}
 
@@ -510,6 +501,7 @@ main(int argc, char **argv)
 
 	progname = get_progname(argv[0]);
 	set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_basebackup"));
+	pg_logging_init(argv[0]);
 
 	if (argc > 1)
 	{
@@ -543,8 +535,7 @@ main(int argc, char **argv)
 			case 'p':
 				if (atoi(optarg) <= 0)
 				{
-					fprintf(stderr, _("%s: invalid port number \"%s\"\n"),
-							progname, optarg);
+					pg_log_error("invalid port number \"%s\"", optarg);
 					exit(1);
 				}
 				dbport = pg_strdup(optarg);
@@ -562,8 +553,7 @@ main(int argc, char **argv)
 				standby_message_timeout = atoi(optarg) * 1000;
 				if (standby_message_timeout < 0)
 				{
-					fprintf(stderr, _("%s: invalid status interval \"%s\"\n"),
-							progname, optarg);
+					pg_log_error("invalid status interval \"%s\"", optarg);
 					exit(1);
 				}
 				break;
@@ -573,9 +563,7 @@ main(int argc, char **argv)
 			case 'E':
 				if (sscanf(optarg, "%X/%X", &hi, &lo) != 2)
 				{
-					fprintf(stderr,
-							_("%s: could not parse end position \"%s\"\n"),
-							progname, optarg);
+					pg_log_error("could not parse end position \"%s\"", optarg);
 					exit(1);
 				}
 				endpos = ((uint64) hi) << 32 | lo;
@@ -590,8 +578,7 @@ main(int argc, char **argv)
 				compresslevel = atoi(optarg);
 				if (compresslevel < 0 || compresslevel > 9)
 				{
-					fprintf(stderr, _("%s: invalid compression level \"%s\"\n"),
-							progname, optarg);
+					pg_log_error("invalid compression level \"%s\"", optarg);
 					exit(1);
 				}
 				break;
@@ -627,9 +614,8 @@ main(int argc, char **argv)
 	 */
 	if (optind < argc)
 	{
-		fprintf(stderr,
-				_("%s: too many command-line arguments (first is \"%s\")\n"),
-				progname, argv[optind]);
+		pg_log_error("too many command-line arguments (first is \"%s\")",
+					 argv[optind]);
 		fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
 				progname);
 		exit(1);
@@ -637,7 +623,7 @@ main(int argc, char **argv)
 
 	if (do_drop_slot && do_create_slot)
 	{
-		fprintf(stderr, _("%s: cannot use --create-slot together with --drop-slot\n"), progname);
+		pg_log_error("cannot use --create-slot together with --drop-slot");
 		fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
 				progname);
 		exit(1);
@@ -646,8 +632,8 @@ main(int argc, char **argv)
 	if (replication_slot == NULL && (do_drop_slot || do_create_slot))
 	{
 		/* translator: second %s is an option name */
-		fprintf(stderr, _("%s: %s needs a slot to be specified using --slot\n"), progname,
-				do_drop_slot ? "--drop-slot" : "--create-slot");
+		pg_log_error("%s needs a slot to be specified using --slot",
+					 do_drop_slot ? "--drop-slot" : "--create-slot");
 		fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
 				progname);
 		exit(1);
@@ -655,7 +641,7 @@ main(int argc, char **argv)
 
 	if (synchronous && !do_sync)
 	{
-		fprintf(stderr, _("%s: cannot use --synchronous together with --no-sync\n"), progname);
+		pg_log_error("cannot use --synchronous together with --no-sync");
 		fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
 				progname);
 		exit(1);
@@ -666,7 +652,7 @@ main(int argc, char **argv)
 	 */
 	if (basedir == NULL && !do_drop_slot && !do_create_slot)
 	{
-		fprintf(stderr, _("%s: no target directory specified\n"), progname);
+		pg_log_error("no target directory specified");
 		fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
 				progname);
 		exit(1);
@@ -675,9 +661,7 @@ main(int argc, char **argv)
 #ifndef HAVE_LIBZ
 	if (compresslevel != 0)
 	{
-		fprintf(stderr,
-				_("%s: this build does not support compression\n"),
-				progname);
+		pg_log_error("this build does not support compression");
 		exit(1);
 	}
 #endif
@@ -733,9 +717,8 @@ main(int argc, char **argv)
 	 */
 	if (db_name)
 	{
-		fprintf(stderr,
-				_("%s: replication connection using slot \"%s\" is unexpectedly database specific\n"),
-				progname, replication_slot);
+		pg_log_error("replication connection using slot \"%s\" is unexpectedly database specific",
+					 replication_slot);
 		exit(1);
 	}
 
@@ -745,9 +728,7 @@ main(int argc, char **argv)
 	if (do_drop_slot)
 	{
 		if (verbose)
-			fprintf(stderr,
-					_("%s: dropping replication slot \"%s\"\n"),
-					progname, replication_slot);
+			pg_log_info("dropping replication slot \"%s\"",	replication_slot);
 
 		if (!DropReplicationSlot(conn, replication_slot))
 			exit(1);
@@ -758,9 +739,7 @@ main(int argc, char **argv)
 	if (do_create_slot)
 	{
 		if (verbose)
-			fprintf(stderr,
-					_("%s: creating replication slot \"%s\"\n"),
-					progname, replication_slot);
+			pg_log_info("creating replication slot \"%s\"", replication_slot);
 
 		if (!CreateReplicationSlot(conn, replication_slot, NULL, false, true, false,
 								   slot_exists_ok))
@@ -786,15 +765,14 @@ main(int argc, char **argv)
 		}
 		else if (noloop)
 		{
-			fprintf(stderr, _("%s: disconnected\n"), progname);
+			pg_log_error("disconnected");
 			exit(1);
 		}
 		else
 		{
-			fprintf(stderr,
 			/* translator: check source for value for %d */
-					_("%s: disconnected; waiting %d seconds to try again\n"),
-					progname, RECONNECT_SLEEP_TIME);
+			pg_log_info("disconnected; waiting %d seconds to try again",
+						RECONNECT_SLEEP_TIME);
 			pg_usleep(RECONNECT_SLEEP_TIME * 1000000);
 		}
 	}
diff --git a/src/bin/pg_basebackup/pg_recvlogical.c b/src/bin/pg_basebackup/pg_recvlogical.c
index d75b66f1e7..3253497998 100644
--- a/src/bin/pg_basebackup/pg_recvlogical.c
+++ b/src/bin/pg_basebackup/pg_recvlogical.c
@@ -25,6 +25,7 @@
 #include "access/xlog_internal.h"
 #include "common/file_perm.h"
 #include "common/fe_memutils.h"
+#include "fe_utils/logging.h"
 #include "getopt_long.h"
 #include "libpq-fe.h"
 #include "libpq/pqsignal.h"
@@ -131,12 +132,10 @@ sendFeedback(PGconn *conn, TimestampTz now, bool force, bool replyRequested)
 		return true;
 
 	if (verbose)
-		fprintf(stderr,
-				_("%s: confirming write up to %X/%X, flush to %X/%X (slot %s)\n"),
-				progname,
-				(uint32) (output_written_lsn >> 32), (uint32) output_written_lsn,
-				(uint32) (output_fsync_lsn >> 32), (uint32) output_fsync_lsn,
-				replication_slot);
+		pg_log_info("confirming write up to %X/%X, flush to %X/%X (slot %s)",
+					(uint32) (output_written_lsn >> 32), (uint32) output_written_lsn,
+					(uint32) (output_fsync_lsn >> 32), (uint32) output_fsync_lsn,
+					replication_slot);
 
 	replybuf[len] = 'r';
 	len += 1;
@@ -157,8 +156,8 @@ sendFeedback(PGconn *conn, TimestampTz now, bool force, bool replyRequested)
 
 	if (PQputCopyData(conn, replybuf, len) <= 0 || PQflush(conn))
 	{
-		fprintf(stderr, _("%s: could not send feedback packet: %s"),
-				progname, PQerrorMessage(conn));
+		pg_log_error("could not send feedback packet: %s",
+					 PQerrorMessage(conn));
 		return false;
 	}
 
@@ -193,9 +192,7 @@ OutputFsync(TimestampTz now)
 
 	if (fsync(outfd) != 0)
 	{
-		fprintf(stderr,
-				_("%s: could not fsync file \"%s\": %s\n"),
-				progname, outfile, strerror(errno));
+		pg_log_error("could not fsync file \"%s\": %m", outfile);
 		return false;
 	}
 
@@ -232,10 +229,9 @@ StreamLogicalLog(void)
 	 * Start the replication
 	 */
 	if (verbose)
-		fprintf(stderr,
-				_("%s: starting log streaming at %X/%X (slot %s)\n"),
-				progname, (uint32) (startpos >> 32), (uint32) startpos,
-				replication_slot);
+		pg_log_info("starting log streaming at %X/%X (slot %s)",
+					(uint32) (startpos >> 32), (uint32) startpos,
+					replication_slot);
 
 	/* Initiate the replication stream at specified location */
 	appendPQExpBuffer(query, "START_REPLICATION SLOT \"%s\" LOGICAL %X/%X",
@@ -265,8 +261,8 @@ StreamLogicalLog(void)
 	res = PQexec(conn, query->data);
 	if (PQresultStatus(res) != PGRES_COPY_BOTH)
 	{
-		fprintf(stderr, _("%s: could not send replication command \"%s\": %s"),
-				progname, query->data, PQresultErrorMessage(res));
+		pg_log_error("could not send replication command \"%s\": %s",
+					 query->data, PQresultErrorMessage(res));
 		PQclear(res);
 		goto error;
 	}
@@ -274,9 +270,7 @@ StreamLogicalLog(void)
 	resetPQExpBuffer(query);
 
 	if (verbose)
-		fprintf(stderr,
-				_("%s: streaming initiated\n"),
-				progname);
+		pg_log_info("streaming initiated");
 
 	while (!time_to_abort)
 	{
@@ -340,16 +334,12 @@ StreamLogicalLog(void)
 							 S_IRUSR | S_IWUSR);
 			if (outfd == -1)
 			{
-				fprintf(stderr,
-						_("%s: could not open log file \"%s\": %s\n"),
-						progname, outfile, strerror(errno));
+				pg_log_error("could not open log file \"%s\": %m", outfile);
 				goto error;
 			}
 
 			if (fstat(outfd, &statbuf) != 0)
-				fprintf(stderr,
-						_("%s: could not stat file \"%s\": %s\n"),
-						progname, outfile, strerror(errno));
+				pg_log_error("could not stat file \"%s\": %m", outfile);
 
 			output_isfile = S_ISREG(statbuf.st_mode) && !isatty(outfd);
 		}
@@ -370,9 +360,7 @@ StreamLogicalLog(void)
 
 			if (PQsocket(conn) < 0)
 			{
-				fprintf(stderr,
-						_("%s: invalid socket: %s"),
-						progname, PQerrorMessage(conn));
+				pg_log_error("invalid socket: %s", PQerrorMessage(conn));
 				goto error;
 			}
 
@@ -425,17 +413,15 @@ StreamLogicalLog(void)
 			}
 			else if (r < 0)
 			{
-				fprintf(stderr, _("%s: select() failed: %s\n"),
-						progname, strerror(errno));
+				pg_log_error("select() failed: %m");
 				goto error;
 			}
 
 			/* Else there is actually data on the socket */
 			if (PQconsumeInput(conn) == 0)
 			{
-				fprintf(stderr,
-						_("%s: could not receive data from WAL stream: %s"),
-						progname, PQerrorMessage(conn));
+				pg_log_error("could not receive data from WAL stream: %s",
+							 PQerrorMessage(conn));
 				goto error;
 			}
 			continue;
@@ -448,8 +434,8 @@ StreamLogicalLog(void)
 		/* Failure while reading the copy stream */
 		if (r == -2)
 		{
-			fprintf(stderr, _("%s: could not read COPY data: %s"),
-					progname, PQerrorMessage(conn));
+			pg_log_error("could not read COPY data: %s",
+						 PQerrorMessage(conn));
 			goto error;
 		}
 
@@ -476,8 +462,7 @@ StreamLogicalLog(void)
 
 			if (r < pos + 1)
 			{
-				fprintf(stderr, _("%s: streaming header too small: %d\n"),
-						progname, r);
+				pg_log_error("streaming header too small: %d", r);
 				goto error;
 			}
 			replyRequested = copybuf[pos];
@@ -512,8 +497,8 @@ StreamLogicalLog(void)
 		}
 		else if (copybuf[0] != 'w')
 		{
-			fprintf(stderr, _("%s: unrecognized streaming header: \"%c\"\n"),
-					progname, copybuf[0]);
+			pg_log_error("unrecognized streaming header: \"%c\"",
+						 copybuf[0]);
 			goto error;
 		}
 
@@ -528,8 +513,7 @@ StreamLogicalLog(void)
 		hdr_len += 8;			/* sendTime */
 		if (r < hdr_len + 1)
 		{
-			fprintf(stderr, _("%s: streaming header too small: %d\n"),
-					progname, r);
+			pg_log_error("streaming header too small: %d", r);
 			goto error;
 		}
 
@@ -567,10 +551,8 @@ StreamLogicalLog(void)
 
 			if (ret < 0)
 			{
-				fprintf(stderr,
-						_("%s: could not write %u bytes to log file \"%s\": %s\n"),
-						progname, bytes_left, outfile,
-						strerror(errno));
+				pg_log_error("could not write %u bytes to log file \"%s\": %m",
+							 bytes_left, outfile);
 				goto error;
 			}
 
@@ -581,10 +563,8 @@ StreamLogicalLog(void)
 
 		if (write(outfd, "\n", 1) != 1)
 		{
-			fprintf(stderr,
-					_("%s: could not write %u bytes to log file \"%s\": %s\n"),
-					progname, 1, outfile,
-					strerror(errno));
+			pg_log_error("could not write %u bytes to log file \"%s\": %m",
+						 1, outfile);
 			goto error;
 		}
 
@@ -611,9 +591,8 @@ StreamLogicalLog(void)
 	}
 	else if (PQresultStatus(res) != PGRES_COMMAND_OK)
 	{
-		fprintf(stderr,
-				_("%s: unexpected termination of replication stream: %s"),
-				progname, PQresultErrorMessage(res));
+		pg_log_error("unexpected termination of replication stream: %s",
+					 PQresultErrorMessage(res));
 		goto error;
 	}
 	PQclear(res);
@@ -626,8 +605,7 @@ StreamLogicalLog(void)
 		OutputFsync(t);
 
 		if (close(outfd) != 0)
-			fprintf(stderr, _("%s: could not close file \"%s\": %s\n"),
-					progname, outfile, strerror(errno));
+			pg_log_error("could not close file \"%s\": %m", outfile);
 	}
 	outfd = -1;
 error:
@@ -707,6 +685,7 @@ main(int argc, char **argv)
 
 	progname = get_progname(argv[0]);
 	set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_basebackup"));
+	pg_logging_init(argv[0]);
 
 	if (argc > 1)
 	{
@@ -736,8 +715,7 @@ main(int argc, char **argv)
 				fsync_interval = atoi(optarg) * 1000;
 				if (fsync_interval < 0)
 				{
-					fprintf(stderr, _("%s: invalid fsync interval \"%s\"\n"),
-							progname, optarg);
+					pg_log_error("invalid fsync interval \"%s\"", optarg);
 					exit(1);
 				}
 				break;
@@ -757,8 +735,7 @@ main(int argc, char **argv)
 			case 'p':
 				if (atoi(optarg) <= 0)
 				{
-					fprintf(stderr, _("%s: invalid port number \"%s\"\n"),
-							progname, optarg);
+					pg_log_error("invalid port number \"%s\"", optarg);
 					exit(1);
 				}
 				dbport = pg_strdup(optarg);
@@ -776,9 +753,7 @@ main(int argc, char **argv)
 			case 'I':
 				if (sscanf(optarg, "%X/%X", &hi, &lo) != 2)
 				{
-					fprintf(stderr,
-							_("%s: could not parse start position \"%s\"\n"),
-							progname, optarg);
+					pg_log_error("could not parse start position \"%s\"", optarg);
 					exit(1);
 				}
 				startpos = ((uint64) hi) << 32 | lo;
@@ -786,9 +761,7 @@ main(int argc, char **argv)
 			case 'E':
 				if (sscanf(optarg, "%X/%X", &hi, &lo) != 2)
 				{
-					fprintf(stderr,
-							_("%s: could not parse end position \"%s\"\n"),
-							progname, optarg);
+					pg_log_error("could not parse end position \"%s\"", optarg);
 					exit(1);
 				}
 				endpos = ((uint64) hi) << 32 | lo;
@@ -820,8 +793,7 @@ main(int argc, char **argv)
 				standby_message_timeout = atoi(optarg) * 1000;
 				if (standby_message_timeout < 0)
 				{
-					fprintf(stderr, _("%s: invalid status interval \"%s\"\n"),
-							progname, optarg);
+					pg_log_error("invalid status interval \"%s\"", optarg);
 					exit(1);
 				}
 				break;
@@ -858,9 +830,8 @@ main(int argc, char **argv)
 	 */
 	if (optind < argc)
 	{
-		fprintf(stderr,
-				_("%s: too many command-line arguments (first is \"%s\")\n"),
-				progname, argv[optind]);
+		pg_log_error("too many command-line arguments (first is \"%s\")",
+					 argv[optind]);
 		fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
 				progname);
 		exit(1);
@@ -871,7 +842,7 @@ main(int argc, char **argv)
 	 */
 	if (replication_slot == NULL)
 	{
-		fprintf(stderr, _("%s: no slot specified\n"), progname);
+		pg_log_error("no slot specified");
 		fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
 				progname);
 		exit(1);
@@ -879,7 +850,7 @@ main(int argc, char **argv)
 
 	if (do_start_slot && outfile == NULL)
 	{
-		fprintf(stderr, _("%s: no target file specified\n"), progname);
+		pg_log_error("no target file specified");
 		fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
 				progname);
 		exit(1);
@@ -887,7 +858,7 @@ main(int argc, char **argv)
 
 	if (!do_drop_slot && dbname == NULL)
 	{
-		fprintf(stderr, _("%s: no database specified\n"), progname);
+		pg_log_error("no database specified");
 		fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
 				progname);
 		exit(1);
@@ -895,7 +866,7 @@ main(int argc, char **argv)
 
 	if (!do_drop_slot && !do_create_slot && !do_start_slot)
 	{
-		fprintf(stderr, _("%s: at least one action needs to be specified\n"), progname);
+		pg_log_error("at least one action needs to be specified");
 		fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
 				progname);
 		exit(1);
@@ -903,7 +874,7 @@ main(int argc, char **argv)
 
 	if (do_drop_slot && (do_create_slot || do_start_slot))
 	{
-		fprintf(stderr, _("%s: cannot use --create-slot or --start together with --drop-slot\n"), progname);
+		pg_log_error("cannot use --create-slot or --start together with --drop-slot");
 		fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
 				progname);
 		exit(1);
@@ -911,7 +882,7 @@ main(int argc, char **argv)
 
 	if (startpos != InvalidXLogRecPtr && (do_create_slot || do_drop_slot))
 	{
-		fprintf(stderr, _("%s: cannot use --create-slot or --drop-slot together with --startpos\n"), progname);
+		pg_log_error("cannot use --create-slot or --drop-slot together with --startpos");
 		fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
 				progname);
 		exit(1);
@@ -919,9 +890,7 @@ main(int argc, char **argv)
 
 	if (endpos != InvalidXLogRecPtr && !do_start_slot)
 	{
-		fprintf(stderr,
-				_("%s: --endpos may only be specified with --start\n"),
-				progname);
+		pg_log_error("--endpos may only be specified with --start");
 		fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
 				progname);
 		exit(1);
@@ -952,9 +921,7 @@ main(int argc, char **argv)
 
 	if (db_name == NULL)
 	{
-		fprintf(stderr,
-				_("%s: could not establish database-specific replication connection\n"),
-				progname);
+		pg_log_error("could not establish database-specific replication connection");
 		exit(1);
 	}
 
@@ -972,9 +939,7 @@ main(int argc, char **argv)
 	if (do_drop_slot)
 	{
 		if (verbose)
-			fprintf(stderr,
-					_("%s: dropping replication slot \"%s\"\n"),
-					progname, replication_slot);
+			pg_log_info("dropping replication slot \"%s\"", replication_slot);
 
 		if (!DropReplicationSlot(conn, replication_slot))
 			exit(1);
@@ -984,9 +949,7 @@ main(int argc, char **argv)
 	if (do_create_slot)
 	{
 		if (verbose)
-			fprintf(stderr,
-					_("%s: creating replication slot \"%s\"\n"),
-					progname, replication_slot);
+			pg_log_info("creating replication slot \"%s\"", replication_slot);
 
 		if (!CreateReplicationSlot(conn, replication_slot, plugin, false,
 								   false, false, slot_exists_ok))
@@ -1011,15 +974,14 @@ main(int argc, char **argv)
 		}
 		else if (noloop)
 		{
-			fprintf(stderr, _("%s: disconnected\n"), progname);
+			pg_log_error("disconnected");
 			exit(1);
 		}
 		else
 		{
-			fprintf(stderr,
 			/* translator: check source for value for %d */
-					_("%s: disconnected; waiting %d seconds to try again\n"),
-					progname, RECONNECT_SLEEP_TIME);
+			pg_log_info("disconnected; waiting %d seconds to try again",
+						RECONNECT_SLEEP_TIME);
 			pg_usleep(RECONNECT_SLEEP_TIME * 1000000);
 		}
 	}
@@ -1058,13 +1020,12 @@ prepareToTerminate(PGconn *conn, XLogRecPtr endpos, bool keepalive, XLogRecPtr l
 	if (verbose)
 	{
 		if (keepalive)
-			fprintf(stderr, "%s: endpos %X/%X reached by keepalive\n",
-					progname,
-					(uint32) (endpos >> 32), (uint32) endpos);
+			pg_log_info("endpos %X/%X reached by keepalive",
+						(uint32) (endpos >> 32), (uint32) endpos);
 		else
-			fprintf(stderr, "%s: endpos %X/%X reached by record at %X/%X\n",
-					progname, (uint32) (endpos >> 32), (uint32) (endpos),
-					(uint32) (lsn >> 32), (uint32) lsn);
+			pg_log_info("endpos %X/%X reached by record at %X/%X",
+						(uint32) (endpos >> 32), (uint32) (endpos),
+						(uint32) (lsn >> 32), (uint32) lsn);
 
 	}
 }
diff --git a/src/bin/pg_basebackup/receivelog.c b/src/bin/pg_basebackup/receivelog.c
index 692d13716e..8384f5791c 100644
--- a/src/bin/pg_basebackup/receivelog.c
+++ b/src/bin/pg_basebackup/receivelog.c
@@ -27,6 +27,7 @@
 #include "libpq-fe.h"
 #include "access/xlog_internal.h"
 #include "common/file_utils.h"
+#include "fe_utils/logging.h"
 
 
 /* fd and filename for currently open WAL file */
@@ -68,8 +69,8 @@ mark_file_as_archived(StreamCtl *stream, const char *fname)
 	f = stream->walmethod->open_for_write(tmppath, NULL, 0);
 	if (f == NULL)
 	{
-		fprintf(stderr, _("%s: could not create archive status file \"%s\": %s\n"),
-				progname, tmppath, stream->walmethod->getlasterror());
+		pg_log_error("could not create archive status file \"%s\": %s",
+					 tmppath, stream->walmethod->getlasterror());
 		return false;
 	}
 
@@ -115,9 +116,8 @@ open_walfile(StreamCtl *stream, XLogRecPtr startpoint)
 		size = stream->walmethod->get_file_size(fn);
 		if (size < 0)
 		{
-			fprintf(stderr,
-					_("%s: could not get size of write-ahead log file \"%s\": %s\n"),
-					progname, fn, stream->walmethod->getlasterror());
+			pg_log_error("could not get size of write-ahead log file \"%s\": %s",
+						 fn, stream->walmethod->getlasterror());
 			return false;
 		}
 		if (size == WalSegSz)
@@ -126,18 +126,16 @@ open_walfile(StreamCtl *stream, XLogRecPtr startpoint)
 			f = stream->walmethod->open_for_write(current_walfile_name, stream->partial_suffix, 0);
 			if (f == NULL)
 			{
-				fprintf(stderr,
-						_("%s: could not open existing write-ahead log file \"%s\": %s\n"),
-						progname, fn, stream->walmethod->getlasterror());
+				pg_log_error("could not open existing write-ahead log file \"%s\": %s",
+							 fn, stream->walmethod->getlasterror());
 				return false;
 			}
 
 			/* fsync file in case of a previous crash */
 			if (stream->walmethod->sync(f) != 0)
 			{
-				fprintf(stderr,
-						_("%s: could not fsync existing write-ahead log file \"%s\": %s\n"),
-						progname, fn, stream->walmethod->getlasterror());
+				pg_log_error("could not fsync existing write-ahead log file \"%s\": %s",
+							 fn, stream->walmethod->getlasterror());
 				stream->walmethod->close(f, CLOSE_UNLINK);
 				return false;
 			}
@@ -150,11 +148,10 @@ open_walfile(StreamCtl *stream, XLogRecPtr startpoint)
 			/* if write didn't set errno, assume problem is no disk space */
 			if (errno == 0)
 				errno = ENOSPC;
-			fprintf(stderr,
-					ngettext("%s: write-ahead log file \"%s\" has %d byte, should be 0 or %d\n",
-							 "%s: write-ahead log file \"%s\" has %d bytes, should be 0 or %d\n",
-							 size),
-					progname, fn, (int) size, WalSegSz);
+			pg_log_error(ngettext("write-ahead log file \"%s\" has %d byte, should be 0 or %d",
+								  "write-ahead log file \"%s\" has %d bytes, should be 0 or %d",
+								  size),
+						 fn, (int) size, WalSegSz);
 			return false;
 		}
 		/* File existed and was empty, so fall through and open */
@@ -166,9 +163,8 @@ open_walfile(StreamCtl *stream, XLogRecPtr startpoint)
 										  stream->partial_suffix, WalSegSz);
 	if (f == NULL)
 	{
-		fprintf(stderr,
-				_("%s: could not open write-ahead log file \"%s\": %s\n"),
-				progname, fn, stream->walmethod->getlasterror());
+		pg_log_error("could not open write-ahead log file \"%s\": %s",
+					 fn, stream->walmethod->getlasterror());
 		return false;
 	}
 
@@ -193,9 +189,8 @@ close_walfile(StreamCtl *stream, XLogRecPtr pos)
 	currpos = stream->walmethod->get_current_pos(walfile);
 	if (currpos == -1)
 	{
-		fprintf(stderr,
-				_("%s: could not determine seek position in file \"%s\": %s\n"),
-				progname, current_walfile_name, stream->walmethod->getlasterror());
+		pg_log_error("could not determine seek position in file \"%s\": %s",
+					 current_walfile_name, stream->walmethod->getlasterror());
 		stream->walmethod->close(walfile, CLOSE_UNLINK);
 		walfile = NULL;
 
@@ -208,9 +203,8 @@ close_walfile(StreamCtl *stream, XLogRecPtr pos)
 			r = stream->walmethod->close(walfile, CLOSE_NORMAL);
 		else
 		{
-			fprintf(stderr,
-					_("%s: not renaming \"%s%s\", segment is not complete\n"),
-					progname, current_walfile_name, stream->partial_suffix);
+			pg_log_info("not renaming \"%s%s\", segment is not complete",
+						current_walfile_name, stream->partial_suffix);
 			r = stream->walmethod->close(walfile, CLOSE_NO_RENAME);
 		}
 	}
@@ -221,8 +215,8 @@ close_walfile(StreamCtl *stream, XLogRecPtr pos)
 
 	if (r != 0)
 	{
-		fprintf(stderr, _("%s: could not close file \"%s\": %s\n"),
-				progname, current_walfile_name, stream->walmethod->getlasterror());
+		pg_log_error("could not close file \"%s\": %s",
+					 current_walfile_name, stream->walmethod->getlasterror());
 		return false;
 	}
 
@@ -278,23 +272,23 @@ writeTimeLineHistoryFile(StreamCtl *stream, char *filename, char *content)
 	TLHistoryFileName(histfname, stream->timeline);
 	if (strcmp(histfname, filename) != 0)
 	{
-		fprintf(stderr, _("%s: server reported unexpected history file name for timeline %u: %s\n"),
-				progname, stream->timeline, filename);
+		pg_log_error("server reported unexpected history file name for timeline %u: %s",
+					 stream->timeline, filename);
 		return false;
 	}
 
 	f = stream->walmethod->open_for_write(histfname, ".tmp", 0);
 	if (f == NULL)
 	{
-		fprintf(stderr, _("%s: could not create timeline history file \"%s\": %s\n"),
-				progname, histfname, stream->walmethod->getlasterror());
+		pg_log_error("could not create timeline history file \"%s\": %s",
+					 histfname, stream->walmethod->getlasterror());
 		return false;
 	}
 
 	if ((int) stream->walmethod->write(f, content, size) != size)
 	{
-		fprintf(stderr, _("%s: could not write timeline history file \"%s\": %s\n"),
-				progname, histfname, stream->walmethod->getlasterror());
+		pg_log_error("could not write timeline history file \"%s\": %s",
+					 histfname, stream->walmethod->getlasterror());
 
 		/*
 		 * If we fail to make the file, delete it to release disk space
@@ -306,8 +300,8 @@ writeTimeLineHistoryFile(StreamCtl *stream, char *filename, char *content)
 
 	if (stream->walmethod->close(f, CLOSE_NORMAL) != 0)
 	{
-		fprintf(stderr, _("%s: could not close file \"%s\": %s\n"),
-				progname, histfname, stream->walmethod->getlasterror());
+		pg_log_error("could not close file \"%s\": %s",
+					 histfname, stream->walmethod->getlasterror());
 		return false;
 	}
 
@@ -349,8 +343,8 @@ sendFeedback(PGconn *conn, XLogRecPtr blockpos, TimestampTz now, bool replyReque
 
 	if (PQputCopyData(conn, replybuf, len) <= 0 || PQflush(conn))
 	{
-		fprintf(stderr, _("%s: could not send feedback packet: %s"),
-				progname, PQerrorMessage(conn));
+		pg_log_error("could not send feedback packet: %s",
+					 PQerrorMessage(conn));
 		return false;
 	}
 
@@ -383,20 +377,18 @@ CheckServerVersionForStreaming(PGconn *conn)
 	{
 		const char *serverver = PQparameterStatus(conn, "server_version");
 
-		fprintf(stderr, _("%s: incompatible server version %s; client does not support streaming from server versions older than %s\n"),
-				progname,
-				serverver ? serverver : "'unknown'",
-				"9.3");
+		pg_log_error("incompatible server version %s; client does not support streaming from server versions older than %s",
+					 serverver ? serverver : "'unknown'",
+					 "9.3");
 		return false;
 	}
 	else if (serverMajor > maxServerMajor)
 	{
 		const char *serverver = PQparameterStatus(conn, "server_version");
 
-		fprintf(stderr, _("%s: incompatible server version %s; client does not support streaming from server versions newer than %s\n"),
-				progname,
-				serverver ? serverver : "'unknown'",
-				PG_VERSION);
+		pg_log_error("incompatible server version %s; client does not support streaming from server versions newer than %s",
+					 serverver ? serverver : "'unknown'",
+					 PG_VERSION);
 		return false;
 	}
 	return true;
@@ -489,33 +481,28 @@ ReceiveXlogStream(PGconn *conn, StreamCtl *stream)
 		res = PQexec(conn, "IDENTIFY_SYSTEM");
 		if (PQresultStatus(res) != PGRES_TUPLES_OK)
 		{
-			fprintf(stderr,
-					_("%s: could not send replication command \"%s\": %s"),
-					progname, "IDENTIFY_SYSTEM", PQerrorMessage(conn));
+			pg_log_error("could not send replication command \"%s\": %s",
+						 "IDENTIFY_SYSTEM", PQerrorMessage(conn));
 			PQclear(res);
 			return false;
 		}
 		if (PQntuples(res) != 1 || PQnfields(res) < 3)
 		{
-			fprintf(stderr,
-					_("%s: could not identify system: got %d rows and %d fields, expected %d rows and %d or more fields\n"),
-					progname, PQntuples(res), PQnfields(res), 1, 3);
+			pg_log_error("could not identify system: got %d rows and %d fields, expected %d rows and %d or more fields",
+						 PQntuples(res), PQnfields(res), 1, 3);
 			PQclear(res);
 			return false;
 		}
 		if (strcmp(stream->sysidentifier, PQgetvalue(res, 0, 0)) != 0)
 		{
-			fprintf(stderr,
-					_("%s: system identifier does not match between base backup and streaming connection\n"),
-					progname);
+			pg_log_error("system identifier does not match between base backup and streaming connection");
 			PQclear(res);
 			return false;
 		}
 		if (stream->timeline > atoi(PQgetvalue(res, 0, 1)))
 		{
-			fprintf(stderr,
-					_("%s: starting timeline %u is not present in the server\n"),
-					progname, stream->timeline);
+			pg_log_error("starting timeline %u is not present in the server",
+						 stream->timeline);
 			PQclear(res);
 			return false;
 		}
@@ -543,8 +530,8 @@ ReceiveXlogStream(PGconn *conn, StreamCtl *stream)
 			if (PQresultStatus(res) != PGRES_TUPLES_OK)
 			{
 				/* FIXME: we might send it ok, but get an error */
-				fprintf(stderr, _("%s: could not send replication command \"%s\": %s"),
-						progname, "TIMELINE_HISTORY", PQresultErrorMessage(res));
+				pg_log_error("could not send replication command \"%s\": %s",
+							 "TIMELINE_HISTORY", PQresultErrorMessage(res));
 				PQclear(res);
 				return false;
 			}
@@ -555,9 +542,8 @@ ReceiveXlogStream(PGconn *conn, StreamCtl *stream)
 			 */
 			if (PQnfields(res) != 2 || PQntuples(res) != 1)
 			{
-				fprintf(stderr,
-						_("%s: unexpected response to TIMELINE_HISTORY command: got %d rows and %d fields, expected %d rows and %d fields\n"),
-						progname, PQntuples(res), PQnfields(res), 1, 2);
+				pg_log_warning("unexpected response to TIMELINE_HISTORY command: got %d rows and %d fields, expected %d rows and %d fields",
+							   PQntuples(res), PQnfields(res), 1, 2);
 			}
 
 			/* Write the history file to disk */
@@ -583,8 +569,8 @@ ReceiveXlogStream(PGconn *conn, StreamCtl *stream)
 		res = PQexec(conn, query);
 		if (PQresultStatus(res) != PGRES_COPY_BOTH)
 		{
-			fprintf(stderr, _("%s: could not send replication command \"%s\": %s"),
-					progname, "START_REPLICATION", PQresultErrorMessage(res));
+			pg_log_error("could not send replication command \"%s\": %s",
+						 "START_REPLICATION", PQresultErrorMessage(res));
 			PQclear(res);
 			return false;
 		}
@@ -627,18 +613,15 @@ ReceiveXlogStream(PGconn *conn, StreamCtl *stream)
 			/* Sanity check the values the server gave us */
 			if (newtimeline <= stream->timeline)
 			{
-				fprintf(stderr,
-						_("%s: server reported unexpected next timeline %u, following timeline %u\n"),
-						progname, newtimeline, stream->timeline);
+				pg_log_error("server reported unexpected next timeline %u, following timeline %u",
+							 newtimeline, stream->timeline);
 				goto error;
 			}
 			if (stream->startpos > stoppos)
 			{
-				fprintf(stderr,
-						_("%s: server stopped streaming timeline %u at %X/%X, but reported next timeline %u to begin at %X/%X\n"),
-						progname,
-						stream->timeline, (uint32) (stoppos >> 32), (uint32) stoppos,
-						newtimeline, (uint32) (stream->startpos >> 32), (uint32) stream->startpos);
+				pg_log_error("server stopped streaming timeline %u at %X/%X, but reported next timeline %u to begin at %X/%X",
+							 stream->timeline, (uint32) (stoppos >> 32), (uint32) stoppos,
+							 newtimeline, (uint32) (stream->startpos >> 32), (uint32) stream->startpos);
 				goto error;
 			}
 
@@ -646,9 +629,8 @@ ReceiveXlogStream(PGconn *conn, StreamCtl *stream)
 			res = PQgetResult(conn);
 			if (PQresultStatus(res) != PGRES_COMMAND_OK)
 			{
-				fprintf(stderr,
-						_("%s: unexpected termination of replication stream: %s"),
-						progname, PQresultErrorMessage(res));
+				pg_log_error("unexpected termination of replication stream: %s",
+							 PQresultErrorMessage(res));
 				PQclear(res);
 				goto error;
 			}
@@ -677,17 +659,15 @@ ReceiveXlogStream(PGconn *conn, StreamCtl *stream)
 				return true;
 			else
 			{
-				fprintf(stderr, _("%s: replication stream was terminated before stop point\n"),
-						progname);
+				pg_log_error("replication stream was terminated before stop point");
 				goto error;
 			}
 		}
 		else
 		{
 			/* Server returned an error. */
-			fprintf(stderr,
-					_("%s: unexpected termination of replication stream: %s"),
-					progname, PQresultErrorMessage(res));
+			pg_log_error("unexpected termination of replication stream: %s",
+						 PQresultErrorMessage(res));
 			PQclear(res);
 			goto error;
 		}
@@ -695,8 +675,8 @@ ReceiveXlogStream(PGconn *conn, StreamCtl *stream)
 
 error:
 	if (walfile != NULL && stream->walmethod->close(walfile, CLOSE_NO_RENAME) != 0)
-		fprintf(stderr, _("%s: could not close file \"%s\": %s\n"),
-				progname, current_walfile_name, stream->walmethod->getlasterror());
+		pg_log_error("could not close file \"%s\": %s",
+					 current_walfile_name, stream->walmethod->getlasterror());
 	walfile = NULL;
 	return false;
 }
@@ -725,9 +705,8 @@ ReadEndOfStreamingResult(PGresult *res, XLogRecPtr *startpos, uint32 *timeline)
 	 */
 	if (PQnfields(res) < 2 || PQntuples(res) != 1)
 	{
-		fprintf(stderr,
-				_("%s: unexpected result set after end-of-timeline: got %d rows and %d fields, expected %d rows and %d fields\n"),
-				progname, PQntuples(res), PQnfields(res), 1, 2);
+		pg_log_error("unexpected result set after end-of-timeline: got %d rows and %d fields, expected %d rows and %d fields",
+					 PQntuples(res), PQnfields(res), 1, 2);
 		return false;
 	}
 
@@ -735,9 +714,8 @@ ReadEndOfStreamingResult(PGresult *res, XLogRecPtr *startpos, uint32 *timeline)
 	if (sscanf(PQgetvalue(res, 0, 1), "%X/%X", &startpos_xlogid,
 			   &startpos_xrecoff) != 2)
 	{
-		fprintf(stderr,
-				_("%s: could not parse next timeline's starting point \"%s\"\n"),
-				progname, PQgetvalue(res, 0, 1));
+		pg_log_error("could not parse next timeline's starting point \"%s\"",
+					 PQgetvalue(res, 0, 1));
 		return false;
 	}
 	*startpos = ((uint64) startpos_xlogid << 32) | startpos_xrecoff;
@@ -785,8 +763,8 @@ HandleCopyStream(PGconn *conn, StreamCtl *stream,
 		{
 			if (stream->walmethod->sync(walfile) != 0)
 			{
-				fprintf(stderr, _("%s: could not fsync file \"%s\": %s\n"),
-						progname, current_walfile_name, stream->walmethod->getlasterror());
+				pg_log_error("could not fsync file \"%s\": %s",
+							 current_walfile_name, stream->walmethod->getlasterror());
 				goto error;
 			}
 			lastFlushPosition = blockpos;
@@ -855,8 +833,8 @@ HandleCopyStream(PGconn *conn, StreamCtl *stream,
 			}
 			else
 			{
-				fprintf(stderr, _("%s: unrecognized streaming header: \"%c\"\n"),
-						progname, copybuf[0]);
+				pg_log_error("unrecognized streaming header: \"%c\"",
+							 copybuf[0]);
 				goto error;
 			}
 
@@ -895,8 +873,7 @@ CopyStreamPoll(PGconn *conn, long timeout_ms, pgsocket stop_socket)
 	connsocket = PQsocket(conn);
 	if (connsocket < 0)
 	{
-		fprintf(stderr, _("%s: invalid socket: %s"), progname,
-				PQerrorMessage(conn));
+		pg_log_error("invalid socket: %s", PQerrorMessage(conn));
 		return -1;
 	}
 
@@ -924,8 +901,7 @@ CopyStreamPoll(PGconn *conn, long timeout_ms, pgsocket stop_socket)
 	{
 		if (errno == EINTR)
 			return 0;			/* Got a signal, so not an error */
-		fprintf(stderr, _("%s: select() failed: %s\n"),
-				progname, strerror(errno));
+		pg_log_error("select() failed: %m");
 		return -1;
 	}
 	if (ret > 0 && FD_ISSET(connsocket, &input_mask))
@@ -975,9 +951,8 @@ CopyStreamReceive(PGconn *conn, long timeout, pgsocket stop_socket,
 		/* Now there is actually data on the socket */
 		if (PQconsumeInput(conn) == 0)
 		{
-			fprintf(stderr,
-					_("%s: could not receive data from WAL stream: %s"),
-					progname, PQerrorMessage(conn));
+			pg_log_error("could not receive data from WAL stream: %s",
+						 PQerrorMessage(conn));
 			return -1;
 		}
 
@@ -990,8 +965,7 @@ CopyStreamReceive(PGconn *conn, long timeout, pgsocket stop_socket,
 		return -2;
 	if (rawlen == -2)
 	{
-		fprintf(stderr, _("%s: could not read COPY data: %s"),
-				progname, PQerrorMessage(conn));
+		pg_log_error("could not read COPY data: %s", PQerrorMessage(conn));
 		return -1;
 	}
 
@@ -1021,8 +995,7 @@ ProcessKeepaliveMsg(PGconn *conn, StreamCtl *stream, char *copybuf, int len,
 
 	if (len < pos + 1)
 	{
-		fprintf(stderr, _("%s: streaming header too small: %d\n"),
-				progname, len);
+		pg_log_error("streaming header too small: %d", len);
 		return false;
 	}
 	replyRequested = copybuf[pos];
@@ -1042,8 +1015,8 @@ ProcessKeepaliveMsg(PGconn *conn, StreamCtl *stream, char *copybuf, int len,
 			 */
 			if (stream->walmethod->sync(walfile) != 0)
 			{
-				fprintf(stderr, _("%s: could not fsync file \"%s\": %s\n"),
-						progname, current_walfile_name, stream->walmethod->getlasterror());
+				pg_log_error("could not fsync file \"%s\": %s",
+							 current_walfile_name, stream->walmethod->getlasterror());
 				return false;
 			}
 			lastFlushPosition = blockpos;
@@ -1088,8 +1061,7 @@ ProcessXLogDataMsg(PGconn *conn, StreamCtl *stream, char *copybuf, int len,
 	hdr_len += 8;				/* sendTime */
 	if (len < hdr_len)
 	{
-		fprintf(stderr, _("%s: streaming header too small: %d\n"),
-				progname, len);
+		pg_log_error("streaming header too small: %d", len);
 		return false;
 	}
 	*blockpos = fe_recvint64(&copybuf[1]);
@@ -1106,9 +1078,8 @@ ProcessXLogDataMsg(PGconn *conn, StreamCtl *stream, char *copybuf, int len,
 		/* No file open yet */
 		if (xlogoff != 0)
 		{
-			fprintf(stderr,
-					_("%s: received write-ahead log record for offset %u with no file open\n"),
-					progname, xlogoff);
+			pg_log_error("received write-ahead log record for offset %u with no file open",
+						 xlogoff);
 			return false;
 		}
 	}
@@ -1117,9 +1088,8 @@ ProcessXLogDataMsg(PGconn *conn, StreamCtl *stream, char *copybuf, int len,
 		/* More data in existing segment */
 		if (stream->walmethod->get_current_pos(walfile) != xlogoff)
 		{
-			fprintf(stderr,
-					_("%s: got WAL data offset %08x, expected %08x\n"),
-					progname, xlogoff, (int) stream->walmethod->get_current_pos(walfile));
+			pg_log_error("got WAL data offset %08x, expected %08x",
+						 xlogoff, (int) stream->walmethod->get_current_pos(walfile));
 			return false;
 		}
 	}
@@ -1152,10 +1122,9 @@ ProcessXLogDataMsg(PGconn *conn, StreamCtl *stream, char *copybuf, int len,
 		if (stream->walmethod->write(walfile, copybuf + hdr_len + bytes_written,
 									 bytes_to_write) != bytes_to_write)
 		{
-			fprintf(stderr,
-					_("%s: could not write %u bytes to WAL file \"%s\": %s\n"),
-					progname, bytes_to_write, current_walfile_name,
-					stream->walmethod->getlasterror());
+			pg_log_error("could not write %u bytes to WAL file \"%s\": %s",
+						 bytes_to_write, current_walfile_name,
+						 stream->walmethod->getlasterror());
 			return false;
 		}
 
@@ -1178,8 +1147,8 @@ ProcessXLogDataMsg(PGconn *conn, StreamCtl *stream, char *copybuf, int len,
 			{
 				if (PQputCopyEnd(conn, NULL) <= 0 || PQflush(conn))
 				{
-					fprintf(stderr, _("%s: could not send copy-end packet: %s"),
-							progname, PQerrorMessage(conn));
+					pg_log_error("could not send copy-end packet: %s",
+								 PQerrorMessage(conn));
 					return false;
 				}
 				still_sending = false;
@@ -1218,9 +1187,8 @@ HandleEndOfCopyStream(PGconn *conn, StreamCtl *stream, char *copybuf,
 		{
 			if (PQputCopyEnd(conn, NULL) <= 0 || PQflush(conn))
 			{
-				fprintf(stderr,
-						_("%s: could not send copy-end packet: %s"),
-						progname, PQerrorMessage(conn));
+				pg_log_error("could not send copy-end packet: %s",
+							 PQerrorMessage(conn));
 				PQclear(res);
 				return NULL;
 			}
@@ -1250,8 +1218,8 @@ CheckCopyStreamStop(PGconn *conn, StreamCtl *stream, XLogRecPtr blockpos,
 		}
 		if (PQputCopyEnd(conn, NULL) <= 0 || PQflush(conn))
 		{
-			fprintf(stderr, _("%s: could not send copy-end packet: %s"),
-					progname, PQerrorMessage(conn));
+			pg_log_error("could not send copy-end packet: %s",
+						 PQerrorMessage(conn));
 			return false;
 		}
 		still_sending = false;
diff --git a/src/bin/pg_basebackup/streamutil.c b/src/bin/pg_basebackup/streamutil.c
index 7e86830ad8..ab2e55d695 100644
--- a/src/bin/pg_basebackup/streamutil.c
+++ b/src/bin/pg_basebackup/streamutil.c
@@ -26,6 +26,7 @@
 #include "common/file_perm.h"
 #include "datatype/timestamp.h"
 #include "fe_utils/connect.h"
+#include "fe_utils/logging.h"
 #include "port/pg_bswap.h"
 #include "pqexpbuffer.h"
 
@@ -90,7 +91,7 @@ GetConnection(void)
 		conn_opts = PQconninfoParse(connection_string, &err_msg);
 		if (conn_opts == NULL)
 		{
-			fprintf(stderr, "%s: %s", progname, err_msg);
+			pg_log_error("%s", err_msg);
 			exit(1);
 		}
 
@@ -183,8 +184,7 @@ GetConnection(void)
 		 */
 		if (!tmpconn)
 		{
-			fprintf(stderr, _("%s: could not connect to server\n"),
-					progname);
+			pg_log_error("could not connect to server");
 			exit(1);
 		}
 
@@ -201,8 +201,8 @@ GetConnection(void)
 
 	if (PQstatus(tmpconn) != CONNECTION_OK)
 	{
-		fprintf(stderr, _("%s: could not connect to server: %s"),
-				progname, PQerrorMessage(tmpconn));
+		pg_log_error("could not connect to server: %s",
+					 PQerrorMessage(tmpconn));
 		PQfinish(tmpconn);
 		free(values);
 		free(keywords);
@@ -230,8 +230,8 @@ GetConnection(void)
 		res = PQexec(tmpconn, ALWAYS_SECURE_SEARCH_PATH_SQL);
 		if (PQresultStatus(res) != PGRES_TUPLES_OK)
 		{
-			fprintf(stderr, _("%s: could not clear search_path: %s"),
-					progname, PQerrorMessage(tmpconn));
+			pg_log_error("could not clear search_path: %s",
+						 PQerrorMessage(tmpconn));
 			PQclear(res);
 			PQfinish(tmpconn);
 			exit(1);
@@ -246,18 +246,14 @@ GetConnection(void)
 	tmpparam = PQparameterStatus(tmpconn, "integer_datetimes");
 	if (!tmpparam)
 	{
-		fprintf(stderr,
-				_("%s: could not determine server setting for integer_datetimes\n"),
-				progname);
+		pg_log_error("could not determine server setting for integer_datetimes");
 		PQfinish(tmpconn);
 		exit(1);
 	}
 
 	if (strcmp(tmpparam, "on") != 0)
 	{
-		fprintf(stderr,
-				_("%s: integer_datetimes compile flag does not match server\n"),
-				progname);
+		pg_log_error("integer_datetimes compile flag does not match server");
 		PQfinish(tmpconn);
 		exit(1);
 	}
@@ -300,17 +296,16 @@ RetrieveWalSegSize(PGconn *conn)
 	res = PQexec(conn, "SHOW wal_segment_size");
 	if (PQresultStatus(res) != PGRES_TUPLES_OK)
 	{
-		fprintf(stderr, _("%s: could not send replication command \"%s\": %s"),
-				progname, "SHOW wal_segment_size", PQerrorMessage(conn));
+		pg_log_error("could not send replication command \"%s\": %s",
+					 "SHOW wal_segment_size", PQerrorMessage(conn));
 
 		PQclear(res);
 		return false;
 	}
 	if (PQntuples(res) != 1 || PQnfields(res) < 1)
 	{
-		fprintf(stderr,
-				_("%s: could not fetch WAL segment size: got %d rows and %d fields, expected %d rows and %d or more fields\n"),
-				progname, PQntuples(res), PQnfields(res), 1, 1);
+		pg_log_error("could not fetch WAL segment size: got %d rows and %d fields, expected %d rows and %d or more fields",
+					 PQntuples(res), PQnfields(res), 1, 1);
 
 		PQclear(res);
 		return false;
@@ -319,8 +314,7 @@ RetrieveWalSegSize(PGconn *conn)
 	/* fetch xlog value and unit from the result */
 	if (sscanf(PQgetvalue(res, 0, 0), "%d%s", &xlog_val, xlog_unit) != 2)
 	{
-		fprintf(stderr, _("%s: WAL segment size could not be parsed\n"),
-				progname);
+		pg_log_error("WAL segment size could not be parsed");
 		return false;
 	}
 
@@ -335,11 +329,10 @@ RetrieveWalSegSize(PGconn *conn)
 
 	if (!IsValidWalSegSize(WalSegSz))
 	{
-		fprintf(stderr,
-				ngettext("%s: WAL segment size must be a power of two between 1 MB and 1 GB, but the remote server reported a value of %d byte\n",
-						 "%s: WAL segment size must be a power of two between 1 MB and 1 GB, but the remote server reported a value of %d bytes\n",
-						 WalSegSz),
-				progname, WalSegSz);
+		pg_log_error(ngettext("WAL segment size must be a power of two between 1 MB and 1 GB, but the remote server reported a value of %d byte",
+							  "WAL segment size must be a power of two between 1 MB and 1 GB, but the remote server reported a value of %d bytes",
+							  WalSegSz),
+					 WalSegSz);
 		return false;
 	}
 
@@ -374,17 +367,16 @@ RetrieveDataDirCreatePerm(PGconn *conn)
 	res = PQexec(conn, "SHOW data_directory_mode");
 	if (PQresultStatus(res) != PGRES_TUPLES_OK)
 	{
-		fprintf(stderr, _("%s: could not send replication command \"%s\": %s"),
-				progname, "SHOW data_directory_mode", PQerrorMessage(conn));
+		pg_log_error("could not send replication command \"%s\": %s",
+					 "SHOW data_directory_mode", PQerrorMessage(conn));
 
 		PQclear(res);
 		return false;
 	}
 	if (PQntuples(res) != 1 || PQnfields(res) < 1)
 	{
-		fprintf(stderr,
-				_("%s: could not fetch group access flag: got %d rows and %d fields, expected %d rows and %d or more fields\n"),
-				progname, PQntuples(res), PQnfields(res), 1, 1);
+		pg_log_error("could not fetch group access flag: got %d rows and %d fields, expected %d rows and %d or more fields",
+					 PQntuples(res), PQnfields(res), 1, 1);
 
 		PQclear(res);
 		return false;
@@ -392,8 +384,8 @@ RetrieveDataDirCreatePerm(PGconn *conn)
 
 	if (sscanf(PQgetvalue(res, 0, 0), "%o", &data_directory_mode) != 1)
 	{
-		fprintf(stderr, _("%s: group access flag could not be parsed: %s\n"),
-				progname, PQgetvalue(res, 0, 0));
+		pg_log_error("group access flag could not be parsed: %s",
+					 PQgetvalue(res, 0, 0));
 
 		PQclear(res);
 		return false;
@@ -427,17 +419,16 @@ RunIdentifySystem(PGconn *conn, char **sysid, TimeLineID *starttli,
 	res = PQexec(conn, "IDENTIFY_SYSTEM");
 	if (PQresultStatus(res) != PGRES_TUPLES_OK)
 	{
-		fprintf(stderr, _("%s: could not send replication command \"%s\": %s"),
-				progname, "IDENTIFY_SYSTEM", PQerrorMessage(conn));
+		pg_log_error("could not send replication command \"%s\": %s",
+					 "IDENTIFY_SYSTEM", PQerrorMessage(conn));
 
 		PQclear(res);
 		return false;
 	}
 	if (PQntuples(res) != 1 || PQnfields(res) < 3)
 	{
-		fprintf(stderr,
-				_("%s: could not identify system: got %d rows and %d fields, expected %d rows and %d or more fields\n"),
-				progname, PQntuples(res), PQnfields(res), 1, 3);
+		pg_log_error("could not identify system: got %d rows and %d fields, expected %d rows and %d or more fields",
+					 PQntuples(res), PQnfields(res), 1, 3);
 
 		PQclear(res);
 		return false;
@@ -456,9 +447,8 @@ RunIdentifySystem(PGconn *conn, char **sysid, TimeLineID *starttli,
 	{
 		if (sscanf(PQgetvalue(res, 0, 2), "%X/%X", &hi, &lo) != 2)
 		{
-			fprintf(stderr,
-					_("%s: could not parse write-ahead log location \"%s\"\n"),
-					progname, PQgetvalue(res, 0, 2));
+			pg_log_error("could not parse write-ahead log location \"%s\"",
+						 PQgetvalue(res, 0, 2));
 
 			PQclear(res);
 			return false;
@@ -474,9 +464,8 @@ RunIdentifySystem(PGconn *conn, char **sysid, TimeLineID *starttli,
 		{
 			if (PQnfields(res) < 4)
 			{
-				fprintf(stderr,
-						_("%s: could not identify system: got %d rows and %d fields, expected %d rows and %d or more fields\n"),
-						progname, PQntuples(res), PQnfields(res), 1, 4);
+				pg_log_error("could not identify system: got %d rows and %d fields, expected %d rows and %d or more fields",
+							 PQntuples(res), PQnfields(res), 1, 4);
 
 				PQclear(res);
 				return false;
@@ -541,8 +530,8 @@ CreateReplicationSlot(PGconn *conn, const char *slot_name, const char *plugin,
 		}
 		else
 		{
-			fprintf(stderr, _("%s: could not send replication command \"%s\": %s"),
-					progname, query->data, PQerrorMessage(conn));
+			pg_log_error("could not send replication command \"%s\": %s",
+						 query->data, PQerrorMessage(conn));
 
 			destroyPQExpBuffer(query);
 			PQclear(res);
@@ -552,10 +541,9 @@ CreateReplicationSlot(PGconn *conn, const char *slot_name, const char *plugin,
 
 	if (PQntuples(res) != 1 || PQnfields(res) != 4)
 	{
-		fprintf(stderr,
-				_("%s: could not create replication slot \"%s\": got %d rows and %d fields, expected %d rows and %d fields\n"),
-				progname, slot_name,
-				PQntuples(res), PQnfields(res), 1, 4);
+		pg_log_error("could not create replication slot \"%s\": got %d rows and %d fields, expected %d rows and %d fields",
+					 slot_name,
+					 PQntuples(res), PQnfields(res), 1, 4);
 
 		destroyPQExpBuffer(query);
 		PQclear(res);
@@ -587,8 +575,8 @@ DropReplicationSlot(PGconn *conn, const char *slot_name)
 	res = PQexec(conn, query->data);
 	if (PQresultStatus(res) != PGRES_COMMAND_OK)
 	{
-		fprintf(stderr, _("%s: could not send replication command \"%s\": %s"),
-				progname, query->data, PQerrorMessage(conn));
+		pg_log_error("could not send replication command \"%s\": %s",
+					 query->data, PQerrorMessage(conn));
 
 		destroyPQExpBuffer(query);
 		PQclear(res);
@@ -597,10 +585,9 @@ DropReplicationSlot(PGconn *conn, const char *slot_name)
 
 	if (PQntuples(res) != 0 || PQnfields(res) != 0)
 	{
-		fprintf(stderr,
-				_("%s: could not drop replication slot \"%s\": got %d rows and %d fields, expected %d rows and %d fields\n"),
-				progname, slot_name,
-				PQntuples(res), PQnfields(res), 0, 0);
+		pg_log_error("could not drop replication slot \"%s\": got %d rows and %d fields, expected %d rows and %d fields",
+					 slot_name,
+					 PQntuples(res), PQnfields(res), 0, 0);
 
 		destroyPQExpBuffer(query);
 		PQclear(res);
diff --git a/src/bin/pg_basebackup/walmethods.c b/src/bin/pg_basebackup/walmethods.c
index 7410af3e63..56e383e4ad 100644
--- a/src/bin/pg_basebackup/walmethods.c
+++ b/src/bin/pg_basebackup/walmethods.c
@@ -155,8 +155,8 @@ dir_open_for_write(const char *pathname, const char *temp_suffix, size_t pad_to_
 	 */
 	if (dir_data->sync)
 	{
-		if (fsync_fname(tmppath, false, progname) != 0 ||
-			fsync_parent_path(tmppath, progname) != 0)
+		if (fsync_fname(tmppath, false) != 0 ||
+			fsync_parent_path(tmppath) != 0)
 		{
 #ifdef HAVE_LIBZ
 			if (dir_data->compression > 0)
@@ -244,7 +244,7 @@ dir_close(Walfile f, WalCloseMethod method)
 			snprintf(tmppath2, sizeof(tmppath2), "%s/%s%s",
 					 dir_data->basedir, df->pathname,
 					 dir_data->compression > 0 ? ".gz" : "");
-			r = durable_rename(tmppath, tmppath2, progname);
+			r = durable_rename(tmppath, tmppath2);
 		}
 		else if (method == CLOSE_UNLINK)
 		{
@@ -264,9 +264,9 @@ dir_close(Walfile f, WalCloseMethod method)
 			 */
 			if (dir_data->sync)
 			{
-				r = fsync_fname(df->fullpath, false, progname);
+				r = fsync_fname(df->fullpath, false);
 				if (r == 0)
-					r = fsync_parent_path(df->fullpath, progname);
+					r = fsync_parent_path(df->fullpath);
 			}
 		}
 	}
@@ -339,7 +339,7 @@ dir_finish(void)
 		 * Files are fsynced when they are closed, but we need to fsync the
 		 * directory entry here as well.
 		 */
-		if (fsync_fname(dir_data->basedir, true, progname) != 0)
+		if (fsync_fname(dir_data->basedir, true) != 0)
 			return false;
 	}
 	return true;
@@ -970,9 +970,9 @@ tar_finish(void)
 
 	if (tar_data->sync)
 	{
-		if (fsync_fname(tar_data->tarfilename, false, progname) != 0)
+		if (fsync_fname(tar_data->tarfilename, false) != 0)
 			return false;
-		if (fsync_parent_path(tar_data->tarfilename, progname) != 0)
+		if (fsync_parent_path(tar_data->tarfilename) != 0)
 			return false;
 	}
 
diff --git a/src/bin/pg_controldata/Makefile b/src/bin/pg_controldata/Makefile
index 2d5c562131..4d9c1370fe 100644
--- a/src/bin/pg_controldata/Makefile
+++ b/src/bin/pg_controldata/Makefile
@@ -15,11 +15,13 @@ subdir = src/bin/pg_controldata
 top_builddir = ../../..
 include $(top_builddir)/src/Makefile.global
 
+LDFLAGS_INTERNAL += -L$(top_builddir)/src/fe_utils -lpgfeutils
+
 OBJS= pg_controldata.o $(WIN32RES)
 
 all: pg_controldata
 
-pg_controldata: $(OBJS) | submake-libpgport
+pg_controldata: $(OBJS) | submake-libpgport submake-libpgfeutils
 	$(CC) $(CFLAGS) $^ $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@$(X)
 
 install: all installdirs
diff --git a/src/bin/pg_controldata/pg_controldata.c b/src/bin/pg_controldata/pg_controldata.c
index 895a51f89d..9bb97a26ec 100644
--- a/src/bin/pg_controldata/pg_controldata.c
+++ b/src/bin/pg_controldata/pg_controldata.c
@@ -24,6 +24,7 @@
 #include "access/xlog_internal.h"
 #include "catalog/pg_control.h"
 #include "common/controldata_utils.h"
+#include "fe_utils/logging.h"
 #include "pg_getopt.h"
 #include "getopt_long.h"
 
@@ -107,7 +108,7 @@ main(int argc, char *argv[])
 	int			WalSegSz;
 
 	set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_controldata"));
-
+	pg_logging_init(argv[0]);
 	progname = get_progname(argv[0]);
 
 	if (argc > 1)
@@ -164,7 +165,7 @@ main(int argc, char *argv[])
 	}
 
 	/* get a copy of the control file */
-	ControlFile = get_controlfile(DataDir, progname, &crc_ok);
+	ControlFile = get_controlfile(DataDir, &crc_ok);
 	if (!crc_ok)
 		printf(_("WARNING: Calculated CRC checksum does not match value stored in file.\n"
 				 "Either the file is corrupt, or it has a different layout than this program\n"
diff --git a/src/bin/pg_ctl/Makefile b/src/bin/pg_ctl/Makefile
index 83cbf97ed8..b931b14a3f 100644
--- a/src/bin/pg_ctl/Makefile
+++ b/src/bin/pg_ctl/Makefile
@@ -16,6 +16,8 @@ subdir = src/bin/pg_ctl
 top_builddir = ../../..
 include $(top_builddir)/src/Makefile.global
 
+LDFLAGS_INTERNAL += -L$(top_builddir)/src/fe_utils -lpgfeutils
+
 # On Windows, we need to link with libpq, just for use of pqexpbuffer;
 # but let's not pull that in on platforms where we don't need it.
 ifeq ($(PORTNAME), win32)
@@ -28,7 +30,7 @@ OBJS=	pg_ctl.o $(WIN32RES)
 
 all: pg_ctl
 
-pg_ctl: $(OBJS) | submake-libpgport $(SUBMAKE_LIBPQ)
+pg_ctl: $(OBJS) | submake-libpgport submake-libpgfeutils $(SUBMAKE_LIBPQ)
 	$(CC) $(CFLAGS) $(OBJS) $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@$(X)
 
 install: all installdirs
diff --git a/src/bin/pg_ctl/pg_ctl.c b/src/bin/pg_ctl/pg_ctl.c
index aadc70113d..4dc1f2ec8f 100644
--- a/src/bin/pg_ctl/pg_ctl.c
+++ b/src/bin/pg_ctl/pg_ctl.c
@@ -26,6 +26,7 @@
 #include "catalog/pg_control.h"
 #include "common/controldata_utils.h"
 #include "common/file_perm.h"
+#include "fe_utils/logging.h"
 #include "getopt_long.h"
 #include "utils/pidfile.h"
 
@@ -2181,7 +2182,7 @@ get_control_dbstate(void)
 {
 	DBState		ret;
 	bool		crc_ok;
-	ControlFileData *control_file_data = get_controlfile(pg_data, progname, &crc_ok);
+	ControlFileData *control_file_data = get_controlfile(pg_data, &crc_ok);
 
 	if (!crc_ok)
 	{
@@ -2224,6 +2225,7 @@ main(int argc, char **argv)
 
 	progname = get_progname(argv[0]);
 	set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_ctl"));
+	pg_logging_init(argv[0]);
 	start_time = time(NULL);
 
 	/*
diff --git a/src/bin/pg_dump/common.c b/src/bin/pg_dump/common.c
index 249706fe57..5958f42a84 100644
--- a/src/bin/pg_dump/common.c
+++ b/src/bin/pg_dump/common.c
@@ -22,6 +22,7 @@
 #include <ctype.h>
 
 #include "catalog/pg_class_d.h"
+#include "fe_utils/logging.h"
 #include "fe_utils/string_utils.h"
 
 
@@ -120,17 +121,14 @@ getSchemaData(Archive *fout, int *numTablesPtr)
 	 * extension membership needs to be consultable during decisions about
 	 * whether other objects are to be dumped.
 	 */
-	if (g_verbose)
-		write_msg(NULL, "reading extensions\n");
+	pg_log_info("reading extensions");
 	extinfo = getExtensions(fout, &numExtensions);
 	extinfoindex = buildIndexArray(extinfo, numExtensions, sizeof(ExtensionInfo));
 
-	if (g_verbose)
-		write_msg(NULL, "identifying extension members\n");
+	pg_log_info("identifying extension members");
 	getExtensionMembership(fout, extinfo, numExtensions);
 
-	if (g_verbose)
-		write_msg(NULL, "reading schemas\n");
+	pg_log_info("reading schemas");
 	nspinfo = getNamespaces(fout, &numNamespaces);
 	nspinfoindex = buildIndexArray(nspinfo, numNamespaces, sizeof(NamespaceInfo));
 
@@ -140,160 +138,124 @@ getSchemaData(Archive *fout, int *numTablesPtr)
 	 * However, we have to do getNamespaces first because the tables get
 	 * linked to their containing namespaces during getTables.
 	 */
-	if (g_verbose)
-		write_msg(NULL, "reading user-defined tables\n");
+	pg_log_info("reading user-defined tables");
 	tblinfo = getTables(fout, &numTables);
 	tblinfoindex = buildIndexArray(tblinfo, numTables, sizeof(TableInfo));
 
 	/* Do this after we've built tblinfoindex */
 	getOwnedSeqs(fout, tblinfo, numTables);
 
-	if (g_verbose)
-		write_msg(NULL, "reading user-defined functions\n");
+	pg_log_info("reading user-defined functions");
 	funinfo = getFuncs(fout, &numFuncs);
 	funinfoindex = buildIndexArray(funinfo, numFuncs, sizeof(FuncInfo));
 
 	/* this must be after getTables and getFuncs */
-	if (g_verbose)
-		write_msg(NULL, "reading user-defined types\n");
+	pg_log_info("reading user-defined types");
 	typinfo = getTypes(fout, &numTypes);
 	typinfoindex = buildIndexArray(typinfo, numTypes, sizeof(TypeInfo));
 
 	/* this must be after getFuncs, too */
-	if (g_verbose)
-		write_msg(NULL, "reading procedural languages\n");
+	pg_log_info("reading procedural languages");
 	getProcLangs(fout, &numProcLangs);
 
-	if (g_verbose)
-		write_msg(NULL, "reading user-defined aggregate functions\n");
+	pg_log_info("reading user-defined aggregate functions");
 	getAggregates(fout, &numAggregates);
 
-	if (g_verbose)
-		write_msg(NULL, "reading user-defined operators\n");
+	pg_log_info("reading user-defined operators");
 	oprinfo = getOperators(fout, &numOperators);
 	oprinfoindex = buildIndexArray(oprinfo, numOperators, sizeof(OprInfo));
 
-	if (g_verbose)
-		write_msg(NULL, "reading user-defined access methods\n");
+	pg_log_info("reading user-defined access methods");
 	getAccessMethods(fout, &numAccessMethods);
 
-	if (g_verbose)
-		write_msg(NULL, "reading user-defined operator classes\n");
+	pg_log_info("reading user-defined operator classes");
 	getOpclasses(fout, &numOpclasses);
 
-	if (g_verbose)
-		write_msg(NULL, "reading user-defined operator families\n");
+	pg_log_info("reading user-defined operator families");
 	getOpfamilies(fout, &numOpfamilies);
 
-	if (g_verbose)
-		write_msg(NULL, "reading user-defined text search parsers\n");
+	pg_log_info("reading user-defined text search parsers");
 	getTSParsers(fout, &numTSParsers);
 
-	if (g_verbose)
-		write_msg(NULL, "reading user-defined text search templates\n");
+	pg_log_info("reading user-defined text search templates");
 	getTSTemplates(fout, &numTSTemplates);
 
-	if (g_verbose)
-		write_msg(NULL, "reading user-defined text search dictionaries\n");
+	pg_log_info("reading user-defined text search dictionaries");
 	getTSDictionaries(fout, &numTSDicts);
 
-	if (g_verbose)
-		write_msg(NULL, "reading user-defined text search configurations\n");
+	pg_log_info("reading user-defined text search configurations");
 	getTSConfigurations(fout, &numTSConfigs);
 
-	if (g_verbose)
-		write_msg(NULL, "reading user-defined foreign-data wrappers\n");
+	pg_log_info("reading user-defined foreign-data wrappers");
 	getForeignDataWrappers(fout, &numForeignDataWrappers);
 
-	if (g_verbose)
-		write_msg(NULL, "reading user-defined foreign servers\n");
+	pg_log_info("reading user-defined foreign servers");
 	getForeignServers(fout, &numForeignServers);
 
-	if (g_verbose)
-		write_msg(NULL, "reading default privileges\n");
+	pg_log_info("reading default privileges");
 	getDefaultACLs(fout, &numDefaultACLs);
 
-	if (g_verbose)
-		write_msg(NULL, "reading user-defined collations\n");
+	pg_log_info("reading user-defined collations");
 	collinfo = getCollations(fout, &numCollations);
 	collinfoindex = buildIndexArray(collinfo, numCollations, sizeof(CollInfo));
 
-	if (g_verbose)
-		write_msg(NULL, "reading user-defined conversions\n");
+	pg_log_info("reading user-defined conversions");
 	getConversions(fout, &numConversions);
 
-	if (g_verbose)
-		write_msg(NULL, "reading type casts\n");
+	pg_log_info("reading type casts");
 	getCasts(fout, &numCasts);
 
-	if (g_verbose)
-		write_msg(NULL, "reading transforms\n");
+	pg_log_info("reading transforms");
 	getTransforms(fout, &numTransforms);
 
-	if (g_verbose)
-		write_msg(NULL, "reading table inheritance information\n");
+	pg_log_info("reading table inheritance information");
 	inhinfo = getInherits(fout, &numInherits);
 
-	if (g_verbose)
-		write_msg(NULL, "reading event triggers\n");
+	pg_log_info("reading event triggers");
 	getEventTriggers(fout, &numEventTriggers);
 
 	/* Identify extension configuration tables that should be dumped */
-	if (g_verbose)
-		write_msg(NULL, "finding extension tables\n");
+	pg_log_info("finding extension tables");
 	processExtensionTables(fout, extinfo, numExtensions);
 
 	/* Link tables to parents, mark parents of target tables interesting */
-	if (g_verbose)
-		write_msg(NULL, "finding inheritance relationships\n");
+	pg_log_info("finding inheritance relationships");
 	flagInhTables(fout, tblinfo, numTables, inhinfo, numInherits);
 
-	if (g_verbose)
-		write_msg(NULL, "reading column info for interesting tables\n");
+	pg_log_info("reading column info for interesting tables");
 	getTableAttrs(fout, tblinfo, numTables);
 
-	if (g_verbose)
-		write_msg(NULL, "flagging inherited columns in subtables\n");
+	pg_log_info("flagging inherited columns in subtables");
 	flagInhAttrs(fout->dopt, tblinfo, numTables);
 
-	if (g_verbose)
-		write_msg(NULL, "reading indexes\n");
+	pg_log_info("reading indexes");
 	getIndexes(fout, tblinfo, numTables);
 
-	if (g_verbose)
-		write_msg(NULL, "flagging indexes in partitioned tables\n");
+	pg_log_info("flagging indexes in partitioned tables");
 	flagInhIndexes(fout, tblinfo, numTables);
 
-	if (g_verbose)
-		write_msg(NULL, "reading extended statistics\n");
+	pg_log_info("reading extended statistics");
 	getExtendedStatistics(fout);
 
-	if (g_verbose)
-		write_msg(NULL, "reading constraints\n");
+	pg_log_info("reading constraints");
 	getConstraints(fout, tblinfo, numTables);
 
-	if (g_verbose)
-		write_msg(NULL, "reading triggers\n");
+	pg_log_info("reading triggers");
 	getTriggers(fout, tblinfo, numTables);
 
-	if (g_verbose)
-		write_msg(NULL, "reading rewrite rules\n");
+	pg_log_info("reading rewrite rules");
 	getRules(fout, &numRules);
 
-	if (g_verbose)
-		write_msg(NULL, "reading policies\n");
+	pg_log_info("reading policies");
 	getPolicies(fout, tblinfo, numTables);
 
-	if (g_verbose)
-		write_msg(NULL, "reading publications\n");
+	pg_log_info("reading publications");
 	getPublications(fout);
 
-	if (g_verbose)
-		write_msg(NULL, "reading publication membership\n");
+	pg_log_info("reading publication membership");
 	getPublicationTables(fout, tblinfo, numTables);
 
-	if (g_verbose)
-		write_msg(NULL, "reading subscriptions\n");
+	pg_log_info("reading subscriptions");
 	getSubscriptions(fout);
 
 	*numTablesPtr = numTables;
@@ -1059,7 +1021,7 @@ findParentsByOid(TableInfo *self,
 				parent = findTableByOid(inhinfo[i].inhparent);
 				if (parent == NULL)
 				{
-					write_msg(NULL, "failed sanity check, parent OID %u of table \"%s\" (OID %u) not found\n",
+					pg_log_error("failed sanity check, parent OID %u of table \"%s\" (OID %u) not found",
 							  inhinfo[i].inhparent,
 							  self->dobj.name,
 							  oid);
@@ -1101,7 +1063,7 @@ parseOidArray(const char *str, Oid *array, int arraysize)
 			{
 				if (argNum >= arraysize)
 				{
-					write_msg(NULL, "could not parse numeric array \"%s\": too many numbers\n", str);
+					pg_log_error("could not parse numeric array \"%s\": too many numbers", str);
 					exit_nicely(1);
 				}
 				temp[j] = '\0';
@@ -1116,7 +1078,7 @@ parseOidArray(const char *str, Oid *array, int arraysize)
 			if (!(isdigit((unsigned char) s) || s == '-') ||
 				j >= sizeof(temp) - 1)
 			{
-				write_msg(NULL, "could not parse numeric array \"%s\": invalid character in number\n", str);
+				pg_log_error("could not parse numeric array \"%s\": invalid character in number", str);
 				exit_nicely(1);
 			}
 			temp[j++] = s;
diff --git a/src/bin/pg_dump/compress_io.c b/src/bin/pg_dump/compress_io.c
index e34e6c5618..9cabe51a28 100644
--- a/src/bin/pg_dump/compress_io.c
+++ b/src/bin/pg_dump/compress_io.c
@@ -74,9 +74,6 @@ struct CompressorState
 #endif
 };
 
-/* translator: this is a module name */
-static const char *modulename = gettext_noop("compress_io");
-
 static void ParseCompressionOption(int compression, CompressionAlgorithm *alg,
 					   int *level);
 
@@ -111,8 +108,7 @@ ParseCompressionOption(int compression, CompressionAlgorithm *alg, int *level)
 		*alg = COMPR_ALG_NONE;
 	else
 	{
-		exit_horribly(modulename, "invalid compression code: %d\n",
-					  compression);
+		fatal("invalid compression code: %d", compression);
 		*alg = COMPR_ALG_NONE;	/* keep compiler quiet */
 	}
 
@@ -135,7 +131,7 @@ AllocateCompressor(int compression, WriteFunc writeF)
 
 #ifndef HAVE_LIBZ
 	if (alg == COMPR_ALG_LIBZ)
-		exit_horribly(modulename, "not built with zlib support\n");
+		fatal("not built with zlib support");
 #endif
 
 	cs = (CompressorState *) pg_malloc0(sizeof(CompressorState));
@@ -171,7 +167,7 @@ ReadDataFromArchive(ArchiveHandle *AH, int compression, ReadFunc readF)
 #ifdef HAVE_LIBZ
 		ReadDataFromArchiveZlib(AH, readF);
 #else
-		exit_horribly(modulename, "not built with zlib support\n");
+		fatal("not built with zlib support");
 #endif
 	}
 }
@@ -189,7 +185,7 @@ WriteDataToArchive(ArchiveHandle *AH, CompressorState *cs,
 #ifdef HAVE_LIBZ
 			WriteDataToArchiveZlib(AH, cs, data, dLen);
 #else
-			exit_horribly(modulename, "not built with zlib support\n");
+			fatal("not built with zlib support");
 #endif
 			break;
 		case COMPR_ALG_NONE:
@@ -238,8 +234,7 @@ InitCompressorZlib(CompressorState *cs, int level)
 	cs->zlibOutSize = ZLIB_OUT_SIZE;
 
 	if (deflateInit(zp, level) != Z_OK)
-		exit_horribly(modulename,
-					  "could not initialize compression library: %s\n",
+		fatal("could not initialize compression library: %s",
 					  zp->msg);
 
 	/* Just be paranoid - maybe End is called after Start, with no Write */
@@ -259,8 +254,7 @@ EndCompressorZlib(ArchiveHandle *AH, CompressorState *cs)
 	DeflateCompressorZlib(AH, cs, true);
 
 	if (deflateEnd(zp) != Z_OK)
-		exit_horribly(modulename,
-					  "could not close compression stream: %s\n", zp->msg);
+		fatal("could not close compression stream: %s", zp->msg);
 
 	free(cs->zlibOut);
 	free(cs->zp);
@@ -277,8 +271,7 @@ DeflateCompressorZlib(ArchiveHandle *AH, CompressorState *cs, bool flush)
 	{
 		res = deflate(zp, flush ? Z_FINISH : Z_NO_FLUSH);
 		if (res == Z_STREAM_ERROR)
-			exit_horribly(modulename,
-						  "could not compress data: %s\n", zp->msg);
+			fatal("could not compress data: %s", zp->msg);
 		if ((flush && (zp->avail_out < cs->zlibOutSize))
 			|| (zp->avail_out == 0)
 			|| (zp->avail_in != 0)
@@ -340,8 +333,7 @@ ReadDataFromArchiveZlib(ArchiveHandle *AH, ReadFunc readF)
 	out = pg_malloc(ZLIB_OUT_SIZE + 1);
 
 	if (inflateInit(zp) != Z_OK)
-		exit_horribly(modulename,
-					  "could not initialize compression library: %s\n",
+		fatal("could not initialize compression library: %s",
 					  zp->msg);
 
 	/* no minimal chunk size for zlib */
@@ -357,8 +349,7 @@ ReadDataFromArchiveZlib(ArchiveHandle *AH, ReadFunc readF)
 
 			res = inflate(zp, 0);
 			if (res != Z_OK && res != Z_STREAM_END)
-				exit_horribly(modulename,
-							  "could not uncompress data: %s\n", zp->msg);
+				fatal("could not uncompress data: %s", zp->msg);
 
 			out[ZLIB_OUT_SIZE - zp->avail_out] = '\0';
 			ahwrite(out, 1, ZLIB_OUT_SIZE - zp->avail_out, AH);
@@ -373,16 +364,14 @@ ReadDataFromArchiveZlib(ArchiveHandle *AH, ReadFunc readF)
 		zp->avail_out = ZLIB_OUT_SIZE;
 		res = inflate(zp, 0);
 		if (res != Z_OK && res != Z_STREAM_END)
-			exit_horribly(modulename,
-						  "could not uncompress data: %s\n", zp->msg);
+			fatal("could not uncompress data: %s", zp->msg);
 
 		out[ZLIB_OUT_SIZE - zp->avail_out] = '\0';
 		ahwrite(out, 1, ZLIB_OUT_SIZE - zp->avail_out, AH);
 	}
 
 	if (inflateEnd(zp) != Z_OK)
-		exit_horribly(modulename,
-					  "could not close compression library: %s\n", zp->msg);
+		fatal("could not close compression library: %s", zp->msg);
 
 	free(buf);
 	free(out);
@@ -516,7 +505,7 @@ cfopen_write(const char *path, const char *mode, int compression)
 		fp = cfopen(fname, mode, compression);
 		free_keep_errno(fname);
 #else
-		exit_horribly(modulename, "not built with zlib support\n");
+		fatal("not built with zlib support");
 		fp = NULL;				/* keep compiler quiet */
 #endif
 	}
@@ -559,7 +548,7 @@ cfopen(const char *path, const char *mode, int compression)
 			fp = NULL;
 		}
 #else
-		exit_horribly(modulename, "not built with zlib support\n");
+		fatal("not built with zlib support");
 #endif
 	}
 	else
@@ -596,8 +585,7 @@ cfread(void *ptr, int size, cfp *fp)
 			int			errnum;
 			const char *errmsg = gzerror(fp->compressedfp, &errnum);
 
-			exit_horribly(modulename,
-						  "could not read from input file: %s\n",
+			fatal("could not read from input file: %s",
 						  errnum == Z_ERRNO ? strerror(errno) : errmsg);
 		}
 	}
@@ -634,11 +622,9 @@ cfgetc(cfp *fp)
 		if (ret == EOF)
 		{
 			if (!gzeof(fp->compressedfp))
-				exit_horribly(modulename,
-							  "could not read from input file: %s\n", strerror(errno));
+				fatal("could not read from input file: %s", strerror(errno));
 			else
-				exit_horribly(modulename,
-							  "could not read from input file: end of file\n");
+				fatal("could not read from input file: end of file");
 		}
 	}
 	else
diff --git a/src/bin/pg_dump/nls.mk b/src/bin/pg_dump/nls.mk
index 37234717cb..378635fbcc 100644
--- a/src/bin/pg_dump/nls.mk
+++ b/src/bin/pg_dump/nls.mk
@@ -1,7 +1,8 @@
 # src/bin/pg_dump/nls.mk
 CATALOG_NAME     = pg_dump
 AVAIL_LANGUAGES  = cs de es fr he it ja ko pl pt_BR ru sv tr zh_CN
-GETTEXT_FILES    = pg_backup_archiver.c pg_backup_db.c pg_backup_custom.c \
+GETTEXT_FILES    = $(FRONTEND_COMMON_GETTEXT_FILES) \
+                   pg_backup_archiver.c pg_backup_db.c pg_backup_custom.c \
                    pg_backup_null.c pg_backup_tar.c \
                    pg_backup_directory.c dumputils.c compress_io.c \
                    pg_dump.c common.c pg_dump_sort.c \
@@ -9,10 +10,10 @@ GETTEXT_FILES    = pg_backup_archiver.c pg_backup_db.c pg_backup_custom.c \
                    parallel.c parallel.h pg_backup_utils.c pg_backup_utils.h \
                    ../../common/exec.c ../../common/fe_memutils.c \
                    ../../common/wait_error.c
-GETTEXT_TRIGGERS = write_msg:2 exit_horribly:2 simple_prompt \
-                   ExecuteSqlCommand:3 ahlog:3 warn_or_exit_horribly:3
-GETTEXT_FLAGS  = \
+GETTEXT_TRIGGERS = $(FRONTEND_COMMON_GETTEXT_TRIGGERS) \
+                   fatal write_msg:2 simple_prompt \
+                   ExecuteSqlCommand:3 warn_or_exit_horribly:3
+GETTEXT_FLAGS    = $(FRONTEND_COMMON_GETTEXT_FLAGS) \
+    fatal:1:c-format \
     write_msg:2:c-format \
-    exit_horribly:2:c-format \
-    ahlog:3:c-format \
     warn_or_exit_horribly:3:c-format
diff --git a/src/bin/pg_dump/parallel.c b/src/bin/pg_dump/parallel.c
index 96b2c0be50..c294dffd95 100644
--- a/src/bin/pg_dump/parallel.c
+++ b/src/bin/pg_dump/parallel.c
@@ -197,8 +197,6 @@ bool		parallel_init_done = false;
 DWORD		mainThreadId;
 #endif							/* WIN32 */
 
-static const char *modulename = gettext_noop("parallel archiver");
-
 /* Local function prototypes */
 static ParallelSlot *GetMyPSlot(ParallelState *pstate);
 static void archive_close_connection(int code, void *arg);
@@ -406,8 +404,8 @@ archive_close_connection(int code, void *arg)
  * Forcibly shut down any remaining workers, waiting for them to finish.
  *
  * Note that we don't expect to come here during normal exit (the workers
- * should be long gone, and the ParallelState too).  We're only here in an
- * exit_horribly() situation, so intervening to cancel active commands is
+ * should be long gone, and the ParallelState too).  We're only here in a
+ * fatal() situation, so intervening to cancel active commands is
  * appropriate.
  */
 static void
@@ -699,7 +697,7 @@ consoleHandler(DWORD dwCtrlType)
 
 		/*
 		 * Report we're quitting, using nothing more complicated than
-		 * write(2).  (We might be able to get away with using write_msg()
+		 * write(2).  (We might be able to get away with using pg_log_*()
 		 * here, but since we terminated other threads uncleanly above, it
 		 * seems better to assume as little as possible.)
 		 */
@@ -969,9 +967,7 @@ ParallelBackupStart(ArchiveHandle *AH)
 
 		/* Create communication pipes for this worker */
 		if (pgpipe(pipeMW) < 0 || pgpipe(pipeWM) < 0)
-			exit_horribly(modulename,
-						  "could not create communication channels: %s\n",
-						  strerror(errno));
+			fatal("could not create communication channels: %m");
 
 		pstate->te[i] = NULL;	/* just for safety */
 
@@ -1034,9 +1030,7 @@ ParallelBackupStart(ArchiveHandle *AH)
 		else if (pid < 0)
 		{
 			/* fork failed */
-			exit_horribly(modulename,
-						  "could not create worker process: %s\n",
-						  strerror(errno));
+			fatal("could not create worker process: %m");
 		}
 
 		/* In Master after successful fork */
@@ -1165,8 +1159,7 @@ parseWorkerCommand(ArchiveHandle *AH, TocEntry **te, T_Action *act,
 		Assert(*te != NULL);
 	}
 	else
-		exit_horribly(modulename,
-					  "unrecognized command received from master: \"%s\"\n",
+		fatal("unrecognized command received from master: \"%s\"",
 					  msg);
 }
 
@@ -1209,8 +1202,7 @@ parseWorkerResponse(ArchiveHandle *AH, TocEntry *te,
 		AH->public.n_errors += n_errors;
 	}
 	else
-		exit_horribly(modulename,
-					  "invalid message received from worker: \"%s\"\n",
+		fatal("invalid message received from worker: \"%s\"",
 					  msg);
 
 	return status;
@@ -1342,11 +1334,10 @@ lockTableForWorker(ArchiveHandle *AH, TocEntry *te)
 	res = PQexec(AH->connection, query->data);
 
 	if (!res || PQresultStatus(res) != PGRES_COMMAND_OK)
-		exit_horribly(modulename,
-					  "could not obtain lock on relation \"%s\"\n"
-					  "This usually means that someone requested an ACCESS EXCLUSIVE lock "
-					  "on the table after the pg_dump parent process had gotten the "
-					  "initial ACCESS SHARE lock on the table.\n", qualId);
+		fatal("could not obtain lock on relation \"%s\"\n"
+			  "This usually means that someone requested an ACCESS EXCLUSIVE lock "
+			  "on the table after the pg_dump parent process had gotten the "
+			  "initial ACCESS SHARE lock on the table.", qualId);
 
 	PQclear(res);
 	destroyPQExpBuffer(query);
@@ -1432,7 +1423,7 @@ ListenToWorkers(ArchiveHandle *AH, ParallelState *pstate, bool do_wait)
 	{
 		/* If do_wait is true, we must have detected EOF on some socket */
 		if (do_wait)
-			exit_horribly(modulename, "a worker process died unexpectedly\n");
+			fatal("a worker process died unexpectedly");
 		return false;
 	}
 
@@ -1449,8 +1440,7 @@ ListenToWorkers(ArchiveHandle *AH, ParallelState *pstate, bool do_wait)
 		pstate->te[worker] = NULL;
 	}
 	else
-		exit_horribly(modulename,
-					  "invalid message received from worker: \"%s\"\n",
+		fatal("invalid message received from worker: \"%s\"",
 					  msg);
 
 	/* Free the string returned from getMessageFromWorker */
@@ -1555,9 +1545,7 @@ sendMessageToMaster(int pipefd[2], const char *str)
 	int			len = strlen(str) + 1;
 
 	if (pipewrite(pipefd[PIPE_WRITE], str, len) != len)
-		exit_horribly(modulename,
-					  "could not write to the communication channel: %s\n",
-					  strerror(errno));
+		fatal("could not write to the communication channel: %m");
 }
 
 /*
@@ -1634,7 +1622,7 @@ getMessageFromWorker(ParallelState *pstate, bool do_wait, int *worker)
 	}
 
 	if (i < 0)
-		exit_horribly(modulename, "select() failed: %s\n", strerror(errno));
+		fatal("select() failed: %m");
 
 	for (i = 0; i < pstate->numWorkers; i++)
 	{
@@ -1673,9 +1661,7 @@ sendMessageToWorker(ParallelState *pstate, int worker, const char *str)
 
 	if (pipewrite(pstate->parallelSlot[worker].pipeWrite, str, len) != len)
 	{
-		exit_horribly(modulename,
-					  "could not write to the communication channel: %s\n",
-					  strerror(errno));
+		fatal("could not write to the communication channel: %m");
 	}
 }
 
@@ -1759,7 +1745,7 @@ pgpipe(int handles[2])
 	 */
 	if ((s = socket(AF_INET, SOCK_STREAM, 0)) == PGINVALID_SOCKET)
 	{
-		write_msg(modulename, "pgpipe: could not create socket: error code %d\n",
+		pg_log_error("pgpipe: could not create socket: error code %d",
 				  WSAGetLastError());
 		return -1;
 	}
@@ -1770,21 +1756,21 @@ pgpipe(int handles[2])
 	serv_addr.sin_addr.s_addr = pg_hton32(INADDR_LOOPBACK);
 	if (bind(s, (SOCKADDR *) &serv_addr, len) == SOCKET_ERROR)
 	{
-		write_msg(modulename, "pgpipe: could not bind: error code %d\n",
+		pg_log_error("pgpipe: could not bind: error code %d",
 				  WSAGetLastError());
 		closesocket(s);
 		return -1;
 	}
 	if (listen(s, 1) == SOCKET_ERROR)
 	{
-		write_msg(modulename, "pgpipe: could not listen: error code %d\n",
+		pg_log_error("pgpipe: could not listen: error code %d",
 				  WSAGetLastError());
 		closesocket(s);
 		return -1;
 	}
 	if (getsockname(s, (SOCKADDR *) &serv_addr, &len) == SOCKET_ERROR)
 	{
-		write_msg(modulename, "pgpipe: getsockname() failed: error code %d\n",
+		pg_log_error("pgpipe: getsockname() failed: error code %d",
 				  WSAGetLastError());
 		closesocket(s);
 		return -1;
@@ -1795,7 +1781,7 @@ pgpipe(int handles[2])
 	 */
 	if ((tmp_sock = socket(AF_INET, SOCK_STREAM, 0)) == PGINVALID_SOCKET)
 	{
-		write_msg(modulename, "pgpipe: could not create second socket: error code %d\n",
+		pg_log_error("pgpipe: could not create second socket: error code %d",
 				  WSAGetLastError());
 		closesocket(s);
 		return -1;
@@ -1804,7 +1790,7 @@ pgpipe(int handles[2])
 
 	if (connect(handles[1], (SOCKADDR *) &serv_addr, len) == SOCKET_ERROR)
 	{
-		write_msg(modulename, "pgpipe: could not connect socket: error code %d\n",
+		pg_log_error("pgpipe: could not connect socket: error code %d",
 				  WSAGetLastError());
 		closesocket(handles[1]);
 		handles[1] = -1;
@@ -1813,7 +1799,7 @@ pgpipe(int handles[2])
 	}
 	if ((tmp_sock = accept(s, (SOCKADDR *) &serv_addr, &len)) == PGINVALID_SOCKET)
 	{
-		write_msg(modulename, "pgpipe: could not accept connection: error code %d\n",
+		pg_log_error("pgpipe: could not accept connection: error code %d",
 				  WSAGetLastError());
 		closesocket(handles[1]);
 		handles[1] = -1;
diff --git a/src/bin/pg_dump/pg_backup_archiver.c b/src/bin/pg_dump/pg_backup_archiver.c
index 2c2f6fb4a9..83a9335aa6 100644
--- a/src/bin/pg_dump/pg_backup_archiver.c
+++ b/src/bin/pg_dump/pg_backup_archiver.c
@@ -35,6 +35,7 @@
 #include "pg_backup_db.h"
 #include "pg_backup_utils.h"
 #include "dumputils.h"
+#include "fe_utils/logging.h"
 #include "fe_utils/string_utils.h"
 
 #include "libpq/libpq-fs.h"
@@ -271,8 +272,7 @@ CloseArchive(Archive *AHX)
 		res = fclose(AH->OF);
 
 	if (res != 0)
-		exit_horribly(modulename, "could not close output file: %s\n",
-					  strerror(errno));
+		fatal("could not close output file: %m");
 }
 
 /* Public */
@@ -316,19 +316,17 @@ ProcessArchiveRestoreOptions(Archive *AHX)
 					break;
 				case SECTION_PRE_DATA:
 					if (curSection != SECTION_PRE_DATA)
-						write_msg(modulename,
-								  "WARNING: archive items not in correct section order\n");
+						pg_log_warning("archive items not in correct section order");
 					break;
 				case SECTION_DATA:
 					if (curSection == SECTION_POST_DATA)
-						write_msg(modulename,
-								  "WARNING: archive items not in correct section order\n");
+						pg_log_warning("archive items not in correct section order");
 					break;
 				case SECTION_POST_DATA:
 					/* ok no matter which section we were in */
 					break;
 				default:
-					exit_horribly(modulename, "unexpected section code %d\n",
+					fatal("unexpected section code %d",
 								  (int) te->section);
 					break;
 			}
@@ -365,11 +363,11 @@ RestoreArchive(Archive *AHX)
 	{
 		/* We haven't got round to making this work for all archive formats */
 		if (AH->ClonePtr == NULL || AH->ReopenPtr == NULL)
-			exit_horribly(modulename, "parallel restore is not supported with this archive file format\n");
+			fatal("parallel restore is not supported with this archive file format");
 
 		/* Doesn't work if the archive represents dependencies as OIDs */
 		if (AH->version < K_VERS_1_8)
-			exit_horribly(modulename, "parallel restore is not supported with archives made by pre-8.0 pg_dump\n");
+			fatal("parallel restore is not supported with archives made by pre-8.0 pg_dump");
 
 		/*
 		 * It's also not gonna work if we can't reopen the input file, so
@@ -387,7 +385,7 @@ RestoreArchive(Archive *AHX)
 		for (te = AH->toc->next; te != AH->toc; te = te->next)
 		{
 			if (te->hadDumper && (te->reqs & REQ_DATA) != 0)
-				exit_horribly(modulename, "cannot restore from compressed archive (compression not supported in this installation)\n");
+				fatal("cannot restore from compressed archive (compression not supported in this installation)");
 		}
 	}
 #endif
@@ -404,9 +402,9 @@ RestoreArchive(Archive *AHX)
 	 */
 	if (ropt->useDB)
 	{
-		ahlog(AH, 1, "connecting to database for restore\n");
+		pg_log_info("connecting to database for restore");
 		if (AH->version < K_VERS_1_3)
-			exit_horribly(modulename, "direct database connections are not supported in pre-1.3 archives\n");
+			fatal("direct database connections are not supported in pre-1.3 archives");
 
 		/*
 		 * We don't want to guess at whether the dump will successfully
@@ -451,7 +449,7 @@ RestoreArchive(Archive *AHX)
 		if (impliedDataOnly)
 		{
 			ropt->dataOnly = impliedDataOnly;
-			ahlog(AH, 1, "implied data-only restore\n");
+			pg_log_info("implied data-only restore");
 		}
 	}
 
@@ -517,7 +515,7 @@ RestoreArchive(Archive *AHX)
 			/* Otherwise, drop anything that's selected and has a dropStmt */
 			if (((te->reqs & (REQ_SCHEMA | REQ_DATA)) != 0) && te->dropStmt)
 			{
-				ahlog(AH, 1, "dropping %s %s\n", te->desc, te->tag);
+				pg_log_info("dropping %s %s", te->desc, te->tag);
 				/* Select owner and schema as necessary */
 				_becomeOwner(AH, te);
 				_selectOutputSchema(AH, te->namespace);
@@ -612,8 +610,7 @@ RestoreArchive(Archive *AHX)
 								else
 								{
 									/* complain and emit unmodified command */
-									write_msg(modulename,
-											  "WARNING: could not find where to insert IF EXISTS in statement \"%s\"\n",
+									pg_log_warning("could not find where to insert IF EXISTS in statement \"%s\"",
 											  dropStmtOrig);
 									appendPQExpBufferStr(ftStmt, dropStmt);
 								}
@@ -769,9 +766,9 @@ restore_toc_entry(ArchiveHandle *AH, TocEntry *te, bool is_parallel)
 	if (!ropt->suppressDumpWarnings && strcmp(te->desc, "WARNING") == 0)
 	{
 		if (!ropt->dataOnly && te->defn != NULL && strlen(te->defn) != 0)
-			write_msg(modulename, "warning from original dump file: %s\n", te->defn);
+			pg_log_warning("warning from original dump file: %s", te->defn);
 		else if (te->copyStmt != NULL && strlen(te->copyStmt) != 0)
-			write_msg(modulename, "warning from original dump file: %s\n", te->copyStmt);
+			pg_log_warning("warning from original dump file: %s", te->copyStmt);
 	}
 
 	/* Work out what, if anything, we want from this entry */
@@ -786,10 +783,11 @@ restore_toc_entry(ArchiveHandle *AH, TocEntry *te, bool is_parallel)
 	{
 		/* Show namespace in log message if available */
 		if (te->namespace)
-			ahlog(AH, 1, "creating %s \"%s.%s\"\n",
-				  te->desc, te->namespace, te->tag);
+			pg_log_info("creating %s \"%s.%s\"",
+						te->desc, te->namespace, te->tag);
 		else
-			ahlog(AH, 1, "creating %s \"%s\"\n", te->desc, te->tag);
+			pg_log_info("creating %s \"%s\"",
+						te->desc, te->tag);
 
 		_printTocEntry(AH, te, false);
 		defnDumped = true;
@@ -845,7 +843,7 @@ restore_toc_entry(ArchiveHandle *AH, TocEntry *te, bool is_parallel)
 			appendConnStrVal(&connstr, te->tag);
 			/* Abandon struct, but keep its buffer until process exit. */
 
-			ahlog(AH, 1, "connecting to new database \"%s\"\n", te->tag);
+			pg_log_info("connecting to new database \"%s\"", te->tag);
 			_reconnectToDB(AH, te->tag);
 			ropt->dbname = connstr.data;
 		}
@@ -873,7 +871,7 @@ restore_toc_entry(ArchiveHandle *AH, TocEntry *te, bool is_parallel)
 				if (strcmp(te->desc, "BLOBS") == 0 ||
 					strcmp(te->desc, "BLOB COMMENTS") == 0)
 				{
-					ahlog(AH, 1, "processing %s\n", te->desc);
+					pg_log_info("processing %s", te->desc);
 
 					_selectOutputSchema(AH, "pg_catalog");
 
@@ -893,7 +891,7 @@ restore_toc_entry(ArchiveHandle *AH, TocEntry *te, bool is_parallel)
 					_becomeOwner(AH, te);
 					_selectOutputSchema(AH, te->namespace);
 
-					ahlog(AH, 1, "processing data for table \"%s.%s\"\n",
+					pg_log_info("processing data for table \"%s.%s\"",
 						  te->namespace, te->tag);
 
 					/*
@@ -955,7 +953,7 @@ restore_toc_entry(ArchiveHandle *AH, TocEntry *te, bool is_parallel)
 		else if (!defnDumped)
 		{
 			/* If we haven't already dumped the defn part, do so now */
-			ahlog(AH, 1, "executing %s %s\n", te->desc, te->tag);
+			pg_log_info("executing %s %s", te->desc, te->tag);
 			_printTocEntry(AH, te, false);
 		}
 	}
@@ -994,7 +992,7 @@ _disableTriggersIfNecessary(ArchiveHandle *AH, TocEntry *te)
 	if (!ropt->dataOnly || !ropt->disable_triggers)
 		return;
 
-	ahlog(AH, 1, "disabling triggers for %s\n", te->tag);
+	pg_log_info("disabling triggers for %s", te->tag);
 
 	/*
 	 * Become superuser if possible, since they are the only ones who can
@@ -1020,7 +1018,7 @@ _enableTriggersIfNecessary(ArchiveHandle *AH, TocEntry *te)
 	if (!ropt->dataOnly || !ropt->disable_triggers)
 		return;
 
-	ahlog(AH, 1, "enabling triggers for %s\n", te->tag);
+	pg_log_info("enabling triggers for %s", te->tag);
 
 	/*
 	 * Become superuser if possible, since they are the only ones who can
@@ -1048,7 +1046,7 @@ WriteData(Archive *AHX, const void *data, size_t dLen)
 	ArchiveHandle *AH = (ArchiveHandle *) AHX;
 
 	if (!AH->currToc)
-		exit_horribly(modulename, "internal error -- WriteData cannot be called outside the context of a DataDumper routine\n");
+		fatal("internal error -- WriteData cannot be called outside the context of a DataDumper routine");
 
 	AH->WriteDataPtr(AH, data, dLen);
 
@@ -1252,7 +1250,7 @@ StartBlob(Archive *AHX, Oid oid)
 	ArchiveHandle *AH = (ArchiveHandle *) AHX;
 
 	if (!AH->StartBlobPtr)
-		exit_horribly(modulename, "large-object output not supported in chosen format\n");
+		fatal("large-object output not supported in chosen format");
 
 	AH->StartBlobPtr(AH, AH->currToc, oid);
 
@@ -1310,8 +1308,8 @@ EndRestoreBlobs(ArchiveHandle *AH)
 			ahprintf(AH, "COMMIT;\n\n");
 	}
 
-	ahlog(AH, 1, ngettext("restored %d large object\n",
-						  "restored %d large objects\n",
+	pg_log_info(ngettext("restored %d large object",
+						 "restored %d large objects",
 						  AH->blobCount),
 		  AH->blobCount);
 }
@@ -1331,7 +1329,7 @@ StartRestoreBlob(ArchiveHandle *AH, Oid oid, bool drop)
 	/* Initialize the LO Buffer */
 	AH->lo_buf_used = 0;
 
-	ahlog(AH, 1, "restoring large object with OID %u\n", oid);
+	pg_log_info("restoring large object with OID %u", oid);
 
 	/* With an old archive we must do drop and create logic here */
 	if (old_blob_style && drop)
@@ -1343,12 +1341,12 @@ StartRestoreBlob(ArchiveHandle *AH, Oid oid, bool drop)
 		{
 			loOid = lo_create(AH->connection, oid);
 			if (loOid == 0 || loOid != oid)
-				exit_horribly(modulename, "could not create large object %u: %s",
+				fatal("could not create large object %u: %s",
 							  oid, PQerrorMessage(AH->connection));
 		}
 		AH->loFd = lo_open(AH->connection, oid, INV_WRITE);
 		if (AH->loFd == -1)
-			exit_horribly(modulename, "could not open large object %u: %s",
+			fatal("could not open large object %u: %s",
 						  oid, PQerrorMessage(AH->connection));
 	}
 	else
@@ -1406,8 +1404,7 @@ SortTocFromFile(Archive *AHX)
 	/* Setup the file */
 	fh = fopen(ropt->tocFile, PG_BINARY_R);
 	if (!fh)
-		exit_horribly(modulename, "could not open TOC file \"%s\": %s\n",
-					  ropt->tocFile, strerror(errno));
+		fatal("could not open TOC file \"%s\": %m", ropt->tocFile);
 
 	incomplete_line = false;
 	while (fgets(buf, sizeof(buf), fh) != NULL)
@@ -1447,14 +1444,14 @@ SortTocFromFile(Archive *AHX)
 		if (endptr == buf || id <= 0 || id > AH->maxDumpId ||
 			ropt->idWanted[id - 1])
 		{
-			write_msg(modulename, "WARNING: line ignored: %s\n", buf);
+			pg_log_warning("line ignored: %s", buf);
 			continue;
 		}
 
 		/* Find TOC entry */
 		te = getTocEntryByDumpId(AH, id);
 		if (!te)
-			exit_horribly(modulename, "could not find entry for ID %d\n",
+			fatal("could not find entry for ID %d",
 						  id);
 
 		/* Mark it wanted */
@@ -1475,8 +1472,7 @@ SortTocFromFile(Archive *AHX)
 	}
 
 	if (fclose(fh) != 0)
-		exit_horribly(modulename, "could not close TOC file: %s\n",
-					  strerror(errno));
+		fatal("could not close TOC file: %m");
 }
 
 /**********************
@@ -1586,11 +1582,9 @@ SetOutput(ArchiveHandle *AH, const char *filename, int compression)
 	if (!AH->OF)
 	{
 		if (filename)
-			exit_horribly(modulename, "could not open output file \"%s\": %s\n",
-						  filename, strerror(errno));
+			fatal("could not open output file \"%s\": %m", filename);
 		else
-			exit_horribly(modulename, "could not open output file: %s\n",
-						  strerror(errno));
+			fatal("could not open output file: %m");
 	}
 }
 
@@ -1616,8 +1610,7 @@ RestoreOutput(ArchiveHandle *AH, OutputContext savedContext)
 		res = fclose(AH->OF);
 
 	if (res != 0)
-		exit_horribly(modulename, "could not close output file: %s\n",
-					  strerror(errno));
+		fatal("could not close output file: %m");
 
 	AH->gzOut = savedContext.gzOut;
 	AH->OF = savedContext.OF;
@@ -1662,19 +1655,6 @@ ahprintf(ArchiveHandle *AH, const char *fmt,...)
 	return (int) cnt;
 }
 
-void
-ahlog(ArchiveHandle *AH, int level, const char *fmt,...)
-{
-	va_list		ap;
-
-	if (AH->debugLevel < level && (!AH->public.verbose || level > 1))
-		return;
-
-	va_start(ap, fmt);
-	vwrite_msg(NULL, fmt, ap);
-	va_end(ap);
-}
-
 /*
  * Single place for logic which says 'We are restoring to a direct DB connection'.
  */
@@ -1697,13 +1677,12 @@ dump_lo_buf(ArchiveHandle *AH)
 		size_t		res;
 
 		res = lo_write(AH->connection, AH->loFd, AH->lo_buf, AH->lo_buf_used);
-		ahlog(AH, 5, ngettext("wrote %lu byte of large object data (result = %lu)\n",
+		pg_log_debug(ngettext("wrote %lu byte of large object data (result = %lu)\n",
 							  "wrote %lu bytes of large object data (result = %lu)\n",
 							  AH->lo_buf_used),
 			  (unsigned long) AH->lo_buf_used, (unsigned long) res);
 		if (res != AH->lo_buf_used)
-			exit_horribly(modulename,
-						  "could not write to large object (result: %lu, expected: %lu)\n",
+			fatal("could not write to large object (result: %lu, expected: %lu)",
 						  (unsigned long) res, (unsigned long) AH->lo_buf_used);
 	}
 	else
@@ -1884,7 +1863,7 @@ buildTocEntryArrays(ArchiveHandle *AH)
 	{
 		/* this check is purely paranoia, maxDumpId should be correct */
 		if (te->dumpId <= 0 || te->dumpId > maxDumpId)
-			exit_horribly(modulename, "bad dumpId\n");
+			fatal("bad dumpId");
 
 		/* tocsByDumpId indexes all TOCs by their dump ID */
 		AH->tocsByDumpId[te->dumpId] = te;
@@ -1905,7 +1884,7 @@ buildTocEntryArrays(ArchiveHandle *AH)
 			 * item's dump ID, so there should be a place for it in the array.
 			 */
 			if (tableId <= 0 || tableId > maxDumpId)
-				exit_horribly(modulename, "bad table dumpId for TABLE DATA item\n");
+				fatal("bad table dumpId for TABLE DATA item");
 
 			AH->tableDataId[tableId] = te->dumpId;
 		}
@@ -1997,7 +1976,7 @@ ReadOffset(ArchiveHandle *AH, pgoff_t * o)
 			break;
 
 		default:
-			exit_horribly(modulename, "unexpected data offset flag %d\n", offsetFlg);
+			fatal("unexpected data offset flag %d", offsetFlg);
 	}
 
 	/*
@@ -2010,7 +1989,7 @@ ReadOffset(ArchiveHandle *AH, pgoff_t * o)
 		else
 		{
 			if (AH->ReadBytePtr(AH) != 0)
-				exit_horribly(modulename, "file offset in dump file is too large\n");
+				fatal("file offset in dump file is too large");
 		}
 	}
 
@@ -2122,9 +2101,7 @@ _discoverArchiveFormat(ArchiveHandle *AH)
 	size_t		cnt;
 	int			wantClose = 0;
 
-#if 0
-	write_msg(modulename, "attempting to ascertain archive format\n");
-#endif
+	pg_log_debug("attempting to ascertain archive format");
 
 	if (AH->lookahead)
 		free(AH->lookahead);
@@ -2149,7 +2126,7 @@ _discoverArchiveFormat(ArchiveHandle *AH)
 			char		buf[MAXPGPATH];
 
 			if (snprintf(buf, MAXPGPATH, "%s/toc.dat", AH->fSpec) >= MAXPGPATH)
-				exit_horribly(modulename, "directory name too long: \"%s\"\n",
+				fatal("directory name too long: \"%s\"",
 							  AH->fSpec);
 			if (stat(buf, &st) == 0 && S_ISREG(st.st_mode))
 			{
@@ -2159,7 +2136,7 @@ _discoverArchiveFormat(ArchiveHandle *AH)
 
 #ifdef HAVE_LIBZ
 			if (snprintf(buf, MAXPGPATH, "%s/toc.dat.gz", AH->fSpec) >= MAXPGPATH)
-				exit_horribly(modulename, "directory name too long: \"%s\"\n",
+				fatal("directory name too long: \"%s\"",
 							  AH->fSpec);
 			if (stat(buf, &st) == 0 && S_ISREG(st.st_mode))
 			{
@@ -2167,7 +2144,7 @@ _discoverArchiveFormat(ArchiveHandle *AH)
 				return AH->format;
 			}
 #endif
-			exit_horribly(modulename, "directory \"%s\" does not appear to be a valid archive (\"toc.dat\" does not exist)\n",
+			fatal("directory \"%s\" does not appear to be a valid archive (\"toc.dat\" does not exist)",
 						  AH->fSpec);
 			fh = NULL;			/* keep compiler quiet */
 		}
@@ -2175,24 +2152,22 @@ _discoverArchiveFormat(ArchiveHandle *AH)
 		{
 			fh = fopen(AH->fSpec, PG_BINARY_R);
 			if (!fh)
-				exit_horribly(modulename, "could not open input file \"%s\": %s\n",
-							  AH->fSpec, strerror(errno));
+				fatal("could not open input file \"%s\": %m", AH->fSpec);
 		}
 	}
 	else
 	{
 		fh = stdin;
 		if (!fh)
-			exit_horribly(modulename, "could not open input file: %s\n",
-						  strerror(errno));
+			fatal("could not open input file: %m");
 	}
 
 	if ((cnt = fread(sig, 1, 5, fh)) != 5)
 	{
 		if (ferror(fh))
-			exit_horribly(modulename, "could not read input file: %s\n", strerror(errno));
+			fatal("could not read input file: %m");
 		else
-			exit_horribly(modulename, "input file is too short (read %lu, expected 5)\n",
+			fatal("input file is too short (read %lu, expected 5)",
 						  (unsigned long) cnt);
 	}
 
@@ -2277,19 +2252,19 @@ _discoverArchiveFormat(ArchiveHandle *AH)
 			 * looks like it's probably a text format dump. so suggest they
 			 * try psql
 			 */
-			exit_horribly(modulename, "input file appears to be a text format dump. Please use psql.\n");
+			fatal("input file appears to be a text format dump. Please use psql.");
 		}
 
 		if (AH->lookaheadLen != 512)
 		{
 			if (feof(fh))
-				exit_horribly(modulename, "input file does not appear to be a valid archive (too short?)\n");
+				fatal("input file does not appear to be a valid archive (too short?)");
 			else
 				READ_ERROR_EXIT(fh);
 		}
 
 		if (!isValidTarHeader(AH->lookahead))
-			exit_horribly(modulename, "input file does not appear to be a valid archive\n");
+			fatal("input file does not appear to be a valid archive");
 
 		AH->format = archTar;
 	}
@@ -2309,8 +2284,7 @@ _discoverArchiveFormat(ArchiveHandle *AH)
 	/* Close the file */
 	if (wantClose)
 		if (fclose(fh) != 0)
-			exit_horribly(modulename, "could not close input file: %s\n",
-						  strerror(errno));
+			fatal("could not close input file: %m");
 
 	return AH->format;
 }
@@ -2326,14 +2300,10 @@ _allocAH(const char *FileSpec, const ArchiveFormat fmt,
 {
 	ArchiveHandle *AH;
 
-#if 0
-	write_msg(modulename, "allocating AH for %s, format %d\n", FileSpec, fmt);
-#endif
+	pg_log_debug("allocating AH for %s, format %d", FileSpec, fmt);
 
 	AH = (ArchiveHandle *) pg_malloc0(sizeof(ArchiveHandle));
 
-	/* AH->debugLevel = 100; */
-
 	AH->version = K_VERS_SELF;
 
 	/* initialize for backwards compatible string processing */
@@ -2427,7 +2397,7 @@ _allocAH(const char *FileSpec, const ArchiveFormat fmt,
 			break;
 
 		default:
-			exit_horribly(modulename, "unrecognized file format \"%d\"\n", fmt);
+			fatal("unrecognized file format \"%d\"", fmt);
 	}
 
 	return AH;
@@ -2509,11 +2479,11 @@ mark_dump_job_done(ArchiveHandle *AH,
 				   int status,
 				   void *callback_data)
 {
-	ahlog(AH, 1, "finished item %d %s %s\n",
+	pg_log_info("finished item %d %s %s",
 		  te->dumpId, te->desc, te->tag);
 
 	if (status != 0)
-		exit_horribly(modulename, "worker process failed: exit code %d\n",
+		fatal("worker process failed: exit code %d",
 					  status);
 }
 
@@ -2632,8 +2602,7 @@ ReadToc(ArchiveHandle *AH)
 
 		/* Sanity check */
 		if (te->dumpId <= 0)
-			exit_horribly(modulename,
-						  "entry ID %d out of range -- perhaps a corrupt TOC\n",
+			fatal("entry ID %d out of range -- perhaps a corrupt TOC",
 						  te->dumpId);
 
 		te->hadDumper = ReadInt(AH);
@@ -2697,8 +2666,7 @@ ReadToc(ArchiveHandle *AH)
 
 		te->owner = ReadStr(AH);
 		if (AH->version < K_VERS_1_9 || strcmp(ReadStr(AH), "true") == 0)
-			write_msg(modulename,
-					  "WARNING: restoring tables WITH OIDS is not supported anymore\n");
+			pg_log_warning("restoring tables WITH OIDS is not supported anymore");
 
 		/* Read TOC entry dependencies */
 		if (AH->version >= K_VERS_1_5)
@@ -2744,7 +2712,7 @@ ReadToc(ArchiveHandle *AH)
 		if (AH->ReadExtraTocPtr)
 			AH->ReadExtraTocPtr(AH, te);
 
-		ahlog(AH, 3, "read TOC entry %d (ID %d) for %s %s\n",
+		pg_log_debug("read TOC entry %d (ID %d) for %s %s",
 			  i, te->dumpId, te->desc, te->tag);
 
 		/* link completed entry into TOC circular list */
@@ -2780,12 +2748,12 @@ processEncodingEntry(ArchiveHandle *AH, TocEntry *te)
 		*ptr2 = '\0';
 		encoding = pg_char_to_encoding(ptr1);
 		if (encoding < 0)
-			exit_horribly(modulename, "unrecognized encoding \"%s\"\n",
+			fatal("unrecognized encoding \"%s\"",
 						  ptr1);
 		AH->public.encoding = encoding;
 	}
 	else
-		exit_horribly(modulename, "invalid ENCODING item: %s\n",
+		fatal("invalid ENCODING item: %s",
 					  te->defn);
 
 	free(defn);
@@ -2803,7 +2771,7 @@ processStdStringsEntry(ArchiveHandle *AH, TocEntry *te)
 	else if (ptr1 && strncmp(ptr1, "'off'", 5) == 0)
 		AH->public.std_strings = false;
 	else
-		exit_horribly(modulename, "invalid STDSTRINGS item: %s\n",
+		fatal("invalid STDSTRINGS item: %s",
 					  te->defn);
 }
 
@@ -2828,35 +2796,35 @@ StrictNamesCheck(RestoreOptions *ropt)
 	{
 		missing_name = simple_string_list_not_touched(&ropt->schemaNames);
 		if (missing_name != NULL)
-			exit_horribly(modulename, "schema \"%s\" not found\n", missing_name);
+			fatal("schema \"%s\" not found", missing_name);
 	}
 
 	if (ropt->tableNames.head != NULL)
 	{
 		missing_name = simple_string_list_not_touched(&ropt->tableNames);
 		if (missing_name != NULL)
-			exit_horribly(modulename, "table \"%s\" not found\n", missing_name);
+			fatal("table \"%s\" not found", missing_name);
 	}
 
 	if (ropt->indexNames.head != NULL)
 	{
 		missing_name = simple_string_list_not_touched(&ropt->indexNames);
 		if (missing_name != NULL)
-			exit_horribly(modulename, "index \"%s\" not found\n", missing_name);
+			fatal("index \"%s\" not found", missing_name);
 	}
 
 	if (ropt->functionNames.head != NULL)
 	{
 		missing_name = simple_string_list_not_touched(&ropt->functionNames);
 		if (missing_name != NULL)
-			exit_horribly(modulename, "function \"%s\" not found\n", missing_name);
+			fatal("function \"%s\" not found", missing_name);
 	}
 
 	if (ropt->triggerNames.head != NULL)
 	{
 		missing_name = simple_string_list_not_touched(&ropt->triggerNames);
 		if (missing_name != NULL)
-			exit_horribly(modulename, "trigger \"%s\" not found\n", missing_name);
+			fatal("trigger \"%s\" not found", missing_name);
 	}
 }
 
@@ -3232,7 +3200,7 @@ _doSetSessionAuth(ArchiveHandle *AH, const char *user)
 
 		if (!res || PQresultStatus(res) != PGRES_COMMAND_OK)
 			/* NOT warn_or_exit_horribly... use -O instead to skip this. */
-			exit_horribly(modulename, "could not set session user to \"%s\": %s",
+			fatal("could not set session user to \"%s\": %s",
 						  user, PQerrorMessage(AH->connection));
 
 		PQclear(res);
@@ -3527,7 +3495,7 @@ _getObjectDescription(PQExpBuffer buf, TocEntry *te, ArchiveHandle *AH)
 		return;
 	}
 
-	write_msg(modulename, "WARNING: don't know how to set owner for object type \"%s\"\n",
+	pg_log_warning("don't know how to set owner for object type \"%s\"",
 			  type);
 }
 
@@ -3695,7 +3663,7 @@ _printTocEntry(ArchiveHandle *AH, TocEntry *te, bool isData)
 		}
 		else
 		{
-			write_msg(modulename, "WARNING: don't know how to set owner for object type \"%s\"\n",
+			pg_log_warning("don't know how to set owner for object type \"%s\"",
 					  te->desc);
 		}
 	}
@@ -3785,7 +3753,7 @@ ReadHead(ArchiveHandle *AH)
 		AH->ReadBufPtr(AH, tmpMag, 5);
 
 		if (strncmp(tmpMag, "PGDMP", 5) != 0)
-			exit_horribly(modulename, "did not find magic string in file header\n");
+			fatal("did not find magic string in file header");
 
 		vmaj = AH->ReadBytePtr(AH);
 		vmin = AH->ReadBytePtr(AH);
@@ -3798,16 +3766,16 @@ ReadHead(ArchiveHandle *AH)
 		AH->version = MAKE_ARCHIVE_VERSION(vmaj, vmin, vrev);
 
 		if (AH->version < K_VERS_1_0 || AH->version > K_VERS_MAX)
-			exit_horribly(modulename, "unsupported version (%d.%d) in file header\n",
+			fatal("unsupported version (%d.%d) in file header",
 						  vmaj, vmin);
 
 		AH->intSize = AH->ReadBytePtr(AH);
 		if (AH->intSize > 32)
-			exit_horribly(modulename, "sanity check on integer size (%lu) failed\n",
+			fatal("sanity check on integer size (%lu) failed",
 						  (unsigned long) AH->intSize);
 
 		if (AH->intSize > sizeof(int))
-			write_msg(modulename, "WARNING: archive was made on a machine with larger integers, some operations might fail\n");
+			pg_log_warning("archive was made on a machine with larger integers, some operations might fail");
 
 		if (AH->version >= K_VERS_1_7)
 			AH->offSize = AH->ReadBytePtr(AH);
@@ -3817,7 +3785,7 @@ ReadHead(ArchiveHandle *AH)
 		fmt = AH->ReadBytePtr(AH);
 
 		if (AH->format != fmt)
-			exit_horribly(modulename, "expected format (%d) differs from format found in file (%d)\n",
+			fatal("expected format (%d) differs from format found in file (%d)",
 						  AH->format, fmt);
 	}
 
@@ -3833,7 +3801,7 @@ ReadHead(ArchiveHandle *AH)
 
 #ifndef HAVE_LIBZ
 	if (AH->compression != 0)
-		write_msg(modulename, "WARNING: archive is compressed, but this installation does not support compression -- no data will be available\n");
+		pg_log_warning("archive is compressed, but this installation does not support compression -- no data will be available");
 #endif
 
 	if (AH->version >= K_VERS_1_4)
@@ -3851,7 +3819,7 @@ ReadHead(ArchiveHandle *AH)
 		AH->createDate = mktime(&crtm);
 
 		if (AH->createDate == (time_t) -1)
-			write_msg(modulename, "WARNING: invalid creation date in header\n");
+			pg_log_warning("invalid creation date in header");
 	}
 
 	if (AH->version >= K_VERS_1_10)
@@ -3924,7 +3892,7 @@ restore_toc_entries_prefork(ArchiveHandle *AH, TocEntry *pending_list)
 	bool		skipped_some;
 	TocEntry   *next_work_item;
 
-	ahlog(AH, 2, "entering restore_toc_entries_prefork\n");
+	pg_log_debug("entering restore_toc_entries_prefork");
 
 	/* Adjust dependency information */
 	fix_dependencies(AH);
@@ -3988,7 +3956,7 @@ restore_toc_entries_prefork(ArchiveHandle *AH, TocEntry *pending_list)
 		if (do_now)
 		{
 			/* OK, restore the item and update its dependencies */
-			ahlog(AH, 1, "processing item %d %s %s\n",
+			pg_log_info("processing item %d %s %s",
 				  next_work_item->dumpId,
 				  next_work_item->desc, next_work_item->tag);
 
@@ -4041,7 +4009,7 @@ restore_toc_entries_parallel(ArchiveHandle *AH, ParallelState *pstate,
 	ParallelReadyList ready_list;
 	TocEntry   *next_work_item;
 
-	ahlog(AH, 2, "entering restore_toc_entries_parallel\n");
+	pg_log_debug("entering restore_toc_entries_parallel");
 
 	/* Set up ready_list with enough room for all known TocEntrys */
 	ready_list_init(&ready_list, AH->tocCount);
@@ -4064,7 +4032,7 @@ restore_toc_entries_parallel(ArchiveHandle *AH, ParallelState *pstate,
 	 * left to be done.  Note invariant: at top of loop, there should always
 	 * be at least one worker available to dispatch a job to.
 	 */
-	ahlog(AH, 1, "entering main parallel loop\n");
+	pg_log_info("entering main parallel loop");
 
 	for (;;)
 	{
@@ -4075,7 +4043,7 @@ restore_toc_entries_parallel(ArchiveHandle *AH, ParallelState *pstate,
 			/* If not to be restored, don't waste time launching a worker */
 			if ((next_work_item->reqs & (REQ_SCHEMA | REQ_DATA)) == 0)
 			{
-				ahlog(AH, 1, "skipping item %d %s %s\n",
+				pg_log_info("skipping item %d %s %s",
 					  next_work_item->dumpId,
 					  next_work_item->desc, next_work_item->tag);
 				/* Update its dependencies as though we'd completed it */
@@ -4084,7 +4052,7 @@ restore_toc_entries_parallel(ArchiveHandle *AH, ParallelState *pstate,
 				continue;
 			}
 
-			ahlog(AH, 1, "launching item %d %s %s\n",
+			pg_log_info("launching item %d %s %s",
 				  next_work_item->dumpId,
 				  next_work_item->desc, next_work_item->tag);
 
@@ -4138,7 +4106,7 @@ restore_toc_entries_parallel(ArchiveHandle *AH, ParallelState *pstate,
 
 	ready_list_free(&ready_list);
 
-	ahlog(AH, 1, "finished main parallel loop\n");
+	pg_log_info("finished main parallel loop");
 }
 
 /*
@@ -4156,7 +4124,7 @@ restore_toc_entries_postfork(ArchiveHandle *AH, TocEntry *pending_list)
 	RestoreOptions *ropt = AH->public.ropt;
 	TocEntry   *te;
 
-	ahlog(AH, 2, "entering restore_toc_entries_postfork\n");
+	pg_log_debug("entering restore_toc_entries_postfork");
 
 	/*
 	 * Now reconnect the single parent connection.
@@ -4176,7 +4144,7 @@ restore_toc_entries_postfork(ArchiveHandle *AH, TocEntry *pending_list)
 	 */
 	for (te = pending_list->pending_next; te != pending_list; te = te->pending_next)
 	{
-		ahlog(AH, 1, "processing missed item %d %s %s\n",
+		pg_log_info("processing missed item %d %s %s",
 			  te->dumpId, te->desc, te->tag);
 		(void) restore_toc_entry(AH, te, false);
 	}
@@ -4418,7 +4386,7 @@ pop_next_work_item(ArchiveHandle *AH, ParallelReadyList *ready_list,
 		return te;
 	}
 
-	ahlog(AH, 2, "no item ready\n");
+	pg_log_debug("no item ready");
 	return NULL;
 }
 
@@ -4462,7 +4430,7 @@ mark_restore_job_done(ArchiveHandle *AH,
 {
 	ParallelReadyList *ready_list = (ParallelReadyList *) callback_data;
 
-	ahlog(AH, 1, "finished item %d %s %s\n",
+	pg_log_info("finished item %d %s %s",
 		  te->dumpId, te->desc, te->tag);
 
 	if (status == WORKER_CREATE_DONE)
@@ -4475,7 +4443,7 @@ mark_restore_job_done(ArchiveHandle *AH,
 	else if (status == WORKER_IGNORED_ERRORS)
 		AH->public.n_errors++;
 	else if (status != 0)
-		exit_horribly(modulename, "worker process failed: exit code %d\n",
+		fatal("worker process failed: exit code %d",
 					  status);
 
 	reduce_dependencies(AH, te, ready_list);
@@ -4647,7 +4615,7 @@ repoint_table_dependencies(ArchiveHandle *AH)
 
 				te->dependencies[i] = tabledataid;
 				te->dataLength = Max(te->dataLength, tabledatate->dataLength);
-				ahlog(AH, 2, "transferring dependency %d -> %d to %d\n",
+				pg_log_debug("transferring dependency %d -> %d to %d",
 					  te->dumpId, olddep, tabledataid);
 			}
 		}
@@ -4729,7 +4697,7 @@ reduce_dependencies(ArchiveHandle *AH, TocEntry *te,
 {
 	int			i;
 
-	ahlog(AH, 2, "reducing dependencies for %d\n", te->dumpId);
+	pg_log_debug("reducing dependencies for %d", te->dumpId);
 
 	for (i = 0; i < te->nRevDeps; i++)
 	{
@@ -4781,7 +4749,7 @@ mark_create_done(ArchiveHandle *AH, TocEntry *te)
 static void
 inhibit_data_for_failed_table(ArchiveHandle *AH, TocEntry *te)
 {
-	ahlog(AH, 1, "table \"%s\" could not be created, will not restore its data\n",
+	pg_log_info("table \"%s\" could not be created, will not restore its data",
 		  te->tag);
 
 	if (AH->tableDataId[te->dumpId] != 0)
diff --git a/src/bin/pg_dump/pg_backup_archiver.h b/src/bin/pg_dump/pg_backup_archiver.h
index 306d2ceba9..1e366155b4 100644
--- a/src/bin/pg_dump/pg_backup_archiver.h
+++ b/src/bin/pg_dump/pg_backup_archiver.h
@@ -126,17 +126,14 @@ struct ParallelState;
 #define READ_ERROR_EXIT(fd) \
 	do { \
 		if (feof(fd)) \
-			exit_horribly(modulename, \
-						  "could not read from input file: end of file\n"); \
+			fatal("could not read from input file: end of file"); \
 		else \
-			exit_horribly(modulename, \
-					"could not read from input file: %s\n", strerror(errno)); \
+			fatal("could not read from input file: %m"); \
 	} while (0)
 
 #define WRITE_ERROR_EXIT \
 	do { \
-		exit_horribly(modulename, "could not write to output file: %s\n", \
-					  strerror(errno)); \
+		fatal("could not write to output file: %m"); \
 	} while (0)
 
 typedef enum T_Action
@@ -246,8 +243,6 @@ struct _archiveHandle
 	char	   *archiveDumpVersion; /* When reading an archive, the version of
 									 * the dumper */
 
-	int			debugLevel;		/* Used for logging (currently only by
-								 * --verbose) */
 	size_t		intSize;		/* Size of an integer in the archive */
 	size_t		offSize;		/* Size of a file offset in the archive -
 								 * Added V1.7 */
@@ -468,6 +463,4 @@ extern void DropBlobIfExists(ArchiveHandle *AH, Oid oid);
 void		ahwrite(const void *ptr, size_t size, size_t nmemb, ArchiveHandle *AH);
 int			ahprintf(ArchiveHandle *AH, const char *fmt,...) pg_attribute_printf(2, 3);
 
-void		ahlog(ArchiveHandle *AH, int level, const char *fmt,...) pg_attribute_printf(3, 4);
-
 #endif
diff --git a/src/bin/pg_dump/pg_backup_custom.c b/src/bin/pg_dump/pg_backup_custom.c
index 96f44e88b1..e811c6c91a 100644
--- a/src/bin/pg_dump/pg_backup_custom.c
+++ b/src/bin/pg_dump/pg_backup_custom.c
@@ -29,6 +29,7 @@
 #include "parallel.h"
 #include "pg_backup_utils.h"
 #include "common/file_utils.h"
+#include "fe_utils/logging.h"
 
 /*--------
  * Routines in the format interface
@@ -91,9 +92,6 @@ static pgoff_t _getFilePos(ArchiveHandle *AH, lclContext *ctx);
 static void _CustomWriteFunc(ArchiveHandle *AH, const char *buf, size_t len);
 static size_t _CustomReadFunc(ArchiveHandle *AH, char **buf, size_t *buflen);
 
-/* translator: this is a module name */
-static const char *modulename = gettext_noop("custom archiver");
-
 
 
 /*
@@ -159,15 +157,13 @@ InitArchiveFmt_Custom(ArchiveHandle *AH)
 		{
 			AH->FH = fopen(AH->fSpec, PG_BINARY_W);
 			if (!AH->FH)
-				exit_horribly(modulename, "could not open output file \"%s\": %s\n",
-							  AH->fSpec, strerror(errno));
+				fatal("could not open output file \"%s\": %m", AH->fSpec);
 		}
 		else
 		{
 			AH->FH = stdout;
 			if (!AH->FH)
-				exit_horribly(modulename, "could not open output file: %s\n",
-							  strerror(errno));
+				fatal("could not open output file: %m");
 		}
 
 		ctx->hasSeek = checkSeek(AH->FH);
@@ -178,15 +174,13 @@ InitArchiveFmt_Custom(ArchiveHandle *AH)
 		{
 			AH->FH = fopen(AH->fSpec, PG_BINARY_R);
 			if (!AH->FH)
-				exit_horribly(modulename, "could not open input file \"%s\": %s\n",
-							  AH->fSpec, strerror(errno));
+				fatal("could not open input file \"%s\": %m", AH->fSpec);
 		}
 		else
 		{
 			AH->FH = stdin;
 			if (!AH->FH)
-				exit_horribly(modulename, "could not open input file: %s\n",
-							  strerror(errno));
+				fatal("could not open input file: %m");
 		}
 
 		ctx->hasSeek = checkSeek(AH->FH);
@@ -381,7 +375,7 @@ _StartBlob(ArchiveHandle *AH, TocEntry *te, Oid oid)
 	lclContext *ctx = (lclContext *) AH->formatData;
 
 	if (oid == 0)
-		exit_horribly(modulename, "invalid OID for large object\n");
+		fatal("invalid OID for large object");
 
 	WriteInt(AH, oid);
 
@@ -451,8 +445,7 @@ _PrintTocData(ArchiveHandle *AH, TocEntry *te)
 					break;
 
 				default:		/* Always have a default */
-					exit_horribly(modulename,
-								  "unrecognized data block type (%d) while searching archive\n",
+					fatal("unrecognized data block type (%d) while searching archive",
 								  blkType);
 					break;
 			}
@@ -463,8 +456,7 @@ _PrintTocData(ArchiveHandle *AH, TocEntry *te)
 	{
 		/* We can just seek to the place we need to be. */
 		if (fseeko(AH->FH, tctx->dataPos, SEEK_SET) != 0)
-			exit_horribly(modulename, "error during file seek: %s\n",
-						  strerror(errno));
+			fatal("error during file seek: %m");
 
 		_readBlockHeader(AH, &blkType, &id);
 	}
@@ -473,24 +465,24 @@ _PrintTocData(ArchiveHandle *AH, TocEntry *te)
 	if (blkType == EOF)
 	{
 		if (tctx->dataState == K_OFFSET_POS_NOT_SET)
-			exit_horribly(modulename, "could not find block ID %d in archive -- "
-						  "possibly due to out-of-order restore request, "
-						  "which cannot be handled due to lack of data offsets in archive\n",
-						  te->dumpId);
+			fatal("could not find block ID %d in archive -- "
+				  "possibly due to out-of-order restore request, "
+				  "which cannot be handled due to lack of data offsets in archive",
+				  te->dumpId);
 		else if (!ctx->hasSeek)
-			exit_horribly(modulename, "could not find block ID %d in archive -- "
-						  "possibly due to out-of-order restore request, "
-						  "which cannot be handled due to non-seekable input file\n",
-						  te->dumpId);
+			fatal("could not find block ID %d in archive -- "
+				  "possibly due to out-of-order restore request, "
+				  "which cannot be handled due to non-seekable input file",
+				  te->dumpId);
 		else					/* huh, the dataPos led us to EOF? */
-			exit_horribly(modulename, "could not find block ID %d in archive -- "
-						  "possibly corrupt archive\n",
-						  te->dumpId);
+			fatal("could not find block ID %d in archive -- "
+				  "possibly corrupt archive",
+				  te->dumpId);
 	}
 
 	/* Are we sane? */
 	if (id != te->dumpId)
-		exit_horribly(modulename, "found unexpected block ID (%d) when reading data -- expected %d\n",
+		fatal("found unexpected block ID (%d) when reading data -- expected %d",
 					  id, te->dumpId);
 
 	switch (blkType)
@@ -504,7 +496,7 @@ _PrintTocData(ArchiveHandle *AH, TocEntry *te)
 			break;
 
 		default:				/* Always have a default */
-			exit_horribly(modulename, "unrecognized data block type %d while restoring archive\n",
+			fatal("unrecognized data block type %d while restoring archive",
 						  blkType);
 			break;
 	}
@@ -584,11 +576,9 @@ _skipData(ArchiveHandle *AH)
 		if ((cnt = fread(buf, 1, blkLen, AH->FH)) != blkLen)
 		{
 			if (feof(AH->FH))
-				exit_horribly(modulename,
-							  "could not read from input file: end of file\n");
+				fatal("could not read from input file: end of file");
 			else
-				exit_horribly(modulename,
-							  "could not read from input file: %s\n", strerror(errno));
+				fatal("could not read from input file: %m");
 		}
 
 		ctx->filePos += blkLen;
@@ -706,8 +696,7 @@ _CloseArchive(ArchiveHandle *AH)
 		/* Remember TOC's seek position for use below */
 		tpos = ftello(AH->FH);
 		if (tpos < 0 && ctx->hasSeek)
-			exit_horribly(modulename, "could not determine seek position in archive file: %s\n",
-						  strerror(errno));
+			fatal("could not determine seek position in archive file: %m");
 		WriteToc(AH);
 		ctx->dataStart = _getFilePos(AH, ctx);
 		WriteDataChunks(AH, NULL);
@@ -724,11 +713,11 @@ _CloseArchive(ArchiveHandle *AH)
 	}
 
 	if (fclose(AH->FH) != 0)
-		exit_horribly(modulename, "could not close archive file: %s\n", strerror(errno));
+		fatal("could not close archive file: %m");
 
 	/* Sync the output file if one is defined */
 	if (AH->dosync && AH->mode == archModeWrite && AH->fSpec)
-		(void) fsync_fname(AH->fSpec, false, progname);
+		(void) fsync_fname(AH->fSpec, false);
 
 	AH->FH = NULL;
 }
@@ -747,36 +736,32 @@ _ReopenArchive(ArchiveHandle *AH)
 	pgoff_t		tpos;
 
 	if (AH->mode == archModeWrite)
-		exit_horribly(modulename, "can only reopen input archives\n");
+		fatal("can only reopen input archives");
 
 	/*
 	 * These two cases are user-facing errors since they represent unsupported
 	 * (but not invalid) use-cases.  Word the error messages appropriately.
 	 */
 	if (AH->fSpec == NULL || strcmp(AH->fSpec, "") == 0)
-		exit_horribly(modulename, "parallel restore from standard input is not supported\n");
+		fatal("parallel restore from standard input is not supported");
 	if (!ctx->hasSeek)
-		exit_horribly(modulename, "parallel restore from non-seekable file is not supported\n");
+		fatal("parallel restore from non-seekable file is not supported");
 
 	tpos = ftello(AH->FH);
 	if (tpos < 0)
-		exit_horribly(modulename, "could not determine seek position in archive file: %s\n",
-					  strerror(errno));
+		fatal("could not determine seek position in archive file: %m");
 
 #ifndef WIN32
 	if (fclose(AH->FH) != 0)
-		exit_horribly(modulename, "could not close archive file: %s\n",
-					  strerror(errno));
+		fatal("could not close archive file: %m");
 #endif
 
 	AH->FH = fopen(AH->fSpec, PG_BINARY_R);
 	if (!AH->FH)
-		exit_horribly(modulename, "could not open input file \"%s\": %s\n",
-					  AH->fSpec, strerror(errno));
+		fatal("could not open input file \"%s\": %m", AH->fSpec);
 
 	if (fseeko(AH->FH, tpos, SEEK_SET) != 0)
-		exit_horribly(modulename, "could not set seek position in archive file: %s\n",
-					  strerror(errno));
+		fatal("could not set seek position in archive file: %m");
 }
 
 /*
@@ -831,8 +816,7 @@ _PrepParallelRestore(ArchiveHandle *AH)
 		pgoff_t		endpos;
 
 		if (fseeko(AH->FH, 0, SEEK_END) != 0)
-			exit_horribly(modulename, "error during file seek: %s\n",
-						  strerror(errno));
+			fatal("error during file seek: %m");
 		endpos = ftello(AH->FH);
 		if (endpos > prev_tctx->dataPos)
 			prev_te->dataLength = endpos - prev_tctx->dataPos;
@@ -853,7 +837,7 @@ _Clone(ArchiveHandle *AH)
 
 	/* sanity check, shouldn't happen */
 	if (ctx->cs != NULL)
-		exit_horribly(modulename, "compressor active\n");
+		fatal("compressor active");
 
 	/*
 	 * Note: we do not make a local lo_buf because we expect at most one BLOBS
@@ -905,11 +889,10 @@ _getFilePos(ArchiveHandle *AH, lclContext *ctx)
 		 */
 		pos = ftello(AH->FH);
 		if (pos < 0)
-			exit_horribly(modulename, "could not determine seek position in archive file: %s\n",
-						  strerror(errno));
+			fatal("could not determine seek position in archive file: %m");
 
 		if (pos != ctx->filePos)
-			write_msg(modulename, "WARNING: ftell mismatch with expected position -- ftell used\n");
+			pg_log_warning("ftell mismatch with expected position -- ftell used");
 	}
 	else
 		pos = ctx->filePos;
@@ -928,7 +911,7 @@ _readBlockHeader(ArchiveHandle *AH, int *type, int *id)
 	int			byt;
 
 	/*
-	 * Note: if we are at EOF with a pre-1.3 input file, we'll exit_horribly
+	 * Note: if we are at EOF with a pre-1.3 input file, we'll fatal()
 	 * inside ReadInt rather than returning EOF.  It doesn't seem worth
 	 * jumping through hoops to deal with that case better, because no such
 	 * files are likely to exist in the wild: only some 7.1 development
diff --git a/src/bin/pg_dump/pg_backup_db.c b/src/bin/pg_dump/pg_backup_db.c
index 5e32ee8a5b..fa576eb58f 100644
--- a/src/bin/pg_dump/pg_backup_db.c
+++ b/src/bin/pg_dump/pg_backup_db.c
@@ -13,6 +13,7 @@
 
 #include "dumputils.h"
 #include "fe_utils/connect.h"
+#include "fe_utils/logging.h"
 #include "fe_utils/string_utils.h"
 #include "parallel.h"
 #include "pg_backup_archiver.h"
@@ -43,7 +44,7 @@ _check_database_version(ArchiveHandle *AH)
 	remoteversion_str = PQparameterStatus(AH->connection, "server_version");
 	remoteversion = PQserverVersion(AH->connection);
 	if (remoteversion == 0 || !remoteversion_str)
-		exit_horribly(modulename, "could not get server_version from libpq\n");
+		fatal("could not get server_version from libpq");
 
 	AH->public.remoteVersionStr = pg_strdup(remoteversion_str);
 	AH->public.remoteVersion = remoteversion;
@@ -54,9 +55,9 @@ _check_database_version(ArchiveHandle *AH)
 		&& (remoteversion < AH->public.minRemoteVersion ||
 			remoteversion > AH->public.maxRemoteVersion))
 	{
-		write_msg(NULL, "server version: %s; %s version: %s\n",
+		pg_log_error("server version: %s; %s version: %s",
 				  remoteversion_str, progname, PG_VERSION);
-		exit_horribly(NULL, "aborting because of server version mismatch\n");
+		fatal("aborting because of server version mismatch");
 	}
 
 	/*
@@ -139,7 +140,7 @@ _connectDB(ArchiveHandle *AH, const char *reqdb, const char *requser)
 	else
 		newuser = requser;
 
-	ahlog(AH, 1, "connecting to database \"%s\" as user \"%s\"\n",
+	pg_log_info("connecting to database \"%s\" as user \"%s\"",
 		  newdb, newuser);
 
 	password = AH->savedPassword;
@@ -178,12 +179,12 @@ _connectDB(ArchiveHandle *AH, const char *reqdb, const char *requser)
 		newConn = PQconnectdbParams(keywords, values, true);
 
 		if (!newConn)
-			exit_horribly(modulename, "failed to reconnect to database\n");
+			fatal("failed to reconnect to database");
 
 		if (PQstatus(newConn) == CONNECTION_BAD)
 		{
 			if (!PQconnectionNeedsPassword(newConn))
-				exit_horribly(modulename, "could not reconnect to database: %s",
+				fatal("could not reconnect to database: %s",
 							  PQerrorMessage(newConn));
 			PQfinish(newConn);
 
@@ -199,7 +200,7 @@ _connectDB(ArchiveHandle *AH, const char *reqdb, const char *requser)
 				password = passbuf;
 			}
 			else
-				exit_horribly(modulename, "connection needs password\n");
+				fatal("connection needs password");
 
 			new_pass = true;
 		}
@@ -250,7 +251,7 @@ ConnectDatabase(Archive *AHX,
 	bool		new_pass;
 
 	if (AH->connection)
-		exit_horribly(modulename, "already connected to a database\n");
+		fatal("already connected to a database");
 
 	password = AH->savedPassword;
 
@@ -289,7 +290,7 @@ ConnectDatabase(Archive *AHX,
 		AH->connection = PQconnectdbParams(keywords, values, true);
 
 		if (!AH->connection)
-			exit_horribly(modulename, "failed to connect to database\n");
+			fatal("failed to connect to database");
 
 		if (PQstatus(AH->connection) == CONNECTION_BAD &&
 			PQconnectionNeedsPassword(AH->connection) &&
@@ -305,7 +306,7 @@ ConnectDatabase(Archive *AHX,
 
 	/* check to see that the backend connection was successfully made */
 	if (PQstatus(AH->connection) == CONNECTION_BAD)
-		exit_horribly(modulename, "connection to database \"%s\" failed: %s",
+		fatal("connection to database \"%s\" failed: %s",
 					  PQdb(AH->connection) ? PQdb(AH->connection) : "",
 					  PQerrorMessage(AH->connection));
 
@@ -351,7 +352,7 @@ DisconnectDatabase(Archive *AHX)
 		/*
 		 * If we have an active query, send a cancel before closing, ignoring
 		 * any errors.  This is of no use for a normal exit, but might be
-		 * helpful during exit_horribly().
+		 * helpful during fatal().
 		 */
 		if (PQtransactionStatus(AH->connection) == PQTRANS_ACTIVE)
 			(void) PQcancel(AH->connCancel, errbuf, sizeof(errbuf));
@@ -380,13 +381,13 @@ notice_processor(void *arg, const char *message)
 	write_msg(NULL, "%s", message);
 }
 
-/* Like exit_horribly(), but with a complaint about a particular query. */
+/* Like exit_fatal(), but with a complaint about a particular query. */
 static void
 die_on_query_failure(ArchiveHandle *AH, const char *modulename, const char *query)
 {
-	write_msg(modulename, "query failed: %s",
+	pg_log_error("query failed: %s",
 			  PQerrorMessage(AH->connection));
-	exit_horribly(modulename, "query was: %s\n", query);
+	fatal("query was: %s", query);
 }
 
 void
@@ -427,9 +428,8 @@ ExecuteSqlQueryForSingleRow(Archive *fout, const char *query)
 	/* Expecting a single result only */
 	ntups = PQntuples(res);
 	if (ntups != 1)
-		exit_horribly(NULL,
-					  ngettext("query returned %d row instead of one: %s\n",
-							   "query returned %d rows instead of one: %s\n",
+		fatal(ngettext("query returned %d row instead of one: %s",
+					   "query returned %d rows instead of one: %s",
 							   ntups),
 					  ntups, query);
 
@@ -573,7 +573,7 @@ ExecuteSqlCommandBuf(Archive *AHX, const char *buf, size_t bufLen)
 		 */
 		if (AH->pgCopyIn &&
 			PQputCopyData(AH->connection, buf, bufLen) <= 0)
-			exit_horribly(modulename, "error returned by PQputCopyData: %s",
+			fatal("error returned by PQputCopyData: %s",
 						  PQerrorMessage(AH->connection));
 	}
 	else if (AH->outputKind == OUTPUT_OTHERDATA)
@@ -622,7 +622,7 @@ EndDBCopyMode(Archive *AHX, const char *tocEntryTag)
 		PGresult   *res;
 
 		if (PQputCopyEnd(AH->connection, NULL) <= 0)
-			exit_horribly(modulename, "error returned by PQputCopyEnd: %s",
+			fatal("error returned by PQputCopyEnd: %s",
 						  PQerrorMessage(AH->connection));
 
 		/* Check command status and return to normal libpq state */
@@ -634,7 +634,7 @@ EndDBCopyMode(Archive *AHX, const char *tocEntryTag)
 
 		/* Do this to ensure we've pumped libpq back to idle state */
 		if (PQgetResult(AH->connection) != NULL)
-			write_msg(NULL, "WARNING: unexpected extra results during COPY of table \"%s\"\n",
+			pg_log_warning("unexpected extra results during COPY of table \"%s\"",
 					  tocEntryTag);
 
 		AH->pgCopyIn = false;
diff --git a/src/bin/pg_dump/pg_backup_directory.c b/src/bin/pg_dump/pg_backup_directory.c
index e6261252c7..70eca82c91 100644
--- a/src/bin/pg_dump/pg_backup_directory.c
+++ b/src/bin/pg_dump/pg_backup_directory.c
@@ -61,9 +61,6 @@ typedef struct
 	char	   *filename;		/* filename excluding the directory (basename) */
 } lclTocEntry;
 
-/* translator: this is a module name */
-static const char *modulename = gettext_noop("directory archiver");
-
 /* prototypes for private functions */
 static void _ArchiveEntry(ArchiveHandle *AH, TocEntry *te);
 static void _StartData(ArchiveHandle *AH, TocEntry *te);
@@ -156,7 +153,7 @@ InitArchiveFmt_Directory(ArchiveHandle *AH)
 	 */
 
 	if (!AH->fSpec || strcmp(AH->fSpec, "") == 0)
-		exit_horribly(modulename, "no output directory specified\n");
+		fatal("no output directory specified");
 
 	ctx->directory = AH->fSpec;
 
@@ -185,18 +182,18 @@ InitArchiveFmt_Directory(ArchiveHandle *AH)
 				}
 
 				if (errno)
-					exit_horribly(modulename, "could not read directory \"%s\": %s\n",
-								  ctx->directory, strerror(errno));
+					fatal("could not read directory \"%s\": %m",
+						  ctx->directory);
 
 				if (closedir(dir))
-					exit_horribly(modulename, "could not close directory \"%s\": %s\n",
-								  ctx->directory, strerror(errno));
+					fatal("could not close directory \"%s\": %m",
+						  ctx->directory);
 			}
 		}
 
 		if (!is_empty && mkdir(ctx->directory, 0700) < 0)
-			exit_horribly(modulename, "could not create directory \"%s\": %s\n",
-						  ctx->directory, strerror(errno));
+			fatal("could not create directory \"%s\": %m",
+				  ctx->directory);
 	}
 	else
 	{							/* Read Mode */
@@ -207,9 +204,7 @@ InitArchiveFmt_Directory(ArchiveHandle *AH)
 
 		tocFH = cfopen_read(fname, PG_BINARY_R);
 		if (tocFH == NULL)
-			exit_horribly(modulename,
-						  "could not open input file \"%s\": %s\n",
-						  fname, strerror(errno));
+			fatal("could not open input file \"%s\": %m", fname);
 
 		ctx->dataFH = tocFH;
 
@@ -224,8 +219,7 @@ InitArchiveFmt_Directory(ArchiveHandle *AH)
 
 		/* Nothing else in the file, so close it again... */
 		if (cfclose(tocFH) != 0)
-			exit_horribly(modulename, "could not close TOC file: %s\n",
-						  strerror(errno));
+			fatal("could not close TOC file: %m");
 		ctx->dataFH = NULL;
 	}
 }
@@ -335,8 +329,7 @@ _StartData(ArchiveHandle *AH, TocEntry *te)
 
 	ctx->dataFH = cfopen_write(fname, PG_BINARY_W, AH->compression);
 	if (ctx->dataFH == NULL)
-		exit_horribly(modulename, "could not open output file \"%s\": %s\n",
-					  fname, strerror(errno));
+		fatal("could not open output file \"%s\": %m", fname);
 }
 
 /*
@@ -354,7 +347,7 @@ _WriteData(ArchiveHandle *AH, const void *data, size_t dLen)
 	lclContext *ctx = (lclContext *) AH->formatData;
 
 	if (dLen > 0 && cfwrite(data, dLen, ctx->dataFH) != dLen)
-		exit_horribly(modulename, "could not write to output file: %s\n",
+		fatal("could not write to output file: %s",
 					  get_cfp_error(ctx->dataFH));
 
 
@@ -395,8 +388,7 @@ _PrintFileData(ArchiveHandle *AH, char *filename)
 	cfp = cfopen_read(filename, PG_BINARY_R);
 
 	if (!cfp)
-		exit_horribly(modulename, "could not open input file \"%s\": %s\n",
-					  filename, strerror(errno));
+		fatal("could not open input file \"%s\": %m", filename);
 
 	buf = pg_malloc(ZLIB_OUT_SIZE);
 	buflen = ZLIB_OUT_SIZE;
@@ -408,8 +400,7 @@ _PrintFileData(ArchiveHandle *AH, char *filename)
 
 	free(buf);
 	if (cfclose(cfp) !=0)
-		exit_horribly(modulename, "could not close data file: %s\n",
-					  strerror(errno));
+		fatal("could not close data file: %m");
 }
 
 /*
@@ -449,8 +440,8 @@ _LoadBlobs(ArchiveHandle *AH)
 	ctx->blobsTocFH = cfopen_read(fname, PG_BINARY_R);
 
 	if (ctx->blobsTocFH == NULL)
-		exit_horribly(modulename, "could not open large object TOC file \"%s\" for input: %s\n",
-					  fname, strerror(errno));
+		fatal("could not open large object TOC file \"%s\" for input: %m",
+			  fname);
 
 	/* Read the blobs TOC file line-by-line, and process each blob */
 	while ((cfgets(ctx->blobsTocFH, line, MAXPGPATH)) != NULL)
@@ -460,7 +451,7 @@ _LoadBlobs(ArchiveHandle *AH)
 
 		/* Can't overflow because line and fname are the same length. */
 		if (sscanf(line, "%u %s\n", &oid, fname) != 2)
-			exit_horribly(modulename, "invalid line in large object TOC file \"%s\": \"%s\"\n",
+			fatal("invalid line in large object TOC file \"%s\": \"%s\"",
 						  fname, line);
 
 		StartRestoreBlob(AH, oid, AH->public.ropt->dropSchema);
@@ -469,12 +460,12 @@ _LoadBlobs(ArchiveHandle *AH)
 		EndRestoreBlob(AH, oid);
 	}
 	if (!cfeof(ctx->blobsTocFH))
-		exit_horribly(modulename, "error reading large object TOC file \"%s\"\n",
+		fatal("error reading large object TOC file \"%s\"",
 					  fname);
 
 	if (cfclose(ctx->blobsTocFH) != 0)
-		exit_horribly(modulename, "could not close large object TOC file \"%s\": %s\n",
-					  fname, strerror(errno));
+		fatal("could not close large object TOC file \"%s\": %m",
+			  fname);
 
 	ctx->blobsTocFH = NULL;
 
@@ -494,7 +485,7 @@ _WriteByte(ArchiveHandle *AH, const int i)
 	lclContext *ctx = (lclContext *) AH->formatData;
 
 	if (cfwrite(&c, 1, ctx->dataFH) != 1)
-		exit_horribly(modulename, "could not write to output file: %s\n",
+		fatal("could not write to output file: %s",
 					  get_cfp_error(ctx->dataFH));
 
 	return 1;
@@ -524,7 +515,7 @@ _WriteBuf(ArchiveHandle *AH, const void *buf, size_t len)
 	lclContext *ctx = (lclContext *) AH->formatData;
 
 	if (cfwrite(buf, len, ctx->dataFH) != len)
-		exit_horribly(modulename, "could not write to output file: %s\n",
+		fatal("could not write to output file: %s",
 					  get_cfp_error(ctx->dataFH));
 
 	return;
@@ -545,8 +536,7 @@ _ReadBuf(ArchiveHandle *AH, void *buf, size_t len)
 	 * exit on short reads.
 	 */
 	if (cfread(buf, len, ctx->dataFH) != len)
-		exit_horribly(modulename,
-					  "could not read from input file: end of file\n");
+		fatal("could not read from input file: end of file");
 
 	return;
 }
@@ -581,8 +571,7 @@ _CloseArchive(ArchiveHandle *AH)
 		/* The TOC is always created uncompressed */
 		tocFH = cfopen_write(fname, PG_BINARY_W, 0);
 		if (tocFH == NULL)
-			exit_horribly(modulename, "could not open output file \"%s\": %s\n",
-						  fname, strerror(errno));
+			fatal("could not open output file \"%s\": %m", fname);
 		ctx->dataFH = tocFH;
 
 		/*
@@ -595,8 +584,7 @@ _CloseArchive(ArchiveHandle *AH)
 		AH->format = archDirectory;
 		WriteToc(AH);
 		if (cfclose(tocFH) != 0)
-			exit_horribly(modulename, "could not close TOC file: %s\n",
-						  strerror(errno));
+			fatal("could not close TOC file: %m");
 		WriteDataChunks(AH, ctx->pstate);
 
 		ParallelBackupEnd(AH, ctx->pstate);
@@ -606,7 +594,7 @@ _CloseArchive(ArchiveHandle *AH)
 		 * individually. Just recurse once through all the files generated.
 		 */
 		if (AH->dosync)
-			fsync_dir_recurse(ctx->directory, progname);
+			fsync_dir_recurse(ctx->directory);
 	}
 	AH->FH = NULL;
 }
@@ -646,8 +634,7 @@ _StartBlobs(ArchiveHandle *AH, TocEntry *te)
 	/* The blob TOC file is never compressed */
 	ctx->blobsTocFH = cfopen_write(fname, "ab", 0);
 	if (ctx->blobsTocFH == NULL)
-		exit_horribly(modulename, "could not open output file \"%s\": %s\n",
-					  fname, strerror(errno));
+		fatal("could not open output file \"%s\": %m", fname);
 }
 
 /*
@@ -666,8 +653,7 @@ _StartBlob(ArchiveHandle *AH, TocEntry *te, Oid oid)
 	ctx->dataFH = cfopen_write(fname, PG_BINARY_W, AH->compression);
 
 	if (ctx->dataFH == NULL)
-		exit_horribly(modulename, "could not open output file \"%s\": %s\n",
-					  fname, strerror(errno));
+		fatal("could not open output file \"%s\": %m", fname);
 }
 
 /*
@@ -689,7 +675,7 @@ _EndBlob(ArchiveHandle *AH, TocEntry *te, Oid oid)
 	/* register the blob in blobs.toc */
 	len = snprintf(buf, sizeof(buf), "%u blob_%u.dat\n", oid, oid);
 	if (cfwrite(buf, len, ctx->blobsTocFH) != len)
-		exit_horribly(modulename, "could not write to blobs TOC file\n");
+		fatal("could not write to blobs TOC file");
 }
 
 /*
@@ -721,7 +707,7 @@ setFilePath(ArchiveHandle *AH, char *buf, const char *relativeFilename)
 	dname = ctx->directory;
 
 	if (strlen(dname) + 1 + strlen(relativeFilename) + 1 > MAXPGPATH)
-		exit_horribly(modulename, "file name too long: \"%s\"\n", dname);
+		fatal("file name too long: \"%s\"", dname);
 
 	strcpy(buf, dname);
 	strcat(buf, "/");
diff --git a/src/bin/pg_dump/pg_backup_null.c b/src/bin/pg_dump/pg_backup_null.c
index 62f6e624f0..f33f7ba421 100644
--- a/src/bin/pg_dump/pg_backup_null.c
+++ b/src/bin/pg_dump/pg_backup_null.c
@@ -72,7 +72,7 @@ InitArchiveFmt_Null(ArchiveHandle *AH)
 	 * Now prevent reading...
 	 */
 	if (AH->mode == archModeRead)
-		exit_horribly(NULL, "this format cannot be read\n");
+		fatal("this format cannot be read");
 }
 
 /*
@@ -147,7 +147,7 @@ _StartBlob(ArchiveHandle *AH, TocEntry *te, Oid oid)
 	bool		old_blob_style = (AH->version < K_VERS_1_12);
 
 	if (oid == 0)
-		exit_horribly(NULL, "invalid OID for large object\n");
+		fatal("invalid OID for large object");
 
 	/* With an old archive we must do drop and create logic here */
 	if (old_blob_style && AH->public.ropt->dropSchema)
diff --git a/src/bin/pg_dump/pg_backup_tar.c b/src/bin/pg_dump/pg_backup_tar.c
index 407a56d8d4..b52593c3c0 100644
--- a/src/bin/pg_dump/pg_backup_tar.c
+++ b/src/bin/pg_dump/pg_backup_tar.c
@@ -99,9 +99,6 @@ typedef struct
 	char	   *filename;
 } lclTocEntry;
 
-/* translator: this is a module name */
-static const char *modulename = gettext_noop("tar archiver");
-
 static void _LoadBlobs(ArchiveHandle *AH);
 
 static TAR_MEMBER *tarOpen(ArchiveHandle *AH, const char *filename, char mode);
@@ -177,17 +174,14 @@ InitArchiveFmt_Tar(ArchiveHandle *AH)
 		{
 			ctx->tarFH = fopen(AH->fSpec, PG_BINARY_W);
 			if (ctx->tarFH == NULL)
-				exit_horribly(modulename,
-							  "could not open TOC file \"%s\" for output: %s\n",
-							  AH->fSpec, strerror(errno));
+				fatal("could not open TOC file \"%s\" for output: %m",
+					  AH->fSpec);
 		}
 		else
 		{
 			ctx->tarFH = stdout;
 			if (ctx->tarFH == NULL)
-				exit_horribly(modulename,
-							  "could not open TOC file for output: %s\n",
-							  strerror(errno));
+				fatal("could not open TOC file for output: %m");
 		}
 
 		ctx->tarFHpos = 0;
@@ -206,8 +200,7 @@ InitArchiveFmt_Tar(ArchiveHandle *AH)
 		 * positioning.
 		 */
 		if (AH->compression != 0)
-			exit_horribly(modulename,
-						  "compression is not supported by tar archive format\n");
+			fatal("compression is not supported by tar archive format");
 	}
 	else
 	{							/* Read Mode */
@@ -215,15 +208,14 @@ InitArchiveFmt_Tar(ArchiveHandle *AH)
 		{
 			ctx->tarFH = fopen(AH->fSpec, PG_BINARY_R);
 			if (ctx->tarFH == NULL)
-				exit_horribly(modulename, "could not open TOC file \"%s\" for input: %s\n",
-							  AH->fSpec, strerror(errno));
+				fatal("could not open TOC file \"%s\" for input: %m",
+					  AH->fSpec);
 		}
 		else
 		{
 			ctx->tarFH = stdin;
 			if (ctx->tarFH == NULL)
-				exit_horribly(modulename, "could not open TOC file for input: %s\n",
-							  strerror(errno));
+				fatal("could not open TOC file for input: %m");
 		}
 
 		/*
@@ -349,7 +341,7 @@ tarOpen(ArchiveHandle *AH, const char *filename, char mode)
 				 * Couldn't find the requested file. Future: do SEEK(0) and
 				 * retry.
 				 */
-				exit_horribly(modulename, "could not find file \"%s\" in archive\n", filename);
+				fatal("could not find file \"%s\" in archive", filename);
 			}
 			else
 			{
@@ -363,7 +355,7 @@ tarOpen(ArchiveHandle *AH, const char *filename, char mode)
 		if (AH->compression == 0)
 			tm->nFH = ctx->tarFH;
 		else
-			exit_horribly(modulename, "compression is not supported by tar archive format\n");
+			fatal("compression is not supported by tar archive format");
 		/* tm->zFH = gzdopen(dup(fileno(ctx->tarFH)), "rb"); */
 #else
 		tm->nFH = ctx->tarFH;
@@ -415,7 +407,7 @@ tarOpen(ArchiveHandle *AH, const char *filename, char mode)
 #endif
 
 		if (tm->tmpFH == NULL)
-			exit_horribly(modulename, "could not generate temporary file name: %s\n", strerror(errno));
+			fatal("could not generate temporary file name: %m");
 
 		umask(old_umask);
 
@@ -426,7 +418,7 @@ tarOpen(ArchiveHandle *AH, const char *filename, char mode)
 			sprintf(fmode, "wb%d", AH->compression);
 			tm->zFH = gzdopen(dup(fileno(tm->tmpFH)), fmode);
 			if (tm->zFH == NULL)
-				exit_horribly(modulename, "could not open temporary file\n");
+				fatal("could not open temporary file");
 		}
 		else
 			tm->nFH = tm->tmpFH;
@@ -453,7 +445,7 @@ tarClose(ArchiveHandle *AH, TAR_MEMBER *th)
 	 */
 	if (AH->compression != 0)
 		if (GZCLOSE(th->zFH) != 0)
-			exit_horribly(modulename, "could not close tar member\n");
+			fatal("could not close tar member");
 
 	if (th->mode == 'w')
 		_tarAddFile(AH, th);	/* This will close the temp file */
@@ -560,12 +552,10 @@ _tarReadRaw(ArchiveHandle *AH, void *buf, size_t len, TAR_MEMBER *th, FILE *fh)
 					int			errnum;
 					const char *errmsg = gzerror(th->zFH, &errnum);
 
-					exit_horribly(modulename,
-								  "could not read from input file: %s\n",
+					fatal("could not read from input file: %s",
 								  errnum == Z_ERRNO ? strerror(errno) : errmsg);
 #else
-					exit_horribly(modulename,
-								  "could not read from input file: %s\n",
+					fatal("could not read from input file: %s",
 								  strerror(errno));
 #endif
 				}
@@ -578,7 +568,7 @@ _tarReadRaw(ArchiveHandle *AH, void *buf, size_t len, TAR_MEMBER *th, FILE *fh)
 			}
 		}
 		else
-			exit_horribly(modulename, "internal error -- neither th nor fh specified in tarReadRaw()\n");
+			fatal("internal error -- neither th nor fh specified in tarReadRaw()\n");
 	}
 
 	ctx->tarFHpos += res + used;
@@ -700,8 +690,7 @@ _PrintTocData(ArchiveHandle *AH, TocEntry *te)
 			pos1 = (int) strlen(te->copyStmt) - 13;
 			if (pos1 < 6 || strncmp(te->copyStmt, "COPY ", 5) != 0 ||
 				strcmp(te->copyStmt + pos1, " FROM stdin;\n") != 0)
-				exit_horribly(modulename,
-							  "unexpected COPY statement syntax: \"%s\"\n",
+				fatal("unexpected COPY statement syntax: \"%s\"",
 							  te->copyStmt);
 
 			/* Emit all but the FROM part ... */
@@ -746,7 +735,7 @@ _LoadBlobs(ArchiveHandle *AH)
 			oid = atooid(&th->targetFile[5]);
 			if (oid != 0)
 			{
-				ahlog(AH, 1, "restoring large object with OID %u\n", oid);
+				pg_log_info("restoring large object with OID %u", oid);
 
 				StartRestoreBlob(AH, oid, AH->public.ropt->dropSchema);
 
@@ -803,8 +792,7 @@ _ReadByte(ArchiveHandle *AH)
 	res = tarRead(&c, 1, ctx->FH);
 	if (res != 1)
 		/* We already would have exited for errors on reads, must be EOF */
-		exit_horribly(modulename,
-					  "could not read from input file: end of file\n");
+		fatal("could not read from input file: end of file");
 	ctx->filePos += 1;
 	return c;
 }
@@ -827,8 +815,7 @@ _ReadBuf(ArchiveHandle *AH, void *buf, size_t len)
 
 	if (tarRead(buf, len, ctx->FH) != len)
 		/* We already would have exited for errors on reads, must be EOF */
-		exit_horribly(modulename,
-					  "could not read from input file: end of file\n");
+		fatal("could not read from input file: end of file");
 
 	ctx->filePos += len;
 	return;
@@ -917,7 +904,7 @@ _CloseArchive(ArchiveHandle *AH)
 
 		/* Sync the output file if one is defined */
 		if (AH->dosync && AH->fSpec)
-			(void) fsync_fname(AH->fSpec, false, progname);
+			(void) fsync_fname(AH->fSpec, false);
 	}
 
 	AH->FH = NULL;
@@ -971,7 +958,7 @@ _StartBlob(ArchiveHandle *AH, TocEntry *te, Oid oid)
 	char	   *sfx;
 
 	if (oid == 0)
-		exit_horribly(modulename, "invalid OID for large object (%u)\n", oid);
+		fatal("invalid OID for large object (%u)", oid);
 
 	if (AH->compression != 0)
 		sfx = ".gz";
@@ -1101,8 +1088,7 @@ _tarAddFile(ArchiveHandle *AH, TAR_MEMBER *th)
 	fseeko(tmp, 0, SEEK_END);
 	th->fileLen = ftello(tmp);
 	if (th->fileLen < 0)
-		exit_horribly(modulename, "could not determine seek position in archive file: %s\n",
-					  strerror(errno));
+		fatal("could not determine seek position in archive file: %m");
 	fseeko(tmp, 0, SEEK_SET);
 
 	_tarWriteHeader(th);
@@ -1117,8 +1103,7 @@ _tarAddFile(ArchiveHandle *AH, TAR_MEMBER *th)
 		READ_ERROR_EXIT(tmp);
 
 	if (fclose(tmp) != 0)		/* This *should* delete it... */
-		exit_horribly(modulename, "could not close temporary file: %s\n",
-					  strerror(errno));
+		fatal("could not close temporary file: %m");
 
 	if (len != th->fileLen)
 	{
@@ -1127,7 +1112,7 @@ _tarAddFile(ArchiveHandle *AH, TAR_MEMBER *th)
 
 		snprintf(buf1, sizeof(buf1), INT64_FORMAT, (int64) len);
 		snprintf(buf2, sizeof(buf2), INT64_FORMAT, (int64) th->fileLen);
-		exit_horribly(modulename, "actual file length (%s) does not match expected (%s)\n",
+		fatal("actual file length (%s) does not match expected (%s)",
 					  buf1, buf2);
 	}
 
@@ -1164,7 +1149,7 @@ _tarPositionTo(ArchiveHandle *AH, const char *filename)
 
 		snprintf(buf1, sizeof(buf1), INT64_FORMAT, (int64) ctx->tarFHpos);
 		snprintf(buf2, sizeof(buf2), INT64_FORMAT, (int64) ctx->tarNextMember);
-		ahlog(AH, 4, "moving from position %s to next member at file position %s\n",
+		pg_log_debug("moving from position %s to next member at file position %s",
 			  buf1, buf2);
 
 		while (ctx->tarFHpos < ctx->tarNextMember)
@@ -1175,7 +1160,7 @@ _tarPositionTo(ArchiveHandle *AH, const char *filename)
 		char		buf[100];
 
 		snprintf(buf, sizeof(buf), INT64_FORMAT, (int64) ctx->tarFHpos);
-		ahlog(AH, 4, "now at file position %s\n", buf);
+		pg_log_debug("now at file position %s", buf);
 	}
 
 	/* We are at the start of the file, or at the next member */
@@ -1184,7 +1169,7 @@ _tarPositionTo(ArchiveHandle *AH, const char *filename)
 	if (!_tarGetHeader(AH, th))
 	{
 		if (filename)
-			exit_horribly(modulename, "could not find header for file \"%s\" in tar archive\n", filename);
+			fatal("could not find header for file \"%s\" in tar archive", filename);
 		else
 		{
 			/*
@@ -1198,12 +1183,12 @@ _tarPositionTo(ArchiveHandle *AH, const char *filename)
 
 	while (filename != NULL && strcmp(th->targetFile, filename) != 0)
 	{
-		ahlog(AH, 4, "skipping tar member %s\n", th->targetFile);
+		pg_log_debug("skipping tar member %s", th->targetFile);
 
 		id = atoi(th->targetFile);
 		if ((TocIDRequired(AH, id) & REQ_DATA) != 0)
-			exit_horribly(modulename, "restoring data out of order is not supported in this archive format: "
-						  "\"%s\" is required, but comes before \"%s\" in the archive file.\n",
+			fatal("restoring data out of order is not supported in this archive format: "
+						  "\"%s\" is required, but comes before \"%s\" in the archive file.",
 						  th->targetFile, filename);
 
 		/* Header doesn't match, so read to next header */
@@ -1214,7 +1199,7 @@ _tarPositionTo(ArchiveHandle *AH, const char *filename)
 			_tarReadRaw(AH, &header[0], 512, NULL, ctx->tarFH);
 
 		if (!_tarGetHeader(AH, th))
-			exit_horribly(modulename, "could not find header for file \"%s\" in tar archive\n", filename);
+			fatal("could not find header for file \"%s\" in tar archive", filename);
 	}
 
 	ctx->tarNextMember = ctx->tarFHpos + ((th->fileLen + 511) & ~511);
@@ -1247,9 +1232,8 @@ _tarGetHeader(ArchiveHandle *AH, TAR_MEMBER *th)
 			return 0;
 
 		if (len != 512)
-			exit_horribly(modulename,
-						  ngettext("incomplete tar header found (%lu byte)\n",
-								   "incomplete tar header found (%lu bytes)\n",
+			fatal(ngettext("incomplete tar header found (%lu byte)",
+						   "incomplete tar header found (%lu bytes)",
 								   len),
 						  (unsigned long) len);
 
@@ -1289,7 +1273,7 @@ _tarGetHeader(ArchiveHandle *AH, TAR_MEMBER *th)
 
 		snprintf(posbuf, sizeof(posbuf), UINT64_FORMAT, (uint64) hPos);
 		snprintf(lenbuf, sizeof(lenbuf), UINT64_FORMAT, (uint64) len);
-		ahlog(AH, 3, "TOC Entry %s at %s (length %s, checksum %d)\n",
+		pg_log_debug("TOC Entry %s at %s (length %s, checksum %d)",
 			  tag, posbuf, lenbuf, sum);
 	}
 
@@ -1299,9 +1283,7 @@ _tarGetHeader(ArchiveHandle *AH, TAR_MEMBER *th)
 
 		snprintf(posbuf, sizeof(posbuf), UINT64_FORMAT,
 				 (uint64) ftello(ctx->tarFH));
-		exit_horribly(modulename,
-					  "corrupt tar header found in %s "
-					  "(expected %d, computed %d) file position %s\n",
+		fatal("corrupt tar header found in %s (expected %d, computed %d) file position %s",
 					  tag, sum, chk, posbuf);
 	}
 
diff --git a/src/bin/pg_dump/pg_backup_utils.c b/src/bin/pg_dump/pg_backup_utils.c
index 1bdce68ff9..80c2594e57 100644
--- a/src/bin/pg_dump/pg_backup_utils.c
+++ b/src/bin/pg_dump/pg_backup_utils.c
@@ -93,29 +93,15 @@ vwrite_msg(const char *modulename, const char *fmt, va_list ap)
 	vfprintf(stderr, _(fmt), ap);
 }
 
-/*
- * Fail and die, with a message to stderr.  Parameters as for write_msg.
- *
- * Note that on_exit_nicely callbacks will get run.
- */
-void
-exit_horribly(const char *modulename, const char *fmt,...)
-{
-	va_list		ap;
-
-	va_start(ap, fmt);
-	vwrite_msg(modulename, fmt, ap);
-	va_end(ap);
-
-	exit_nicely(1);
-}
-
 /* Register a callback to be run when exit_nicely is invoked. */
 void
 on_exit_nicely(on_exit_nicely_callback function, void *arg)
 {
 	if (on_exit_nicely_index >= MAX_ON_EXIT_NICELY)
-		exit_horribly(NULL, "out of on_exit_nicely slots\n");
+	{
+		pg_log_fatal("out of on_exit_nicely slots");
+		exit_nicely(1);
+	}
 	on_exit_nicely_list[on_exit_nicely_index].function = function;
 	on_exit_nicely_list[on_exit_nicely_index].arg = arg;
 	on_exit_nicely_index++;
diff --git a/src/bin/pg_dump/pg_backup_utils.h b/src/bin/pg_dump/pg_backup_utils.h
index 7dbf3c9feb..2e1f31f04d 100644
--- a/src/bin/pg_dump/pg_backup_utils.h
+++ b/src/bin/pg_dump/pg_backup_utils.h
@@ -15,6 +15,8 @@
 #ifndef PG_BACKUP_UTILS_H
 #define PG_BACKUP_UTILS_H
 
+#include "fe_utils/logging.h"
+
 typedef enum					/* bits returned by set_dump_section */
 {
 	DUMP_PRE_DATA = 0x01,
@@ -33,6 +35,6 @@ extern void vwrite_msg(const char *modulename, const char *fmt, va_list ap) pg_a
 extern void on_exit_nicely(on_exit_nicely_callback function, void *arg);
 extern void exit_nicely(int code) pg_attribute_noreturn();
 
-extern void exit_horribly(const char *modulename, const char *fmt,...) pg_attribute_printf(2, 3) pg_attribute_noreturn();
+#define fatal(...) do { pg_log_error(__VA_ARGS__); exit_nicely(1); } while(0)
 
 #endif							/* PG_BACKUP_UTILS_H */
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index 0e129f9654..5f7a50c8c2 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -62,6 +62,7 @@
 #include "pg_backup_utils.h"
 #include "pg_dump.h"
 #include "fe_utils/connect.h"
+#include "fe_utils/logging.h"
 #include "fe_utils/string_utils.h"
 
 
@@ -91,8 +92,6 @@ typedef enum OidOptions
 } OidOptions;
 
 /* global decls */
-bool		g_verbose;			/* User wants verbose narration of our
-								 * activities. */
 static bool dosync = true;		/* Issue fsync() to make dump durable on disk. */
 
 /* subquery used to convert user ID (eg, datdba) to user name */
@@ -304,6 +303,7 @@ main(int argc, char **argv)
 	int			optindex;
 	RestoreOptions *ropt;
 	Archive    *fout;			/* the script file */
+	bool		g_verbose = false;
 	const char *dumpencoding = NULL;
 	const char *dumpsnapshot = NULL;
 	char	   *use_role = NULL;
@@ -382,6 +382,8 @@ main(int argc, char **argv)
 	};
 
 	set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_dump"));
+	pg_logging_init(argv[0]);
+	pg_logging_set_level(PG_LOG_WARNING);
 
 	/*
 	 * Initialize what we need for parallel execution, especially for thread
@@ -389,8 +391,6 @@ main(int argc, char **argv)
 	 */
 	init_parallel_dump_utils();
 
-	g_verbose = false;
-
 	strcpy(g_comment_start, "-- ");
 	g_comment_end[0] = '\0';
 	strcpy(g_opaque_type, "opaque");
@@ -506,6 +506,7 @@ main(int argc, char **argv)
 
 			case 'v':			/* verbose */
 				g_verbose = true;
+				pg_logging_set_level(PG_LOG_INFO);
 				break;
 
 			case 'w':
@@ -524,7 +525,7 @@ main(int argc, char **argv)
 				compressLevel = atoi(optarg);
 				if (compressLevel < 0 || compressLevel > 9)
 				{
-					write_msg(NULL, "compression level must be in range 0..9\n");
+					pg_log_error("compression level must be in range 0..9");
 					exit_nicely(1);
 				}
 				break;
@@ -573,8 +574,8 @@ main(int argc, char **argv)
 	/* Complain if any arguments remain */
 	if (optind < argc)
 	{
-		fprintf(stderr, _("%s: too many command-line arguments (first is \"%s\")\n"),
-				progname, argv[optind]);
+		pg_log_error("too many command-line arguments (first is \"%s\")",
+					 argv[optind]);
 		fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
 				progname);
 		exit_nicely(1);
@@ -594,21 +595,21 @@ main(int argc, char **argv)
 
 	if (dopt.dataOnly && dopt.schemaOnly)
 	{
-		write_msg(NULL, "options -s/--schema-only and -a/--data-only cannot be used together\n");
+		pg_log_error("options -s/--schema-only and -a/--data-only cannot be used together");
 		exit_nicely(1);
 	}
 
 	if (dopt.dataOnly && dopt.outputClean)
 	{
-		write_msg(NULL, "options -c/--clean and -a/--data-only cannot be used together\n");
+		pg_log_error("options -c/--clean and -a/--data-only cannot be used together");
 		exit_nicely(1);
 	}
 
 	if (dopt.if_exists && !dopt.outputClean)
-		exit_horribly(NULL, "option --if-exists requires option -c/--clean\n");
+		fatal("option --if-exists requires option -c/--clean");
 
 	if (dopt.do_nothing && !(dopt.dump_inserts || dopt.column_inserts))
-		exit_horribly(NULL, "option --on-conflict-do-nothing requires option --inserts or --column-inserts\n");
+		fatal("option --on-conflict-do-nothing requires option --inserts or --column-inserts");
 
 	/* Identify archive format to emit */
 	archiveFormat = parseArchiveFormat(format, &archiveMode);
@@ -630,8 +631,7 @@ main(int argc, char **argv)
 
 #ifndef HAVE_LIBZ
 	if (compressLevel != 0)
-		write_msg(NULL, "WARNING: requested compression not available in this "
-				  "installation -- archive will be uncompressed\n");
+		pg_log_warning("requested compression not available in this installation -- archive will be uncompressed");
 	compressLevel = 0;
 #endif
 
@@ -652,11 +652,11 @@ main(int argc, char **argv)
 		|| numWorkers > MAXIMUM_WAIT_OBJECTS
 #endif
 		)
-		exit_horribly(NULL, "invalid number of parallel jobs\n");
+		fatal("invalid number of parallel jobs");
 
 	/* Parallel backup only in the directory archive format so far */
 	if (archiveFormat != archDirectory && numWorkers > 1)
-		exit_horribly(NULL, "parallel backup only supported by the directory format\n");
+		fatal("parallel backup only supported by the directory format");
 
 	/* Open the output file */
 	fout = CreateArchive(filename, archiveFormat, compressLevel, dosync,
@@ -671,6 +671,7 @@ main(int argc, char **argv)
 	/* Let the archiver know how noisy to be */
 	fout->verbose = g_verbose;
 
+
 	/*
 	 * We allow the server to be back to 8.0, and up to any minor release of
 	 * our own major version.  (See also version check in pg_dumpall.c.)
@@ -710,15 +711,13 @@ main(int argc, char **argv)
 	/* check the version for the synchronized snapshots feature */
 	if (numWorkers > 1 && fout->remoteVersion < 90200
 		&& !dopt.no_synchronized_snapshots)
-		exit_horribly(NULL,
-					  "Synchronized snapshots are not supported by this server version.\n"
-					  "Run with --no-synchronized-snapshots instead if you do not need\n"
-					  "synchronized snapshots.\n");
+		fatal("Synchronized snapshots are not supported by this server version.\n"
+			  "Run with --no-synchronized-snapshots instead if you do not need\n"
+			  "synchronized snapshots.");
 
 	/* check the version when a snapshot is explicitly specified by user */
 	if (dumpsnapshot && fout->remoteVersion < 90200)
-		exit_horribly(NULL,
-					  "Exported snapshots are not supported by this server version.\n");
+		fatal("Exported snapshots are not supported by this server version.");
 
 	/*
 	 * Find the last built-in OID, if needed (prior to 8.1)
@@ -730,8 +729,7 @@ main(int argc, char **argv)
 	else
 		g_last_builtin_oid = FirstNormalObjectId - 1;
 
-	if (g_verbose)
-		write_msg(NULL, "last built-in OID is %u\n", g_last_builtin_oid);
+	pg_log_info("last built-in OID is %u", g_last_builtin_oid);
 
 	/* Expand schema selection patterns into OID lists */
 	if (schema_include_patterns.head != NULL)
@@ -740,7 +738,7 @@ main(int argc, char **argv)
 									&schema_include_oids,
 									strict_names);
 		if (schema_include_oids.head == NULL)
-			exit_horribly(NULL, "no matching schemas were found\n");
+			fatal("no matching schemas were found");
 	}
 	expand_schema_name_patterns(fout, &schema_exclude_patterns,
 								&schema_exclude_oids,
@@ -754,7 +752,7 @@ main(int argc, char **argv)
 								   &table_include_oids,
 								   strict_names);
 		if (table_include_oids.head == NULL)
-			exit_horribly(NULL, "no matching tables were found\n");
+			fatal("no matching tables were found");
 	}
 	expand_table_name_patterns(fout, &table_exclude_patterns,
 							   &table_exclude_oids,
@@ -1016,8 +1014,8 @@ setup_connection(Archive *AH, const char *dumpencoding,
 	if (dumpencoding)
 	{
 		if (PQsetClientEncoding(conn, dumpencoding) < 0)
-			exit_horribly(NULL, "invalid client encoding \"%s\" specified\n",
-						  dumpencoding);
+			fatal("invalid client encoding \"%s\" specified",
+				  dumpencoding);
 	}
 
 	/*
@@ -1152,10 +1150,9 @@ setup_connection(Archive *AH, const char *dumpencoding,
 			 !dopt->no_synchronized_snapshots)
 	{
 		if (AH->isStandby && AH->remoteVersion < 100000)
-			exit_horribly(NULL,
-						  "Synchronized snapshots on standby servers are not supported by this server version.\n"
-						  "Run with --no-synchronized-snapshots instead if you do not need\n"
-						  "synchronized snapshots.\n");
+			fatal("Synchronized snapshots on standby servers are not supported by this server version.\n"
+				  "Run with --no-synchronized-snapshots instead if you do not need\n"
+				  "synchronized snapshots.");
 
 
 		AH->sync_snapshot_id = get_synchronized_snapshot(AH);
@@ -1222,7 +1219,7 @@ parseArchiveFormat(const char *format, ArchiveMode *mode)
 	else if (pg_strcasecmp(format, "tar") == 0)
 		archiveFormat = archTar;
 	else
-		exit_horribly(NULL, "invalid output format \"%s\" specified\n", format);
+		fatal("invalid output format \"%s\" specified", format);
 	return archiveFormat;
 }
 
@@ -1260,7 +1257,7 @@ expand_schema_name_patterns(Archive *fout,
 
 		res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
 		if (strict_names && PQntuples(res) == 0)
-			exit_horribly(NULL, "no matching schemas were found for pattern \"%s\"\n", cell->val);
+			fatal("no matching schemas were found for pattern \"%s\"", cell->val);
 
 		for (i = 0; i < PQntuples(res); i++)
 		{
@@ -1324,7 +1321,7 @@ expand_table_name_patterns(Archive *fout,
 		PQclear(ExecuteSqlQueryForSingleRow(fout,
 											ALWAYS_SECURE_SEARCH_PATH_SQL));
 		if (strict_names && PQntuples(res) == 0)
-			exit_horribly(NULL, "no matching tables were found for pattern \"%s\"\n", cell->val);
+			fatal("no matching tables were found for pattern \"%s\"", cell->val);
 
 		for (i = 0; i < PQntuples(res); i++)
 		{
@@ -1738,9 +1735,8 @@ dumpTableData_copy(Archive *fout, void *dcontext)
 	char	   *copybuf;
 	const char *column_list;
 
-	if (g_verbose)
-		write_msg(NULL, "dumping contents of table \"%s.%s\"\n",
-				  tbinfo->dobj.namespace->dobj.name, classname);
+	pg_log_info("dumping contents of table \"%s.%s\"",
+				tbinfo->dobj.namespace->dobj.name, classname);
 
 	/*
 	 * Specify the column list explicitly so that we have no possibility of
@@ -1840,9 +1836,9 @@ dumpTableData_copy(Archive *fout, void *dcontext)
 	if (ret == -2)
 	{
 		/* copy data transfer failed */
-		write_msg(NULL, "Dumping the contents of table \"%s\" failed: PQgetCopyData() failed.\n", classname);
-		write_msg(NULL, "Error message from server: %s", PQerrorMessage(conn));
-		write_msg(NULL, "The command was: %s\n", q->data);
+		pg_log_error("Dumping the contents of table \"%s\" failed: PQgetCopyData() failed.", classname);
+		pg_log_error("Error message from server: %s", PQerrorMessage(conn));
+		pg_log_error("The command was: %s", q->data);
 		exit_nicely(1);
 	}
 
@@ -1850,16 +1846,16 @@ dumpTableData_copy(Archive *fout, void *dcontext)
 	res = PQgetResult(conn);
 	if (PQresultStatus(res) != PGRES_COMMAND_OK)
 	{
-		write_msg(NULL, "Dumping the contents of table \"%s\" failed: PQgetResult() failed.\n", classname);
-		write_msg(NULL, "Error message from server: %s", PQerrorMessage(conn));
-		write_msg(NULL, "The command was: %s\n", q->data);
+		pg_log_error("Dumping the contents of table \"%s\" failed: PQgetResult() failed.", classname);
+		pg_log_error("Error message from server: %s", PQerrorMessage(conn));
+		pg_log_error("The command was: %s", q->data);
 		exit_nicely(1);
 	}
 	PQclear(res);
 
 	/* Do this to ensure we've pumped libpq back to idle state */
 	if (PQgetResult(conn) != NULL)
-		write_msg(NULL, "WARNING: unexpected extra results during COPY of table \"%s\"\n",
+		pg_log_warning("unexpected extra results during COPY of table \"%s\"",
 				  classname);
 
 	destroyPQExpBuffer(q);
@@ -2560,8 +2556,7 @@ dumpDatabase(Archive *fout)
 				minmxid;
 	char	   *qdatname;
 
-	if (g_verbose)
-		write_msg(NULL, "saving database definition\n");
+	pg_log_info("saving database definition");
 
 	/* Fetch the database-level properties for this database */
 	if (fout->remoteVersion >= 90600)
@@ -3006,8 +3001,7 @@ dumpEncoding(Archive *AH)
 	const char *encname = pg_encoding_to_char(AH->encoding);
 	PQExpBuffer qry = createPQExpBuffer();
 
-	if (g_verbose)
-		write_msg(NULL, "saving encoding = %s\n", encname);
+	pg_log_info("saving encoding = %s", encname);
 
 	appendPQExpBufferStr(qry, "SET client_encoding = ");
 	appendStringLiteralAH(qry, encname, AH);
@@ -3033,9 +3027,8 @@ dumpStdStrings(Archive *AH)
 	const char *stdstrings = AH->std_strings ? "on" : "off";
 	PQExpBuffer qry = createPQExpBuffer();
 
-	if (g_verbose)
-		write_msg(NULL, "saving standard_conforming_strings = %s\n",
-				  stdstrings);
+	pg_log_info("saving standard_conforming_strings = %s",
+				stdstrings);
 
 	appendPQExpBuffer(qry, "SET standard_conforming_strings = '%s';\n",
 					  stdstrings);
@@ -3074,7 +3067,7 @@ dumpSearchPath(Archive *AH)
 									  "SELECT pg_catalog.current_schemas(false)");
 
 	if (!parsePGArray(PQgetvalue(res, 0, 0), &schemanames, &nschemanames))
-		exit_horribly(NULL, "could not parse result of current_schemas()\n");
+		fatal("could not parse result of current_schemas()");
 
 	/*
 	 * We use set_config(), not a simple "SET search_path" command, because
@@ -3093,8 +3086,7 @@ dumpSearchPath(Archive *AH)
 	appendStringLiteralAH(qry, path->data, AH);
 	appendPQExpBufferStr(qry, ", false);\n");
 
-	if (g_verbose)
-		write_msg(NULL, "saving search_path = %s\n", path->data);
+	pg_log_info("saving search_path = %s", path->data);
 
 	ArchiveEntry(AH, nilCatalogId, createDumpId(),
 				 "SEARCHPATH", NULL, NULL, "",
@@ -3135,9 +3127,7 @@ getBlobs(Archive *fout)
 	int			i_initlomacl;
 	int			i_initrlomacl;
 
-	/* Verbose message */
-	if (g_verbose)
-		write_msg(NULL, "reading large objects\n");
+	pg_log_info("reading large objects");
 
 	/* Fetch BLOB OIDs, and owner/ACL data if >= 9.0 */
 	if (fout->remoteVersion >= 90600)
@@ -3320,8 +3310,7 @@ dumpBlobs(Archive *fout, void *arg)
 	int			i;
 	int			cnt;
 
-	if (g_verbose)
-		write_msg(NULL, "saving large objects\n");
+	pg_log_info("saving large objects");
 
 	/*
 	 * Currently, we re-fetch all BLOB OIDs using a cursor.  Consider scanning
@@ -3357,7 +3346,7 @@ dumpBlobs(Archive *fout, void *arg)
 			/* Open the BLOB */
 			loFd = lo_open(conn, blobOid, INV_READ);
 			if (loFd == -1)
-				exit_horribly(NULL, "could not open large object %u: %s",
+				fatal("could not open large object %u: %s",
 							  blobOid, PQerrorMessage(conn));
 
 			StartBlob(fout, blobOid);
@@ -3367,7 +3356,7 @@ dumpBlobs(Archive *fout, void *arg)
 			{
 				cnt = lo_read(conn, loFd, buf, LOBBUFSIZE);
 				if (cnt < 0)
-					exit_horribly(NULL, "error reading large object %u: %s",
+					fatal("error reading large object %u: %s",
 								  blobOid, PQerrorMessage(conn));
 
 				WriteData(fout, buf, cnt);
@@ -3419,10 +3408,9 @@ getPolicies(Archive *fout, TableInfo tblinfo[], int numTables)
 		if (!(tbinfo->dobj.dump & DUMP_COMPONENT_POLICY))
 			continue;
 
-		if (g_verbose)
-			write_msg(NULL, "reading row security enabled for table \"%s.%s\"\n",
-					  tbinfo->dobj.namespace->dobj.name,
-					  tbinfo->dobj.name);
+		pg_log_info("reading row security enabled for table \"%s.%s\"",
+					tbinfo->dobj.namespace->dobj.name,
+					tbinfo->dobj.name);
 
 		/*
 		 * Get row security enabled information for the table. We represent
@@ -3451,10 +3439,9 @@ getPolicies(Archive *fout, TableInfo tblinfo[], int numTables)
 			polinfo->polwithcheck = NULL;
 		}
 
-		if (g_verbose)
-			write_msg(NULL, "reading policies for table \"%s.%s\"\n",
-					  tbinfo->dobj.namespace->dobj.name,
-					  tbinfo->dobj.name);
+		pg_log_info("reading policies for table \"%s.%s\"",
+					tbinfo->dobj.namespace->dobj.name,
+					tbinfo->dobj.name);
 
 		resetPQExpBuffer(query);
 
@@ -3602,7 +3589,7 @@ dumpPolicy(Archive *fout, PolicyInfo *polinfo)
 		cmd = " FOR DELETE";
 	else
 	{
-		write_msg(NULL, "unexpected policy command type: %c\n",
+		pg_log_error("unexpected policy command type: %c",
 				  polinfo->polcmd);
 		exit_nicely(1);
 	}
@@ -3730,7 +3717,7 @@ getPublications(Archive *fout)
 			(strcmp(PQgetvalue(res, i, i_pubtruncate), "t") == 0);
 
 		if (strlen(pubinfo[i].rolname) == 0)
-			write_msg(NULL, "WARNING: owner of publication \"%s\" appears to be invalid\n",
+			pg_log_warning("owner of publication \"%s\" appears to be invalid",
 					  pubinfo[i].dobj.name);
 
 		/* Decide whether we want to dump it */
@@ -3869,10 +3856,9 @@ getPublicationTables(Archive *fout, TableInfo tblinfo[], int numTables)
 		if (!(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
 			continue;
 
-		if (g_verbose)
-			write_msg(NULL, "reading publication membership for table \"%s.%s\"\n",
-					  tbinfo->dobj.namespace->dobj.name,
-					  tbinfo->dobj.name);
+		pg_log_info("reading publication membership for table \"%s.%s\"",
+					tbinfo->dobj.namespace->dobj.name,
+					tbinfo->dobj.name);
 
 		resetPQExpBuffer(query);
 
@@ -4016,7 +4002,7 @@ getSubscriptions(Archive *fout)
 							  PGRES_TUPLES_OK);
 		n = atoi(PQgetvalue(res, 0, 0));
 		if (n > 0)
-			write_msg(NULL, "WARNING: subscriptions not dumped because current user is not a superuser\n");
+			pg_log_warning("subscriptions not dumped because current user is not a superuser");
 		PQclear(res);
 		return;
 	}
@@ -4070,7 +4056,7 @@ getSubscriptions(Archive *fout)
 			pg_strdup(PQgetvalue(res, i, i_subpublications));
 
 		if (strlen(subinfo[i].rolname) == 0)
-			write_msg(NULL, "WARNING: owner of subscription \"%s\" appears to be invalid\n",
+			pg_log_warning("owner of subscription \"%s\" appears to be invalid",
 					  subinfo[i].dobj.name);
 
 		/* Decide whether we want to dump it */
@@ -4114,8 +4100,7 @@ dumpSubscription(Archive *fout, SubscriptionInfo *subinfo)
 	/* Build list of quoted publications and append them to query. */
 	if (!parsePGArray(subinfo->subpublications, &pubnames, &npubnames))
 	{
-		write_msg(NULL,
-				  "WARNING: could not parse subpublications array\n");
+		pg_log_warning("could not parse subpublications array");
 		if (pubnames)
 			free(pubnames);
 		pubnames = NULL;
@@ -4383,7 +4368,7 @@ binary_upgrade_extension_member(PQExpBuffer upgrade_buffer,
 		extobj = NULL;
 	}
 	if (extobj == NULL)
-		exit_horribly(NULL, "could not find parent extension for %s %s\n",
+		fatal("could not find parent extension for %s %s",
 					  objtype, objname);
 
 	appendPQExpBufferStr(upgrade_buffer,
@@ -4515,7 +4500,7 @@ getNamespaces(Archive *fout, int *numNamespaces)
 			nsinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
 
 		if (strlen(nsinfo[i].rolname) == 0)
-			write_msg(NULL, "WARNING: owner of schema \"%s\" appears to be invalid\n",
+			pg_log_warning("owner of schema \"%s\" appears to be invalid",
 					  nsinfo[i].dobj.name);
 	}
 
@@ -4538,7 +4523,7 @@ findNamespace(Archive *fout, Oid nsoid)
 
 	nsinfo = findNamespaceByOid(nsoid);
 	if (nsinfo == NULL)
-		exit_horribly(NULL, "schema with OID %u does not exist\n", nsoid);
+		fatal("schema with OID %u does not exist", nsoid);
 	return nsinfo;
 }
 
@@ -4863,7 +4848,7 @@ getTypes(Archive *fout, int *numTypes)
 		}
 
 		if (strlen(tyinfo[i].rolname) == 0)
-			write_msg(NULL, "WARNING: owner of data type \"%s\" appears to be invalid\n",
+			pg_log_warning("owner of data type \"%s\" appears to be invalid",
 					  tyinfo[i].dobj.name);
 	}
 
@@ -4948,7 +4933,7 @@ getOperators(Archive *fout, int *numOprs)
 		oprinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
 
 		if (strlen(oprinfo[i].rolname) == 0)
-			write_msg(NULL, "WARNING: owner of operator \"%s\" appears to be invalid\n",
+			pg_log_warning("owner of operator \"%s\" appears to be invalid",
 					  oprinfo[i].dobj.name);
 	}
 
@@ -5250,7 +5235,7 @@ getOpclasses(Archive *fout, int *numOpclasses)
 		opcinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
 
 		if (strlen(opcinfo[i].rolname) == 0)
-			write_msg(NULL, "WARNING: owner of operator class \"%s\" appears to be invalid\n",
+			pg_log_warning("owner of operator class \"%s\" appears to be invalid",
 					  opcinfo[i].dobj.name);
 	}
 
@@ -5334,7 +5319,7 @@ getOpfamilies(Archive *fout, int *numOpfamilies)
 		opfinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
 
 		if (strlen(opfinfo[i].rolname) == 0)
-			write_msg(NULL, "WARNING: owner of operator family \"%s\" appears to be invalid\n",
+			pg_log_warning("owner of operator family \"%s\" appears to be invalid",
 					  opfinfo[i].dobj.name);
 	}
 
@@ -5503,7 +5488,7 @@ getAggregates(Archive *fout, int *numAggs)
 						  atooid(PQgetvalue(res, i, i_aggnamespace)));
 		agginfo[i].aggfn.rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
 		if (strlen(agginfo[i].aggfn.rolname) == 0)
-			write_msg(NULL, "WARNING: owner of aggregate function \"%s\" appears to be invalid\n",
+			pg_log_warning("owner of aggregate function \"%s\" appears to be invalid",
 					  agginfo[i].aggfn.dobj.name);
 		agginfo[i].aggfn.lang = InvalidOid; /* not currently interesting */
 		agginfo[i].aggfn.prorettype = InvalidOid;	/* not saved */
@@ -5763,8 +5748,7 @@ getFuncs(Archive *fout, int *numFuncs)
 			finfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
 
 		if (strlen(finfo[i].rolname) == 0)
-			write_msg(NULL,
-					  "WARNING: owner of function \"%s\" appears to be invalid\n",
+			pg_log_warning("owner of function \"%s\" appears to be invalid",
 					  finfo[i].dobj.name);
 	}
 
@@ -6548,7 +6532,7 @@ getTables(Archive *fout, int *numTables)
 
 		/* Emit notice if join for owner failed */
 		if (strlen(tblinfo[i].rolname) == 0)
-			write_msg(NULL, "WARNING: owner of table \"%s\" appears to be invalid\n",
+			pg_log_warning("owner of table \"%s\" appears to be invalid",
 					  tblinfo[i].dobj.name);
 	}
 
@@ -6590,7 +6574,7 @@ getOwnedSeqs(Archive *fout, TableInfo tblinfo[], int numTables)
 
 		owning_tab = findTableByOid(seqinfo->owning_tab);
 		if (owning_tab == NULL)
-			exit_horribly(NULL, "failed sanity check, parent table with OID %u of sequence with OID %u not found\n",
+			fatal("failed sanity check, parent table with OID %u of sequence with OID %u not found",
 						  seqinfo->owning_tab, seqinfo->dobj.catId.oid);
 
 		/*
@@ -6734,10 +6718,9 @@ getIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
 			!tbinfo->interesting)
 			continue;
 
-		if (g_verbose)
-			write_msg(NULL, "reading indexes for table \"%s.%s\"\n",
-					  tbinfo->dobj.namespace->dobj.name,
-					  tbinfo->dobj.name);
+		pg_log_info("reading indexes for table \"%s.%s\"",
+					tbinfo->dobj.namespace->dobj.name,
+					tbinfo->dobj.name);
 
 		/*
 		 * The point of the messy-looking outer join is to find a constraint
@@ -7136,10 +7119,9 @@ getConstraints(Archive *fout, TableInfo tblinfo[], int numTables)
 			!(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
 			continue;
 
-		if (g_verbose)
-			write_msg(NULL, "reading foreign key constraints for table \"%s.%s\"\n",
-					  tbinfo->dobj.namespace->dobj.name,
-					  tbinfo->dobj.name);
+		pg_log_info("reading foreign key constraints for table \"%s.%s\"",
+					tbinfo->dobj.namespace->dobj.name,
+					tbinfo->dobj.name);
 
 		resetPQExpBuffer(query);
 		if (fout->remoteVersion >= 110000)
@@ -7356,7 +7338,7 @@ getRules(Archive *fout, int *numRules)
 		ruletableoid = atooid(PQgetvalue(res, i, i_ruletable));
 		ruleinfo[i].ruletable = findTableByOid(ruletableoid);
 		if (ruleinfo[i].ruletable == NULL)
-			exit_horribly(NULL, "failed sanity check, parent table with OID %u of pg_rewrite entry with OID %u not found\n",
+			fatal("failed sanity check, parent table with OID %u of pg_rewrite entry with OID %u not found",
 						  ruletableoid, ruleinfo[i].dobj.catId.oid);
 		ruleinfo[i].dobj.namespace = ruleinfo[i].ruletable->dobj.namespace;
 		ruleinfo[i].dobj.dump = ruleinfo[i].ruletable->dobj.dump;
@@ -7439,10 +7421,9 @@ getTriggers(Archive *fout, TableInfo tblinfo[], int numTables)
 			!(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
 			continue;
 
-		if (g_verbose)
-			write_msg(NULL, "reading triggers for table \"%s.%s\"\n",
-					  tbinfo->dobj.namespace->dobj.name,
-					  tbinfo->dobj.name);
+		pg_log_info("reading triggers for table \"%s.%s\"",
+					tbinfo->dobj.namespace->dobj.name,
+					tbinfo->dobj.name);
 
 		resetPQExpBuffer(query);
 		if (fout->remoteVersion >= 90000)
@@ -7573,7 +7554,7 @@ getTriggers(Archive *fout, TableInfo tblinfo[], int numTables)
 					if (OidIsValid(tginfo[j].tgconstrrelid))
 					{
 						if (PQgetisnull(res, j, i_tgconstrrelname))
-							exit_horribly(NULL, "query produced null referenced table name for foreign key trigger \"%s\" on table \"%s\" (OID of table: %u)\n",
+							fatal("query produced null referenced table name for foreign key trigger \"%s\" on table \"%s\" (OID of table: %u)",
 										  tginfo[j].dobj.name,
 										  tbinfo->dobj.name,
 										  tginfo[j].tgconstrrelid);
@@ -8127,10 +8108,9 @@ getTableAttrs(Archive *fout, TableInfo *tblinfo, int numTables)
 		 * we must read the attribute names in attribute number order! because
 		 * we will use the attnum to index into the attnames array later.
 		 */
-		if (g_verbose)
-			write_msg(NULL, "finding the columns and types of table \"%s.%s\"\n",
-					  tbinfo->dobj.namespace->dobj.name,
-					  tbinfo->dobj.name);
+		pg_log_info("finding the columns and types of table \"%s.%s\"",
+					tbinfo->dobj.namespace->dobj.name,
+					tbinfo->dobj.name);
 
 		resetPQExpBuffer(q);
 
@@ -8255,8 +8235,7 @@ getTableAttrs(Archive *fout, TableInfo *tblinfo, int numTables)
 		for (j = 0; j < ntups; j++)
 		{
 			if (j + 1 != atoi(PQgetvalue(res, j, i_attnum)))
-				exit_horribly(NULL,
-							  "invalid column numbering in table \"%s\"\n",
+				fatal("invalid column numbering in table \"%s\"",
 							  tbinfo->dobj.name);
 			tbinfo->attnames[j] = pg_strdup(PQgetvalue(res, j, i_attname));
 			tbinfo->atttypnames[j] = pg_strdup(PQgetvalue(res, j, i_atttypname));
@@ -8292,10 +8271,9 @@ getTableAttrs(Archive *fout, TableInfo *tblinfo, int numTables)
 			AttrDefInfo *attrdefs;
 			int			numDefaults;
 
-			if (g_verbose)
-				write_msg(NULL, "finding default expressions of table \"%s.%s\"\n",
-						  tbinfo->dobj.namespace->dobj.name,
-						  tbinfo->dobj.name);
+			pg_log_info("finding default expressions of table \"%s.%s\"",
+						tbinfo->dobj.namespace->dobj.name,
+						tbinfo->dobj.name);
 
 			printfPQExpBuffer(q, "SELECT tableoid, oid, adnum, "
 							  "pg_catalog.pg_get_expr(adbin, adrelid) AS adsrc "
@@ -8315,8 +8293,7 @@ getTableAttrs(Archive *fout, TableInfo *tblinfo, int numTables)
 				adnum = atoi(PQgetvalue(res, j, 2));
 
 				if (adnum <= 0 || adnum > ntups)
-					exit_horribly(NULL,
-								  "invalid adnum value %d for table \"%s\"\n",
+					fatal("invalid adnum value %d for table \"%s\"",
 								  adnum, tbinfo->dobj.name);
 
 				/*
@@ -8381,10 +8358,9 @@ getTableAttrs(Archive *fout, TableInfo *tblinfo, int numTables)
 			ConstraintInfo *constrs;
 			int			numConstrs;
 
-			if (g_verbose)
-				write_msg(NULL, "finding check constraints for table \"%s.%s\"\n",
-						  tbinfo->dobj.namespace->dobj.name,
-						  tbinfo->dobj.name);
+			pg_log_info("finding check constraints for table \"%s.%s\"",
+						tbinfo->dobj.namespace->dobj.name,
+						tbinfo->dobj.name);
 
 			resetPQExpBuffer(q);
 			if (fout->remoteVersion >= 90200)
@@ -8431,11 +8407,11 @@ getTableAttrs(Archive *fout, TableInfo *tblinfo, int numTables)
 			numConstrs = PQntuples(res);
 			if (numConstrs != tbinfo->ncheck)
 			{
-				write_msg(NULL, ngettext("expected %d check constraint on table \"%s\" but found %d\n",
-										 "expected %d check constraints on table \"%s\" but found %d\n",
-										 tbinfo->ncheck),
+				pg_log_error(ngettext("expected %d check constraint on table \"%s\" but found %d",
+									  "expected %d check constraints on table \"%s\" but found %d",
+									  tbinfo->ncheck),
 						  tbinfo->ncheck, tbinfo->dobj.name, numConstrs);
-				write_msg(NULL, "(The system catalogs might be corrupted.)\n");
+				pg_log_error("(The system catalogs might be corrupted.)");
 				exit_nicely(1);
 			}
 
@@ -10010,7 +9986,7 @@ dumpType(Archive *fout, TypeInfo *tyinfo)
 	else if (tyinfo->typtype == TYPTYPE_PSEUDO && !tyinfo->isDefined)
 		dumpUndefinedType(fout, tyinfo);
 	else
-		write_msg(NULL, "WARNING: typtype of data type \"%s\" appears to be invalid\n",
+		pg_log_warning("typtype of data type \"%s\" appears to be invalid",
 				  tyinfo->dobj.name);
 }
 
@@ -11370,7 +11346,7 @@ format_function_arguments_old(Archive *fout,
 					argmode = "INOUT ";
 					break;
 				default:
-					write_msg(NULL, "WARNING: bogus value in proargmodes array\n");
+					pg_log_warning("bogus value in proargmodes array");
 					argmode = "";
 					break;
 			}
@@ -11715,7 +11691,7 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
 		if (!parsePGArray(proallargtypes, &allargtypes, &nitems) ||
 			nitems < finfo->nargs)
 		{
-			write_msg(NULL, "WARNING: could not parse proallargtypes array\n");
+			pg_log_warning("could not parse proallargtypes array");
 			if (allargtypes)
 				free(allargtypes);
 			allargtypes = NULL;
@@ -11731,7 +11707,7 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
 		if (!parsePGArray(proargmodes, &argmodes, &nitems) ||
 			nitems != nallargs)
 		{
-			write_msg(NULL, "WARNING: could not parse proargmodes array\n");
+			pg_log_warning("could not parse proargmodes array");
 			if (argmodes)
 				free(argmodes);
 			argmodes = NULL;
@@ -11745,7 +11721,7 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
 		if (!parsePGArray(proargnames, &argnames, &nitems) ||
 			nitems != nallargs)
 		{
-			write_msg(NULL, "WARNING: could not parse proargnames array\n");
+			pg_log_warning("could not parse proargnames array");
 			if (argnames)
 				free(argnames);
 			argnames = NULL;
@@ -11756,7 +11732,7 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
 	{
 		if (!parsePGArray(proconfig, &configitems, &nconfigitems))
 		{
-			write_msg(NULL, "WARNING: could not parse proconfig array\n");
+			pg_log_warning("could not parse proconfig array");
 			if (configitems)
 				free(configitems);
 			configitems = NULL;
@@ -11836,7 +11812,7 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
 		else if (provolatile[0] == PROVOLATILE_STABLE)
 			appendPQExpBufferStr(q, " STABLE");
 		else if (provolatile[0] != PROVOLATILE_VOLATILE)
-			exit_horribly(NULL, "unrecognized provolatile value for function \"%s\"\n",
+			fatal("unrecognized provolatile value for function \"%s\"",
 						  finfo->dobj.name);
 	}
 
@@ -11880,7 +11856,7 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
 		else if (proparallel[0] == PROPARALLEL_RESTRICTED)
 			appendPQExpBufferStr(q, " PARALLEL RESTRICTED");
 		else if (proparallel[0] != PROPARALLEL_UNSAFE)
-			exit_horribly(NULL, "unrecognized proparallel value for function \"%s\"\n",
+			fatal("unrecognized proparallel value for function \"%s\"",
 						  finfo->dobj.name);
 	}
 
@@ -12014,7 +11990,7 @@ dumpCast(Archive *fout, CastInfo *cast)
 	{
 		funcInfo = findFuncByOid(cast->castfunc);
 		if (funcInfo == NULL)
-			exit_horribly(NULL, "could not find function definition for function with OID %u\n",
+			fatal("could not find function definition for function with OID %u",
 						  cast->castfunc);
 	}
 
@@ -12053,10 +12029,10 @@ dumpCast(Archive *fout, CastInfo *cast)
 				free(fsig);
 			}
 			else
-				write_msg(NULL, "WARNING: bogus value in pg_cast.castfunc or pg_cast.castmethod field\n");
+				pg_log_warning("bogus value in pg_cast.castfunc or pg_cast.castmethod field");
 			break;
 		default:
-			write_msg(NULL, "WARNING: bogus value in pg_cast.castmethod field\n");
+			pg_log_warning("bogus value in pg_cast.castmethod field");
 	}
 
 	if (cast->castcontext == 'a')
@@ -12124,14 +12100,14 @@ dumpTransform(Archive *fout, TransformInfo *transform)
 	{
 		fromsqlFuncInfo = findFuncByOid(transform->trffromsql);
 		if (fromsqlFuncInfo == NULL)
-			exit_horribly(NULL, "could not find function definition for function with OID %u\n",
+			fatal("could not find function definition for function with OID %u",
 						  transform->trffromsql);
 	}
 	if (OidIsValid(transform->trftosql))
 	{
 		tosqlFuncInfo = findFuncByOid(transform->trftosql);
 		if (tosqlFuncInfo == NULL)
-			exit_horribly(NULL, "could not find function definition for function with OID %u\n",
+			fatal("could not find function definition for function with OID %u",
 						  transform->trftosql);
 	}
 
@@ -12150,7 +12126,7 @@ dumpTransform(Archive *fout, TransformInfo *transform)
 					  transformType, lanname);
 
 	if (!transform->trffromsql && !transform->trftosql)
-		write_msg(NULL, "WARNING: bogus transform definition, at least one of trffromsql and trftosql should be nonzero\n");
+		pg_log_warning("bogus transform definition, at least one of trffromsql and trftosql should be nonzero");
 
 	if (transform->trffromsql)
 	{
@@ -12167,7 +12143,7 @@ dumpTransform(Archive *fout, TransformInfo *transform)
 			free(fsig);
 		}
 		else
-			write_msg(NULL, "WARNING: bogus value in pg_transform.trffromsql field\n");
+			pg_log_warning("bogus value in pg_transform.trffromsql field");
 	}
 
 	if (transform->trftosql)
@@ -12188,7 +12164,7 @@ dumpTransform(Archive *fout, TransformInfo *transform)
 			free(fsig);
 		}
 		else
-			write_msg(NULL, "WARNING: bogus value in pg_transform.trftosql field\n");
+			pg_log_warning("bogus value in pg_transform.trftosql field");
 	}
 
 	appendPQExpBuffer(defqry, ");\n");
@@ -12504,7 +12480,7 @@ getFormattedOperatorName(Archive *fout, const char *oproid)
 	oprInfo = findOprByOid(atooid(oproid));
 	if (oprInfo == NULL)
 	{
-		write_msg(NULL, "WARNING: could not find operator with OID %s\n",
+		pg_log_warning("could not find operator with OID %s",
 				  oproid);
 		return NULL;
 	}
@@ -12569,7 +12545,7 @@ dumpAccessMethod(Archive *fout, AccessMethodInfo *aminfo)
 			appendPQExpBuffer(q, "TYPE INDEX ");
 			break;
 		default:
-			write_msg(NULL, "WARNING: invalid type \"%c\" of access method \"%s\"\n",
+			pg_log_warning("invalid type \"%c\" of access method \"%s\"",
 					  aminfo->amtype, qamname);
 			destroyPQExpBuffer(q);
 			destroyPQExpBuffer(delq);
@@ -13320,8 +13296,7 @@ dumpCollation(Archive *fout, CollInfo *collinfo)
 		/* to allow dumping pg_catalog; not accepted on input */
 		appendPQExpBufferStr(q, "default");
 	else
-		exit_horribly(NULL,
-					  "unrecognized collation provider: %s\n",
+		fatal("unrecognized collation provider: %s\n",
 					  collprovider);
 
 	if (strcmp(collcollate, collctype) == 0)
@@ -13792,7 +13767,7 @@ dumpAgg(Archive *fout, AggInfo *agginfo)
 
 	if (!convertok)
 	{
-		write_msg(NULL, "WARNING: aggregate function %s could not be dumped correctly for this database version; ignored\n",
+		pg_log_warning("aggregate function %s could not be dumped correctly for this database version; ignored",
 				  aggsig);
 
 		if (aggfullsig)
@@ -13847,7 +13822,7 @@ dumpAgg(Archive *fout, AggInfo *agginfo)
 					appendPQExpBufferStr(details, ",\n    FINALFUNC_MODIFY = READ_WRITE");
 					break;
 				default:
-					exit_horribly(NULL, "unrecognized aggfinalmodify value for aggregate \"%s\"\n",
+					fatal("unrecognized aggfinalmodify value for aggregate \"%s\"",
 								  agginfo->aggfn.dobj.name);
 					break;
 			}
@@ -13903,7 +13878,7 @@ dumpAgg(Archive *fout, AggInfo *agginfo)
 					appendPQExpBufferStr(details, ",\n    MFINALFUNC_MODIFY = READ_WRITE");
 					break;
 				default:
-					exit_horribly(NULL, "unrecognized aggmfinalmodify value for aggregate \"%s\"\n",
+					fatal("unrecognized aggmfinalmodify value for aggregate \"%s\"",
 								  agginfo->aggfn.dobj.name);
 					break;
 			}
@@ -13928,7 +13903,7 @@ dumpAgg(Archive *fout, AggInfo *agginfo)
 		else if (proparallel[0] == PROPARALLEL_RESTRICTED)
 			appendPQExpBufferStr(details, ",\n    PARALLEL = restricted");
 		else if (proparallel[0] != PROPARALLEL_UNSAFE)
-			exit_horribly(NULL, "unrecognized proparallel value for function \"%s\"\n",
+			fatal("unrecognized proparallel value for function \"%s\"",
 						  agginfo->aggfn.dobj.name);
 	}
 
@@ -14637,8 +14612,7 @@ dumpDefaultACL(Archive *fout, DefaultACLInfo *daclinfo)
 			break;
 		default:
 			/* shouldn't get here */
-			exit_horribly(NULL,
-						  "unrecognized object type in default privileges: %d\n",
+			fatal("unrecognized object type in default privileges: %d",
 						  (int) daclinfo->defaclobjtype);
 			type = "";			/* keep compiler quiet */
 	}
@@ -14656,7 +14630,7 @@ dumpDefaultACL(Archive *fout, DefaultACLInfo *daclinfo)
 								 daclinfo->defaclrole,
 								 fout->remoteVersion,
 								 q))
-		exit_horribly(NULL, "could not parse default ACL list (%s)\n",
+		fatal("could not parse default ACL list (%s)",
 					  daclinfo->defaclacl);
 
 	if (daclinfo->dobj.dump & DUMP_COMPONENT_ACL)
@@ -14737,8 +14711,7 @@ dumpACL(Archive *fout, CatalogId objCatId, DumpId objDumpId,
 		if (!buildACLCommands(name, subname, nspname, type,
 							  initacls, initracls, owner,
 							  "", fout->remoteVersion, sql))
-			exit_horribly(NULL,
-						  "could not parse initial GRANT ACL list (%s) or initial REVOKE ACL list (%s) for object \"%s\" (%s)\n",
+			fatal("could not parse initial GRANT ACL list (%s) or initial REVOKE ACL list (%s) for object \"%s\" (%s)",
 						  initacls, initracls, name, type);
 		appendPQExpBuffer(sql, "SELECT pg_catalog.binary_upgrade_set_record_init_privs(false);\n");
 	}
@@ -14746,8 +14719,7 @@ dumpACL(Archive *fout, CatalogId objCatId, DumpId objDumpId,
 	if (!buildACLCommands(name, subname, nspname, type,
 						  acls, racls, owner,
 						  "", fout->remoteVersion, sql))
-		exit_horribly(NULL,
-					  "could not parse GRANT ACL list (%s) or REVOKE ACL list (%s) for object \"%s\" (%s)\n",
+		fatal("could not parse GRANT ACL list (%s) or REVOKE ACL list (%s) for object \"%s\" (%s)",
 					  acls, racls, name, type);
 
 	if (sql->len > 0)
@@ -15241,17 +15213,17 @@ createViewAsClause(Archive *fout, TableInfo *tbinfo)
 	if (PQntuples(res) != 1)
 	{
 		if (PQntuples(res) < 1)
-			exit_horribly(NULL, "query to obtain definition of view \"%s\" returned no data\n",
+			fatal("query to obtain definition of view \"%s\" returned no data",
 						  tbinfo->dobj.name);
 		else
-			exit_horribly(NULL, "query to obtain definition of view \"%s\" returned more than one definition\n",
+			fatal("query to obtain definition of view \"%s\" returned more than one definition",
 						  tbinfo->dobj.name);
 	}
 
 	len = PQgetlength(res, 0, 0);
 
 	if (len == 0)
-		exit_horribly(NULL, "definition of view \"%s\" appears to be empty (length zero)\n",
+		fatal("definition of view \"%s\" appears to be empty (length zero)",
 					  tbinfo->dobj.name);
 
 	/* Strip off the trailing semicolon so that other things may follow. */
@@ -15333,8 +15305,7 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo)
 
 
 	if (tbinfo->hasoids)
-		write_msg(NULL,
-				  "WARNING: WITH OIDS is not supported anymore (table \"%s\")\n",
+		pg_log_warning("WITH OIDS is not supported anymore (table \"%s\")",
 				  qrelname);
 
 	if (dopt->binary_upgrade)
@@ -15461,7 +15432,7 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo)
 			 * parent.
 			 */
 			if (tbinfo->numParents != 1)
-				exit_horribly(NULL, "invalid number of parents %d for table \"%s\"\n",
+				fatal("invalid number of parents %d for table \"%s\"",
 							  tbinfo->numParents, tbinfo->dobj.name);
 
 			appendPQExpBuffer(q, " PARTITION OF %s",
@@ -16134,7 +16105,7 @@ getAttrName(int attrnum, TableInfo *tblInfo)
 		case TableOidAttributeNumber:
 			return "tableoid";
 	}
-	exit_horribly(NULL, "invalid column number %d for table \"%s\"\n",
+	fatal("invalid column number %d for table \"%s\"",
 				  attrnum, tblInfo->dobj.name);
 	return NULL;				/* keep compiler quiet */
 }
@@ -16400,7 +16371,7 @@ dumpConstraint(Archive *fout, ConstraintInfo *coninfo)
 		indxinfo = (IndxInfo *) findObjectByDumpId(coninfo->conindex);
 
 		if (indxinfo == NULL)
-			exit_horribly(NULL, "missing index for constraint \"%s\"\n",
+			fatal("missing index for constraint \"%s\"",
 						  coninfo->dobj.name);
 
 		if (dopt->binary_upgrade)
@@ -16623,7 +16594,7 @@ dumpConstraint(Archive *fout, ConstraintInfo *coninfo)
 	}
 	else
 	{
-		exit_horribly(NULL, "unrecognized constraint type: %c\n",
+		fatal("unrecognized constraint type: %c",
 					  coninfo->contype);
 	}
 
@@ -16755,8 +16726,8 @@ dumpSequence(Archive *fout, TableInfo *tbinfo)
 
 	if (PQntuples(res) != 1)
 	{
-		write_msg(NULL, ngettext("query to get data of sequence \"%s\" returned %d row (expected 1)\n",
-								 "query to get data of sequence \"%s\" returned %d rows (expected 1)\n",
+		pg_log_error(ngettext("query to get data of sequence \"%s\" returned %d row (expected 1)",
+							  "query to get data of sequence \"%s\" returned %d rows (expected 1)",
 								 PQntuples(res)),
 				  tbinfo->dobj.name, PQntuples(res));
 		exit_nicely(1);
@@ -16789,7 +16760,7 @@ dumpSequence(Archive *fout, TableInfo *tbinfo)
 	}
 	else
 	{
-		exit_horribly(NULL, "unrecognized sequence type: %s\n", seqtype);
+		fatal("unrecognized sequence type: %s", seqtype);
 		default_minv = default_maxv = 0;	/* keep compiler quiet */
 	}
 
@@ -16911,7 +16882,7 @@ dumpSequence(Archive *fout, TableInfo *tbinfo)
 		TableInfo  *owning_tab = findTableByOid(tbinfo->owning_tab);
 
 		if (owning_tab == NULL)
-			exit_horribly(NULL, "failed sanity check, parent table with OID %u of sequence with OID %u not found\n",
+			fatal("failed sanity check, parent table with OID %u of sequence with OID %u not found",
 						  tbinfo->owning_tab, tbinfo->dobj.catId.oid);
 
 		if (owning_tab->dobj.dump & DUMP_COMPONENT_DEFINITION)
@@ -16976,8 +16947,8 @@ dumpSequenceData(Archive *fout, TableDataInfo *tdinfo)
 
 	if (PQntuples(res) != 1)
 	{
-		write_msg(NULL, ngettext("query to get data of sequence \"%s\" returned %d row (expected 1)\n",
-								 "query to get data of sequence \"%s\" returned %d rows (expected 1)\n",
+		pg_log_error(ngettext("query to get data of sequence \"%s\" returned %d row (expected 1)",
+							  "query to get data of sequence \"%s\" returned %d rows (expected 1)",
 								 PQntuples(res)),
 				  tbinfo->dobj.name, PQntuples(res));
 		exit_nicely(1);
@@ -17072,7 +17043,7 @@ dumpTrigger(Archive *fout, TriggerInfo *tginfo)
 			appendPQExpBufferStr(query, "INSTEAD OF");
 		else
 		{
-			write_msg(NULL, "unexpected tgtype value: %d\n", tginfo->tgtype);
+			pg_log_error("unexpected tgtype value: %d", tginfo->tgtype);
 			exit_nicely(1);
 		}
 
@@ -17146,7 +17117,7 @@ dumpTrigger(Archive *fout, TriggerInfo *tginfo)
 			if (p + tlen >= tgargs + lentgargs)
 			{
 				/* hm, not found before end of bytea value... */
-				write_msg(NULL, "invalid argument string (%s) for trigger \"%s\" on table \"%s\"\n",
+				pg_log_error("invalid argument string (%s) for trigger \"%s\" on table \"%s\"",
 						  tginfo->tgargs,
 						  tginfo->dobj.name,
 						  tbinfo->dobj.name);
@@ -17376,7 +17347,7 @@ dumpRule(Archive *fout, RuleInfo *rinfo)
 
 		if (PQntuples(res) != 1)
 		{
-			write_msg(NULL, "query to get rule \"%s\" for table \"%s\" failed: wrong number of rows returned\n",
+			pg_log_error("query to get rule \"%s\" for table \"%s\" failed: wrong number of rows returned",
 					  rinfo->dobj.name, tbinfo->dobj.name);
 			exit_nicely(1);
 		}
@@ -17539,7 +17510,7 @@ getExtensionMembership(Archive *fout, ExtensionInfo extinfo[],
 		if (ext == NULL)
 		{
 			/* shouldn't happen */
-			fprintf(stderr, "could not find referenced extension %u\n", extId);
+			pg_log_warning("could not find referenced extension %u", extId);
 			continue;
 		}
 
@@ -17751,8 +17722,7 @@ getDependencies(Archive *fout)
 	DumpableObject *dobj,
 			   *refdobj;
 
-	if (g_verbose)
-		write_msg(NULL, "reading dependency data\n");
+	pg_log_info("reading dependency data");
 
 	query = createPQExpBuffer();
 
@@ -17807,7 +17777,7 @@ getDependencies(Archive *fout)
 		if (dobj == NULL)
 		{
 #ifdef NOT_USED
-			fprintf(stderr, "no referencing object %u %u\n",
+			pg_log_warning("no referencing object %u %u",
 					objId.tableoid, objId.oid);
 #endif
 			continue;
@@ -17818,7 +17788,7 @@ getDependencies(Archive *fout)
 		if (refdobj == NULL)
 		{
 #ifdef NOT_USED
-			fprintf(stderr, "no referenced object %u %u\n",
+			pg_log_warning("no referenced object %u %u",
 					refobjId.tableoid, refobjId.oid);
 #endif
 			continue;
@@ -18183,5 +18153,5 @@ appendReloptionsArrayAH(PQExpBuffer buffer, const char *reloptions,
 	res = appendReloptionsArray(buffer, reloptions, prefix, fout->encoding,
 								fout->std_strings);
 	if (!res)
-		write_msg(NULL, "WARNING: could not parse reloptions array\n");
+		pg_log_warning("could not parse reloptions array");
 }
diff --git a/src/bin/pg_dump/pg_dump.h b/src/bin/pg_dump/pg_dump.h
index 21d2ab05b0..c546b752f8 100644
--- a/src/bin/pg_dump/pg_dump.h
+++ b/src/bin/pg_dump/pg_dump.h
@@ -637,7 +637,6 @@ typedef struct _extensionMemberId
 
 /* global decls */
 extern bool force_quotes;		/* double-quotes for identifiers flag */
-extern bool g_verbose;			/* verbose flag */
 
 /* placeholders for comment starting and ending delimiters */
 extern char g_comment_start[10];
diff --git a/src/bin/pg_dump/pg_dump_sort.c b/src/bin/pg_dump/pg_dump_sort.c
index 08005c530f..63905bd487 100644
--- a/src/bin/pg_dump/pg_dump_sort.c
+++ b/src/bin/pg_dump/pg_dump_sort.c
@@ -20,9 +20,7 @@
 #include "pg_dump.h"
 
 #include "catalog/pg_class_d.h"
-
-/* translator: this is a module name */
-static const char *modulename = gettext_noop("sorter");
+#include "fe_utils/logging.h"
 
 /*
  * Sort priority for database object types.
@@ -328,13 +326,13 @@ TopoSort(DumpableObject **objs,
 		obj = objs[i];
 		j = obj->dumpId;
 		if (j <= 0 || j > maxDumpId)
-			exit_horribly(modulename, "invalid dumpId %d\n", j);
+			fatal("invalid dumpId %d", j);
 		idMap[j] = i;
 		for (j = 0; j < obj->nDeps; j++)
 		{
 			k = obj->dependencies[j];
 			if (k <= 0 || k > maxDumpId)
-				exit_horribly(modulename, "invalid dependency %d\n", k);
+				fatal("invalid dependency %d", k);
 			beforeConstraints[k]++;
 		}
 	}
@@ -567,7 +565,7 @@ findDependencyLoops(DumpableObject **objs, int nObjs, int totObjs)
 
 	/* We'd better have fixed at least one loop */
 	if (!fixedloop)
-		exit_horribly(modulename, "could not identify dependency loop\n");
+		fatal("could not identify dependency loop");
 
 	free(workspace);
 	free(searchFailed);
@@ -1114,13 +1112,13 @@ repairDependencyLoop(DumpableObject **loop,
 	}
 	if (i >= nLoop)
 	{
-		write_msg(NULL, ngettext("NOTICE: there are circular foreign-key constraints on this table:\n",
-								 "NOTICE: there are circular foreign-key constraints among these tables:\n",
-								 nLoop));
+		pg_log_warning(ngettext("there are circular foreign-key constraints on this table:",
+								"there are circular foreign-key constraints among these tables:",
+								nLoop));
 		for (i = 0; i < nLoop; i++)
-			write_msg(NULL, "  %s\n", loop[i]->name);
-		write_msg(NULL, "You might not be able to restore the dump without using --disable-triggers or temporarily dropping the constraints.\n");
-		write_msg(NULL, "Consider using a full dump instead of a --data-only dump to avoid this problem.\n");
+			pg_log_warning("  %s", loop[i]->name);
+		pg_log_warning("You might not be able to restore the dump without using --disable-triggers or temporarily dropping the constraints.");
+		pg_log_warning("Consider using a full dump instead of a --data-only dump to avoid this problem.");
 		if (nLoop > 1)
 			removeObjectDependency(loop[0], loop[1]->dumpId);
 		else					/* must be a self-dependency */
@@ -1132,13 +1130,13 @@ repairDependencyLoop(DumpableObject **loop,
 	 * If we can't find a principled way to break the loop, complain and break
 	 * it in an arbitrary fashion.
 	 */
-	write_msg(modulename, "WARNING: could not resolve dependency loop among these items:\n");
+	pg_log_warning("could not resolve dependency loop among these items:");
 	for (i = 0; i < nLoop; i++)
 	{
 		char		buf[1024];
 
 		describeDumpableObject(loop[i], buf, sizeof(buf));
-		write_msg(modulename, "  %s\n", buf);
+		pg_log_warning("  %s", buf);
 	}
 
 	if (nLoop > 1)
diff --git a/src/bin/pg_dump/pg_dumpall.c b/src/bin/pg_dump/pg_dumpall.c
index 1d539193ca..266428fca7 100644
--- a/src/bin/pg_dump/pg_dumpall.c
+++ b/src/bin/pg_dump/pg_dumpall.c
@@ -24,6 +24,7 @@
 #include "pg_backup.h"
 #include "common/file_utils.h"
 #include "fe_utils/connect.h"
+#include "fe_utils/logging.h"
 #include "fe_utils/string_utils.h"
 
 /* version string we expect back from pg_dump */
@@ -162,7 +163,8 @@ main(int argc, char *argv[])
 	int			optindex;
 
 	set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_dump"));
-
+	pg_logging_init(argv[0]);
+	pg_logging_set_level(PG_LOG_WARNING);
 	progname = get_progname(argv[0]);
 
 	if (argc > 1)
@@ -188,18 +190,15 @@ main(int argc, char *argv[])
 			strlcpy(full_path, progname, sizeof(full_path));
 
 		if (ret == -1)
-			fprintf(stderr,
-					_("The program \"pg_dump\" is needed by %s "
-					  "but was not found in the\n"
-					  "same directory as \"%s\".\n"
-					  "Check your installation.\n"),
-					progname, full_path);
+			pg_log_error("The program \"pg_dump\" is needed by %s but was not found in the\n"
+						 "same directory as \"%s\".\n"
+						 "Check your installation.",
+						 progname, full_path);
 		else
-			fprintf(stderr,
-					_("The program \"pg_dump\" was found by \"%s\"\n"
-					  "but was not the same version as %s.\n"
-					  "Check your installation.\n"),
-					full_path, progname);
+			pg_log_error("The program \"pg_dump\" was found by \"%s\"\n"
+						 "but was not the same version as %s.\n"
+						 "Check your installation.",
+						 full_path, progname);
 		exit_nicely(1);
 	}
 
@@ -281,6 +280,7 @@ main(int argc, char *argv[])
 
 			case 'v':
 				verbose = true;
+				pg_logging_set_level(PG_LOG_INFO);
 				appendPQExpBufferStr(pgdumpopts, " -v");
 				break;
 
@@ -327,8 +327,8 @@ main(int argc, char *argv[])
 	/* Complain if any arguments remain */
 	if (optind < argc)
 	{
-		fprintf(stderr, _("%s: too many command-line arguments (first is \"%s\")\n"),
-				progname, argv[optind]);
+		pg_log_error("too many command-line arguments (first is \"%s\")",
+					 argv[optind]);
 		fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
 				progname);
 		exit_nicely(1);
@@ -337,8 +337,7 @@ main(int argc, char *argv[])
 	/* Make sure the user hasn't specified a mix of globals-only options */
 	if (globals_only && roles_only)
 	{
-		fprintf(stderr, _("%s: options -g/--globals-only and -r/--roles-only cannot be used together\n"),
-				progname);
+		pg_log_error("options -g/--globals-only and -r/--roles-only cannot be used together");
 		fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
 				progname);
 		exit_nicely(1);
@@ -346,8 +345,7 @@ main(int argc, char *argv[])
 
 	if (globals_only && tablespaces_only)
 	{
-		fprintf(stderr, _("%s: options -g/--globals-only and -t/--tablespaces-only cannot be used together\n"),
-				progname);
+		pg_log_error("options -g/--globals-only and -t/--tablespaces-only cannot be used together");
 		fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
 				progname);
 		exit_nicely(1);
@@ -355,15 +353,13 @@ main(int argc, char *argv[])
 
 	if (if_exists && !output_clean)
 	{
-		fprintf(stderr, _("%s: option --if-exists requires option -c/--clean\n"),
-				progname);
+		pg_log_error("option --if-exists requires option -c/--clean");
 		exit_nicely(1);
 	}
 
 	if (roles_only && tablespaces_only)
 	{
-		fprintf(stderr, _("%s: options -r/--roles-only and -t/--tablespaces-only cannot be used together\n"),
-				progname);
+		pg_log_error("options -r/--roles-only and -t/--tablespaces-only cannot be used together");
 		fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
 				progname);
 		exit_nicely(1);
@@ -424,8 +420,7 @@ main(int argc, char *argv[])
 
 		if (!conn)
 		{
-			fprintf(stderr, _("%s: could not connect to database \"%s\"\n"),
-					progname, pgdb);
+			pg_log_error("could not connect to database \"%s\"", pgdb);
 			exit_nicely(1);
 		}
 	}
@@ -439,9 +434,8 @@ main(int argc, char *argv[])
 
 		if (!conn)
 		{
-			fprintf(stderr, _("%s: could not connect to databases \"postgres\" or \"template1\"\n"
-							  "Please specify an alternative database.\n"),
-					progname);
+			pg_log_error("could not connect to databases \"postgres\" or \"template1\"\n"
+						 "Please specify an alternative database.");
 			fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
 					progname);
 			exit_nicely(1);
@@ -456,8 +450,8 @@ main(int argc, char *argv[])
 		OPF = fopen(filename, PG_BINARY_W);
 		if (!OPF)
 		{
-			fprintf(stderr, _("%s: could not open the output file \"%s\": %s\n"),
-					progname, filename, strerror(errno));
+			pg_log_error("could not open the output file \"%s\": %m",
+						 filename);
 			exit_nicely(1);
 		}
 	}
@@ -471,8 +465,8 @@ main(int argc, char *argv[])
 	{
 		if (PQsetClientEncoding(conn, dumpencoding) < 0)
 		{
-			fprintf(stderr, _("%s: invalid client encoding \"%s\" specified\n"),
-					progname, dumpencoding);
+			pg_log_error("invalid client encoding \"%s\" specified",
+						 dumpencoding);
 			exit_nicely(1);
 		}
 	}
@@ -578,7 +572,7 @@ main(int argc, char *argv[])
 
 		/* sync the resulting file, errors are not fatal */
 		if (dosync)
-			(void) fsync_fname(filename, false, progname);
+			(void) fsync_fname(filename, false);
 	}
 
 	exit_nicely(0);
@@ -846,8 +840,8 @@ dumpRoles(PGconn *conn)
 
 		if (strncmp(rolename, "pg_", 3) == 0)
 		{
-			fprintf(stderr, _("%s: role name starting with \"pg_\" skipped (%s)\n"),
-					progname, rolename);
+			pg_log_warning("role name starting with \"pg_\" skipped (%s)",
+						   rolename);
 			continue;
 		}
 
@@ -1228,8 +1222,8 @@ dumpTablespaces(PGconn *conn)
 							  spcacl, rspcacl,
 							  spcowner, "", server_version, buf))
 		{
-			fprintf(stderr, _("%s: could not parse ACL list (%s) for tablespace \"%s\"\n"),
-					progname, spcacl, spcname);
+			pg_log_error("could not parse ACL list (%s) for tablespace \"%s\"",
+						 spcacl, spcname);
 			PQfinish(conn);
 			exit_nicely(1);
 		}
@@ -1388,8 +1382,7 @@ dumpDatabases(PGconn *conn)
 		if (strcmp(dbname, "template0") == 0)
 			continue;
 
-		if (verbose)
-			fprintf(stderr, _("%s: dumping database \"%s\"...\n"), progname, dbname);
+		pg_log_info("dumping database \"%s\"...", dbname);
 
 		/*
 		 * We assume that "template1" and "postgres" already exist in the
@@ -1419,7 +1412,7 @@ dumpDatabases(PGconn *conn)
 		ret = runPgDump(dbname, create_opts);
 		if (ret != 0)
 		{
-			fprintf(stderr, _("%s: pg_dump failed on database \"%s\", exiting\n"), progname, dbname);
+			pg_log_error("pg_dump failed on database \"%s\", exiting", dbname);
 			exit_nicely(1);
 		}
 
@@ -1428,8 +1421,8 @@ dumpDatabases(PGconn *conn)
 			OPF = fopen(filename, PG_BINARY_A);
 			if (!OPF)
 			{
-				fprintf(stderr, _("%s: could not re-open the output file \"%s\": %s\n"),
-						progname, filename, strerror(errno));
+				pg_log_error("could not re-open the output file \"%s\": %m",
+							 filename);
 				exit_nicely(1);
 			}
 		}
@@ -1472,8 +1465,7 @@ runPgDump(const char *dbname, const char *create_opts)
 
 	appendShellString(cmd, connstrbuf->data);
 
-	if (verbose)
-		fprintf(stderr, _("%s: running \"%s\"\n"), progname, cmd->data);
+	pg_log_info("running \"%s\"", cmd->data);
 
 	fflush(stdout);
 	fflush(stderr);
@@ -1573,7 +1565,7 @@ connectDatabase(const char *dbname, const char *connection_string,
 			conn_opts = PQconninfoParse(connection_string, &err_msg);
 			if (conn_opts == NULL)
 			{
-				fprintf(stderr, "%s: %s", progname, err_msg);
+				pg_log_error("%s", err_msg);
 				exit_nicely(1);
 			}
 
@@ -1643,8 +1635,7 @@ connectDatabase(const char *dbname, const char *connection_string,
 
 		if (!conn)
 		{
-			fprintf(stderr, _("%s: could not connect to database \"%s\"\n"),
-					progname, dbname);
+			pg_log_error("could not connect to database \"%s\"", dbname);
 			exit_nicely(1);
 		}
 
@@ -1665,9 +1656,8 @@ connectDatabase(const char *dbname, const char *connection_string,
 	{
 		if (fail_on_error)
 		{
-			fprintf(stderr,
-					_("%s: could not connect to database \"%s\": %s"),
-					progname, dbname, PQerrorMessage(conn));
+			pg_log_error("could not connect to database \"%s\": %s",
+						 dbname, PQerrorMessage(conn));
 			exit_nicely(1);
 		}
 		else
@@ -1696,14 +1686,14 @@ connectDatabase(const char *dbname, const char *connection_string,
 	remoteversion_str = PQparameterStatus(conn, "server_version");
 	if (!remoteversion_str)
 	{
-		fprintf(stderr, _("%s: could not get server version\n"), progname);
+		pg_log_error("could not get server version");
 		exit_nicely(1);
 	}
 	server_version = PQserverVersion(conn);
 	if (server_version == 0)
 	{
-		fprintf(stderr, _("%s: could not parse server version \"%s\"\n"),
-				progname, remoteversion_str);
+		pg_log_error("could not parse server version \"%s\"",
+					 remoteversion_str);
 		exit_nicely(1);
 	}
 
@@ -1717,9 +1707,9 @@ connectDatabase(const char *dbname, const char *connection_string,
 		&& (server_version < 80000 ||
 			(server_version / 100) > (my_version / 100)))
 	{
-		fprintf(stderr, _("server version: %s; %s version: %s\n"),
-				remoteversion_str, progname, PG_VERSION);
-		fprintf(stderr, _("aborting because of server version mismatch\n"));
+		pg_log_error("server version: %s; %s version: %s",
+					 remoteversion_str, progname, PG_VERSION);
+		pg_log_error("aborting because of server version mismatch");
 		exit_nicely(1);
 	}
 
@@ -1774,17 +1764,14 @@ executeQuery(PGconn *conn, const char *query)
 {
 	PGresult   *res;
 
-	if (verbose)
-		fprintf(stderr, _("%s: executing %s\n"), progname, query);
+	pg_log_info("executing %s", query);
 
 	res = PQexec(conn, query);
 	if (!res ||
 		PQresultStatus(res) != PGRES_TUPLES_OK)
 	{
-		fprintf(stderr, _("%s: query failed: %s"),
-				progname, PQerrorMessage(conn));
-		fprintf(stderr, _("%s: query was: %s\n"),
-				progname, query);
+		pg_log_error("query failed: %s", PQerrorMessage(conn));
+		pg_log_error("query was: %s", query);
 		PQfinish(conn);
 		exit_nicely(1);
 	}
@@ -1800,17 +1787,14 @@ executeCommand(PGconn *conn, const char *query)
 {
 	PGresult   *res;
 
-	if (verbose)
-		fprintf(stderr, _("%s: executing %s\n"), progname, query);
+	pg_log_info("executing %s", query);
 
 	res = PQexec(conn, query);
 	if (!res ||
 		PQresultStatus(res) != PGRES_COMMAND_OK)
 	{
-		fprintf(stderr, _("%s: query failed: %s"),
-				progname, PQerrorMessage(conn));
-		fprintf(stderr, _("%s: query was: %s\n"),
-				progname, query);
+		pg_log_error("query failed: %s", PQerrorMessage(conn));
+		pg_log_error("query was: %s", query);
 		PQfinish(conn);
 		exit_nicely(1);
 	}
diff --git a/src/bin/pg_dump/pg_restore.c b/src/bin/pg_dump/pg_restore.c
index 44012ff44d..96c1d41d01 100644
--- a/src/bin/pg_dump/pg_restore.c
+++ b/src/bin/pg_dump/pg_restore.c
@@ -51,6 +51,8 @@
 #include "parallel.h"
 #include "pg_backup_utils.h"
 
+#include "fe_utils/logging.h"
+
 
 static void usage(const char *progname);
 
@@ -129,6 +131,7 @@ main(int argc, char **argv)
 	};
 
 	set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_dump"));
+	pg_logging_init(argv[0]);
 
 	init_parallel_dump_utils();
 
@@ -296,8 +299,8 @@ main(int argc, char **argv)
 	/* Complain if any arguments remain */
 	if (optind < argc)
 	{
-		fprintf(stderr, _("%s: too many command-line arguments (first is \"%s\")\n"),
-				progname, argv[optind]);
+		pg_log_error("too many command-line arguments (first is \"%s\")",
+					 argv[optind]);
 		fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
 				progname);
 		exit_nicely(1);
@@ -308,8 +311,7 @@ main(int argc, char **argv)
 	{
 		if (opts->filename)
 		{
-			fprintf(stderr, _("%s: options -d/--dbname and -f/--file cannot be used together\n"),
-					progname);
+			pg_log_error("options -d/--dbname and -f/--file cannot be used together");
 			fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
 					progname);
 			exit_nicely(1);
@@ -319,15 +321,13 @@ main(int argc, char **argv)
 
 	if (opts->dataOnly && opts->schemaOnly)
 	{
-		fprintf(stderr, _("%s: options -s/--schema-only and -a/--data-only cannot be used together\n"),
-				progname);
+		pg_log_error("options -s/--schema-only and -a/--data-only cannot be used together");
 		exit_nicely(1);
 	}
 
 	if (opts->dataOnly && opts->dropSchema)
 	{
-		fprintf(stderr, _("%s: options -c/--clean and -a/--data-only cannot be used together\n"),
-				progname);
+		pg_log_error("options -c/--clean and -a/--data-only cannot be used together");
 		exit_nicely(1);
 	}
 
@@ -337,14 +337,13 @@ main(int argc, char **argv)
 	 */
 	if (opts->createDB && opts->single_txn)
 	{
-		fprintf(stderr, _("%s: options -C/--create and -1/--single-transaction cannot be used together\n"),
-				progname);
+		pg_log_error("options -C/--create and -1/--single-transaction cannot be used together");
 		exit_nicely(1);
 	}
 
 	if (numWorkers <= 0)
 	{
-		fprintf(stderr, _("%s: invalid number of parallel jobs\n"), progname);
+		pg_log_error("invalid number of parallel jobs");
 		exit(1);
 	}
 
@@ -352,8 +351,8 @@ main(int argc, char **argv)
 #ifdef WIN32
 	if (numWorkers > MAXIMUM_WAIT_OBJECTS)
 	{
-		fprintf(stderr, _("%s: maximum number of parallel jobs is %d\n"),
-				progname, MAXIMUM_WAIT_OBJECTS);
+		pg_log_error("maximum number of parallel jobs is %d",
+					 MAXIMUM_WAIT_OBJECTS);
 		exit(1);
 	}
 #endif
@@ -361,8 +360,7 @@ main(int argc, char **argv)
 	/* Can't do single-txn mode with multiple connections */
 	if (opts->single_txn && numWorkers > 1)
 	{
-		fprintf(stderr, _("%s: cannot specify both --single-transaction and multiple jobs\n"),
-				progname);
+		pg_log_error("cannot specify both --single-transaction and multiple jobs");
 		exit_nicely(1);
 	}
 
@@ -378,8 +376,7 @@ main(int argc, char **argv)
 
 	if (if_exists && !opts->dropSchema)
 	{
-		fprintf(stderr, _("%s: option --if-exists requires option -c/--clean\n"),
-				progname);
+		pg_log_error("option --if-exists requires option -c/--clean");
 		exit_nicely(1);
 	}
 	opts->if_exists = if_exists;
@@ -405,7 +402,7 @@ main(int argc, char **argv)
 				break;
 
 			default:
-				write_msg(NULL, "unrecognized archive format \"%s\"; please specify \"c\", \"d\", or \"t\"\n",
+				pg_log_error("unrecognized archive format \"%s\"; please specify \"c\", \"d\", or \"t\"",
 						  opts->formatName);
 				exit_nicely(1);
 		}
@@ -445,8 +442,7 @@ main(int argc, char **argv)
 
 	/* done, print a summary of ignored errors */
 	if (AH->n_errors)
-		fprintf(stderr, _("WARNING: errors ignored on restore: %d\n"),
-				AH->n_errors);
+		pg_log_warning("errors ignored on restore: %d", AH->n_errors);
 
 	/* AH may be freed in CloseArchive? */
 	exit_code = AH->n_errors ? 1 : 0;
diff --git a/src/bin/pg_dump/t/001_basic.pl b/src/bin/pg_dump/t/001_basic.pl
index a875d540b8..87d25099ac 100644
--- a/src/bin/pg_dump/t/001_basic.pl
+++ b/src/bin/pg_dump/t/001_basic.pl
@@ -30,123 +30,123 @@
 
 command_fails_like(
 	[ 'pg_dump', 'qqq', 'abc' ],
-	qr/\Qpg_dump: too many command-line arguments (first is "abc")\E/,
-	'pg_dump: too many command-line arguments (first is "asd")');
+	qr/\Qpg_dump: error: too many command-line arguments (first is "abc")\E/,
+	'pg_dump: too many command-line arguments');
 
 command_fails_like(
 	[ 'pg_restore', 'qqq', 'abc' ],
-	qr/\Qpg_restore: too many command-line arguments (first is "abc")\E/,
-	'pg_restore too many command-line arguments (first is "abc")');
+	qr/\Qpg_restore: error: too many command-line arguments (first is "abc")\E/,
+	'pg_restore: too many command-line arguments');
 
 command_fails_like(
 	[ 'pg_dumpall', 'qqq', 'abc' ],
-	qr/\Qpg_dumpall: too many command-line arguments (first is "qqq")\E/,
-	'pg_dumpall: too many command-line arguments (first is "qqq")');
+	qr/\Qpg_dumpall: error: too many command-line arguments (first is "qqq")\E/,
+	'pg_dumpall: too many command-line arguments');
 
 command_fails_like(
 	[ 'pg_dump', '-s', '-a' ],
-	qr/\Qpg_dump: options -s\/--schema-only and -a\/--data-only cannot be used together\E/,
+	qr/\Qpg_dump: error: options -s\/--schema-only and -a\/--data-only cannot be used together\E/,
 	'pg_dump: options -s/--schema-only and -a/--data-only cannot be used together'
 );
 
 command_fails_like(
 	[ 'pg_restore', '-s', '-a' ],
-	qr/\Qpg_restore: options -s\/--schema-only and -a\/--data-only cannot be used together\E/,
+	qr/\Qpg_restore: error: options -s\/--schema-only and -a\/--data-only cannot be used together\E/,
 	'pg_restore: options -s/--schema-only and -a/--data-only cannot be used together'
 );
 
 command_fails_like(
 	[ 'pg_restore', '-d', 'xxx', '-f', 'xxx' ],
-	qr/\Qpg_restore: options -d\/--dbname and -f\/--file cannot be used together\E/,
+	qr/\Qpg_restore: error: options -d\/--dbname and -f\/--file cannot be used together\E/,
 	'pg_restore: options -d/--dbname and -f/--file cannot be used together');
 
 command_fails_like(
 	[ 'pg_dump', '-c', '-a' ],
-	qr/\Qpg_dump: options -c\/--clean and -a\/--data-only cannot be used together\E/,
+	qr/\Qpg_dump: error: options -c\/--clean and -a\/--data-only cannot be used together\E/,
 	'pg_dump: options -c/--clean and -a/--data-only cannot be used together');
 
 command_fails_like(
 	[ 'pg_restore', '-c', '-a' ],
-	qr/\Qpg_restore: options -c\/--clean and -a\/--data-only cannot be used together\E/,
+	qr/\Qpg_restore: error: options -c\/--clean and -a\/--data-only cannot be used together\E/,
 	'pg_restore: options -c/--clean and -a/--data-only cannot be used together'
 );
 
 command_fails_like(
 	[ 'pg_dump', '--if-exists' ],
-	qr/\Qpg_dump: option --if-exists requires option -c\/--clean\E/,
+	qr/\Qpg_dump: error: option --if-exists requires option -c\/--clean\E/,
 	'pg_dump: option --if-exists requires option -c/--clean');
 
 command_fails_like(
 	[ 'pg_dump', '-j3' ],
-	qr/\Qpg_dump: parallel backup only supported by the directory format\E/,
+	qr/\Qpg_dump: error: parallel backup only supported by the directory format\E/,
 	'pg_dump: parallel backup only supported by the directory format');
 
 command_fails_like(
 	[ 'pg_dump', '-j', '-1' ],
-	qr/\Qpg_dump: invalid number of parallel jobs\E/,
+	qr/\Qpg_dump: error: invalid number of parallel jobs\E/,
 	'pg_dump: invalid number of parallel jobs');
 
 command_fails_like(
 	[ 'pg_dump', '-F', 'garbage' ],
-	qr/\Qpg_dump: invalid output format\E/,
+	qr/\Qpg_dump: error: invalid output format\E/,
 	'pg_dump: invalid output format');
 
 command_fails_like(
 	[ 'pg_restore', '-j', '-1' ],
-	qr/\Qpg_restore: invalid number of parallel jobs\E/,
+	qr/\Qpg_restore: error: invalid number of parallel jobs\E/,
 	'pg_restore: invalid number of parallel jobs');
 
 command_fails_like(
 	[ 'pg_restore', '--single-transaction', '-j3' ],
-	qr/\Qpg_restore: cannot specify both --single-transaction and multiple jobs\E/,
+	qr/\Qpg_restore: error: cannot specify both --single-transaction and multiple jobs\E/,
 	'pg_restore: cannot specify both --single-transaction and multiple jobs');
 
 command_fails_like(
 	[ 'pg_dump', '-Z', '-1' ],
-	qr/\Qpg_dump: compression level must be in range 0..9\E/,
+	qr/\Qpg_dump: error: compression level must be in range 0..9\E/,
 	'pg_dump: compression level must be in range 0..9');
 
 command_fails_like(
 	[ 'pg_restore', '--if-exists' ],
-	qr/\Qpg_restore: option --if-exists requires option -c\/--clean\E/,
+	qr/\Qpg_restore: error: option --if-exists requires option -c\/--clean\E/,
 	'pg_restore: option --if-exists requires option -c/--clean');
 
 command_fails_like(
 	[ 'pg_restore', '-F', 'garbage' ],
-	qr/\Qpg_restore: unrecognized archive format "garbage";\E/,
+	qr/\Qpg_restore: error: unrecognized archive format "garbage";\E/,
 	'pg_dump: unrecognized archive format');
 
 command_fails_like(
 	[ 'pg_dump', '--on-conflict-do-nothing' ],
-	qr/\Qpg_dump: option --on-conflict-do-nothing requires option --inserts or --column-inserts\E/,
+	qr/\Qpg_dump: error: option --on-conflict-do-nothing requires option --inserts or --column-inserts\E/,
 	'pg_dump: option --on-conflict-do-nothing requires option --inserts or --column-inserts');
 
 # pg_dumpall command-line argument checks
 command_fails_like(
 	[ 'pg_dumpall', '-g', '-r' ],
-	qr/\Qpg_dumpall: options -g\/--globals-only and -r\/--roles-only cannot be used together\E/,
+	qr/\Qpg_dumpall: error: options -g\/--globals-only and -r\/--roles-only cannot be used together\E/,
 	'pg_dumpall: options -g/--globals-only and -r/--roles-only cannot be used together'
 );
 
 command_fails_like(
 	[ 'pg_dumpall', '-g', '-t' ],
-	qr/\Qpg_dumpall: options -g\/--globals-only and -t\/--tablespaces-only cannot be used together\E/,
+	qr/\Qpg_dumpall: error: options -g\/--globals-only and -t\/--tablespaces-only cannot be used together\E/,
 	'pg_dumpall: options -g/--globals-only and -t/--tablespaces-only cannot be used together'
 );
 
 command_fails_like(
 	[ 'pg_dumpall', '-r', '-t' ],
-	qr/\Qpg_dumpall: options -r\/--roles-only and -t\/--tablespaces-only cannot be used together\E/,
+	qr/\Qpg_dumpall: error: options -r\/--roles-only and -t\/--tablespaces-only cannot be used together\E/,
 	'pg_dumpall: options -r/--roles-only and -t/--tablespaces-only cannot be used together'
 );
 
 command_fails_like(
 	[ 'pg_dumpall', '--if-exists' ],
-	qr/\Qpg_dumpall: option --if-exists requires option -c\/--clean\E/,
+	qr/\Qpg_dumpall: error: option --if-exists requires option -c\/--clean\E/,
 	'pg_dumpall: option --if-exists requires option -c/--clean');
 
 command_fails_like(
 	[ 'pg_restore', '-C', '-1' ],
-	qr/\Qpg_restore: options -C\/--create and -1\/--single-transaction cannot be used together\E/,
+	qr/\Qpg_restore: error: options -C\/--create and -1\/--single-transaction cannot be used together\E/,
 	'pg_restore: options -C\/--create and -1\/--single-transaction cannot be used together'
 );
diff --git a/src/bin/pg_dump/t/002_pg_dump.pl b/src/bin/pg_dump/t/002_pg_dump.pl
index 245fcbf5ce..a9493eccc4 100644
--- a/src/bin/pg_dump/t/002_pg_dump.pl
+++ b/src/bin/pg_dump/t/002_pg_dump.pl
@@ -3201,8 +3201,8 @@
 
 command_fails_like(
 	[ 'pg_dump', '-p', "$port", 'qqq' ],
-	qr/\Qpg_dump: [archiver (db)] connection to database "qqq" failed: FATAL:  database "qqq" does not exist\E/,
-	'pg_dump: [archiver (db)] connection to database "qqq" failed: FATAL:  database "qqq" does not exist'
+	qr/\Qpg_dump: error: connection to database "qqq" failed: FATAL:  database "qqq" does not exist\E/,
+	'pg_dump: error: connection to database "qqq" failed: FATAL:  database "qqq" does not exist'
 );
 
 #########################################
@@ -3210,30 +3210,30 @@
 
 command_fails_like(
 	[ 'pg_dump', '-p', "$port", '--role=regress_dump_test_role' ],
-	qr/\Qpg_dump: [archiver (db)] query failed: ERROR:  permission denied for\E/,
-	'pg_dump: [archiver (db)] query failed: ERROR:  permission denied for');
+	qr/\Qpg_dump: error: query failed: ERROR:  permission denied for\E/,
+	'pg_dump: error: query failed: ERROR:  permission denied for');
 
 #########################################
 # Test dumping a non-existent schema, table, and patterns with --strict-names
 
 command_fails_like(
 	[ 'pg_dump', '-p', "$port", '-n', 'nonexistant' ],
-	qr/\Qpg_dump: no matching schemas were found\E/,
+	qr/\Qpg_dump: error: no matching schemas were found\E/,
 	'pg_dump: no matching schemas were found');
 
 command_fails_like(
 	[ 'pg_dump', '-p', "$port", '-t', 'nonexistant' ],
-	qr/\Qpg_dump: no matching tables were found\E/,
+	qr/\Qpg_dump: error: no matching tables were found\E/,
 	'pg_dump: no matching tables were found');
 
 command_fails_like(
 	[ 'pg_dump', '-p', "$port", '--strict-names', '-n', 'nonexistant*' ],
-	qr/\Qpg_dump: no matching schemas were found for pattern\E/,
+	qr/\Qpg_dump: error: no matching schemas were found for pattern\E/,
 	'pg_dump: no matching schemas were found for pattern');
 
 command_fails_like(
 	[ 'pg_dump', '-p', "$port", '--strict-names', '-t', 'nonexistant*' ],
-	qr/\Qpg_dump: no matching tables were found for pattern\E/,
+	qr/\Qpg_dump: error: no matching tables were found for pattern\E/,
 	'pg_dump: no matching tables were found for pattern');
 
 #########################################
diff --git a/src/bin/pg_resetwal/Makefile b/src/bin/pg_resetwal/Makefile
index 2a3835691f..09ede1efd2 100644
--- a/src/bin/pg_resetwal/Makefile
+++ b/src/bin/pg_resetwal/Makefile
@@ -15,11 +15,13 @@ subdir = src/bin/pg_resetwal
 top_builddir = ../../..
 include $(top_builddir)/src/Makefile.global
 
+LDFLAGS_INTERNAL += -L$(top_builddir)/src/fe_utils -lpgfeutils
+
 OBJS= pg_resetwal.o $(WIN32RES)
 
 all: pg_resetwal
 
-pg_resetwal: $(OBJS) | submake-libpgport
+pg_resetwal: $(OBJS) | submake-libpgport submake-libpgfeutils
 	$(CC) $(CFLAGS) $^ $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@$(X)
 
 install: all installdirs
diff --git a/src/bin/pg_resetwal/nls.mk b/src/bin/pg_resetwal/nls.mk
index 82ec4f743c..cc40875b48 100644
--- a/src/bin/pg_resetwal/nls.mk
+++ b/src/bin/pg_resetwal/nls.mk
@@ -1,4 +1,6 @@
 # src/bin/pg_resetwal/nls.mk
 CATALOG_NAME     = pg_resetwal
 AVAIL_LANGUAGES  = cs de es fr it ja ko pl pt_BR ru sv tr zh_CN
-GETTEXT_FILES    = pg_resetwal.c ../../common/restricted_token.c
+GETTEXT_FILES    = $(FRONTEND_COMMON_GETTEXT_FILES) pg_resetwal.c ../../common/restricted_token.c
+GETTEXT_TRIGGERS = $(FRONTEND_COMMON_GETTEXT_TRIGGERS)
+GETTEXT_FLAGS    = $(FRONTEND_COMMON_GETTEXT_FLAGS)
diff --git a/src/bin/pg_resetwal/pg_resetwal.c b/src/bin/pg_resetwal/pg_resetwal.c
index e3213d404a..c6aa1644d7 100644
--- a/src/bin/pg_resetwal/pg_resetwal.c
+++ b/src/bin/pg_resetwal/pg_resetwal.c
@@ -54,6 +54,7 @@
 #include "common/fe_memutils.h"
 #include "common/file_perm.h"
 #include "common/restricted_token.h"
+#include "fe_utils/logging.h"
 #include "storage/large_object.h"
 #include "pg_getopt.h"
 #include "getopt_long.h"
@@ -117,7 +118,7 @@ main(int argc, char *argv[])
 	int			fd;
 
 	set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_resetwal"));
-
+	pg_logging_init(argv[0]);
 	progname = get_progname(argv[0]);
 
 	if (argc > 1)
@@ -157,13 +158,13 @@ main(int argc, char *argv[])
 				{
 					/*------
 					  translator: the second %s is a command line argument (-e, etc) */
-					fprintf(stderr, _("%s: invalid argument for option %s\n"), progname, "-e");
+					pg_log_error("invalid argument for option %s", "-e");
 					fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
 					exit(1);
 				}
 				if (set_xid_epoch == -1)
 				{
-					fprintf(stderr, _("%s: transaction ID epoch (-e) must not be -1\n"), progname);
+					pg_log_error("transaction ID epoch (-e) must not be -1");
 					exit(1);
 				}
 				break;
@@ -172,13 +173,13 @@ main(int argc, char *argv[])
 				set_xid = strtoul(optarg, &endptr, 0);
 				if (endptr == optarg || *endptr != '\0')
 				{
-					fprintf(stderr, _("%s: invalid argument for option %s\n"), progname, "-x");
+					pg_log_error("invalid argument for option %s", "-x");
 					fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
 					exit(1);
 				}
 				if (set_xid == 0)
 				{
-					fprintf(stderr, _("%s: transaction ID (-x) must not be 0\n"), progname);
+					pg_log_error("transaction ID (-x) must not be 0");
 					exit(1);
 				}
 				break;
@@ -187,14 +188,14 @@ main(int argc, char *argv[])
 				set_oldest_commit_ts_xid = strtoul(optarg, &endptr, 0);
 				if (endptr == optarg || *endptr != ',')
 				{
-					fprintf(stderr, _("%s: invalid argument for option %s\n"), progname, "-c");
+					pg_log_error("invalid argument for option %s", "-c");
 					fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
 					exit(1);
 				}
 				set_newest_commit_ts_xid = strtoul(endptr + 1, &endptr2, 0);
 				if (endptr2 == endptr + 1 || *endptr2 != '\0')
 				{
-					fprintf(stderr, _("%s: invalid argument for option %s\n"), progname, "-c");
+					pg_log_error("invalid argument for option %s", "-c");
 					fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
 					exit(1);
 				}
@@ -202,14 +203,14 @@ main(int argc, char *argv[])
 				if (set_oldest_commit_ts_xid < 2 &&
 					set_oldest_commit_ts_xid != 0)
 				{
-					fprintf(stderr, _("%s: transaction ID (-c) must be either 0 or greater than or equal to 2\n"), progname);
+					pg_log_error("transaction ID (-c) must be either 0 or greater than or equal to 2");
 					exit(1);
 				}
 
 				if (set_newest_commit_ts_xid < 2 &&
 					set_newest_commit_ts_xid != 0)
 				{
-					fprintf(stderr, _("%s: transaction ID (-c) must be either 0 or greater than or equal to 2\n"), progname);
+					pg_log_error("transaction ID (-c) must be either 0 or greater than or equal to 2");
 					exit(1);
 				}
 				break;
@@ -218,13 +219,13 @@ main(int argc, char *argv[])
 				set_oid = strtoul(optarg, &endptr, 0);
 				if (endptr == optarg || *endptr != '\0')
 				{
-					fprintf(stderr, _("%s: invalid argument for option %s\n"), progname, "-o");
+					pg_log_error("invalid argument for option %s", "-o");
 					fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
 					exit(1);
 				}
 				if (set_oid == 0)
 				{
-					fprintf(stderr, _("%s: OID (-o) must not be 0\n"), progname);
+					pg_log_error("OID (-o) must not be 0");
 					exit(1);
 				}
 				break;
@@ -233,7 +234,7 @@ main(int argc, char *argv[])
 				set_mxid = strtoul(optarg, &endptr, 0);
 				if (endptr == optarg || *endptr != ',')
 				{
-					fprintf(stderr, _("%s: invalid argument for option %s\n"), progname, "-m");
+					pg_log_error("invalid argument for option %s", "-m");
 					fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
 					exit(1);
 				}
@@ -241,13 +242,13 @@ main(int argc, char *argv[])
 				set_oldestmxid = strtoul(endptr + 1, &endptr2, 0);
 				if (endptr2 == endptr + 1 || *endptr2 != '\0')
 				{
-					fprintf(stderr, _("%s: invalid argument for option %s\n"), progname, "-m");
+					pg_log_error("invalid argument for option %s", "-m");
 					fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
 					exit(1);
 				}
 				if (set_mxid == 0)
 				{
-					fprintf(stderr, _("%s: multitransaction ID (-m) must not be 0\n"), progname);
+					pg_log_error("multitransaction ID (-m) must not be 0");
 					exit(1);
 				}
 
@@ -257,8 +258,7 @@ main(int argc, char *argv[])
 				 */
 				if (set_oldestmxid == 0)
 				{
-					fprintf(stderr, _("%s: oldest multitransaction ID (-m) must not be 0\n"),
-							progname);
+					pg_log_error("oldest multitransaction ID (-m) must not be 0");
 					exit(1);
 				}
 				break;
@@ -267,13 +267,13 @@ main(int argc, char *argv[])
 				set_mxoff = strtoul(optarg, &endptr, 0);
 				if (endptr == optarg || *endptr != '\0')
 				{
-					fprintf(stderr, _("%s: invalid argument for option %s\n"), progname, "-O");
+					pg_log_error("invalid argument for option %s", "-O");
 					fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
 					exit(1);
 				}
 				if (set_mxoff == -1)
 				{
-					fprintf(stderr, _("%s: multitransaction offset (-O) must not be -1\n"), progname);
+					pg_log_error("multitransaction offset (-O) must not be -1");
 					exit(1);
 				}
 				break;
@@ -281,7 +281,7 @@ main(int argc, char *argv[])
 			case 'l':
 				if (strspn(optarg, "01234567890ABCDEFabcdef") != XLOG_FNAME_LEN)
 				{
-					fprintf(stderr, _("%s: invalid argument for option %s\n"), progname, "-l");
+					pg_log_error("invalid argument for option %s", "-l");
 					fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
 					exit(1);
 				}
@@ -297,16 +297,12 @@ main(int argc, char *argv[])
 				set_wal_segsize = strtol(optarg, &endptr, 10) * 1024 * 1024;
 				if (endptr == optarg || *endptr != '\0')
 				{
-					fprintf(stderr,
-							_("%s: argument of --wal-segsize must be a number\n"),
-							progname);
+					pg_log_error("argument of --wal-segsize must be a number");
 					exit(1);
 				}
 				if (!IsValidWalSegSize(set_wal_segsize))
 				{
-					fprintf(stderr,
-							_("%s: argument of --wal-segsize must be a power of 2 between 1 and 1024\n"),
-							progname);
+					pg_log_error("argument of --wal-segsize must be a power of 2 between 1 and 1024");
 					exit(1);
 				}
 				break;
@@ -323,8 +319,8 @@ main(int argc, char *argv[])
 	/* Complain if any arguments remain */
 	if (optind < argc)
 	{
-		fprintf(stderr, _("%s: too many command-line arguments (first is \"%s\")\n"),
-				progname, argv[optind]);
+		pg_log_error("too many command-line arguments (first is \"%s\")",
+					 argv[optind]);
 		fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
 				progname);
 		exit(1);
@@ -332,7 +328,7 @@ main(int argc, char *argv[])
 
 	if (DataDir == NULL)
 	{
-		fprintf(stderr, _("%s: no data directory specified\n"), progname);
+		pg_log_error("no data directory specified");
 		fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
 		exit(1);
 	}
@@ -346,21 +342,20 @@ main(int argc, char *argv[])
 #ifndef WIN32
 	if (geteuid() == 0)
 	{
-		fprintf(stderr, _("%s: cannot be executed by \"root\"\n"),
-				progname);
-		fprintf(stderr, _("You must run %s as the PostgreSQL superuser.\n"),
-				progname);
+		pg_log_error("cannot be executed by \"root\"");
+		pg_log_info("You must run %s as the PostgreSQL superuser.",
+					progname);
 		exit(1);
 	}
 #endif
 
-	get_restricted_token(progname);
+	get_restricted_token();
 
 	/* Set mask based on PGDATA permissions */
 	if (!GetDataDirectoryCreatePerm(DataDir))
 	{
-		fprintf(stderr, _("%s: could not read permissions of directory \"%s\": %s\n"),
-				progname, DataDir, strerror(errno));
+		pg_log_error("could not read permissions of directory \"%s\": %m",
+					 DataDir);
 		exit(1);
 	}
 
@@ -368,8 +363,8 @@ main(int argc, char *argv[])
 
 	if (chdir(DataDir) < 0)
 	{
-		fprintf(stderr, _("%s: could not change directory to \"%s\": %s\n"),
-				progname, DataDir, strerror(errno));
+		pg_log_error("could not change directory to \"%s\": %m",
+					 DataDir);
 		exit(1);
 	}
 
@@ -384,16 +379,15 @@ main(int argc, char *argv[])
 	{
 		if (errno != ENOENT)
 		{
-			fprintf(stderr, _("%s: could not open file \"%s\" for reading: %s\n"),
-					progname, "postmaster.pid", strerror(errno));
+			pg_log_error("could not open file \"%s\" for reading: %m",
+						 "postmaster.pid");
 			exit(1);
 		}
 	}
 	else
 	{
-		fprintf(stderr, _("%s: lock file \"%s\" exists\n"
-						  "Is a server running?  If not, delete the lock file and try again.\n"),
-				progname, "postmaster.pid");
+		pg_log_error("lock file \"%s\" exists", "postmaster.pid");
+		pg_log_info("Is a server running?  If not, delete the lock file and try again.");
 		exit(1);
 	}
 
@@ -545,8 +539,8 @@ CheckDataVersion(void)
 
 	if ((ver_fd = fopen(ver_file, "r")) == NULL)
 	{
-		fprintf(stderr, _("%s: could not open file \"%s\" for reading: %s\n"),
-				progname, ver_file, strerror(errno));
+		pg_log_error("could not open file \"%s\" for reading: %m",
+					 ver_file);
 		exit(1);
 	}
 
@@ -554,15 +548,9 @@ CheckDataVersion(void)
 	if (!fgets(rawline, sizeof(rawline), ver_fd))
 	{
 		if (!ferror(ver_fd))
-		{
-			fprintf(stderr, _("%s: unexpected empty file \"%s\"\n"),
-					progname, ver_file);
-		}
+			pg_log_error("unexpected empty file \"%s\"", ver_file);
 		else
-		{
-			fprintf(stderr, _("%s: could not read file \"%s\": %s\n"),
-					progname, ver_file, strerror(errno));
-		}
+			pg_log_error("could not read file \"%s\": %m", ver_file);
 		exit(1);
 	}
 
@@ -577,9 +565,9 @@ CheckDataVersion(void)
 
 	if (strcmp(rawline, PG_MAJORVERSION) != 0)
 	{
-		fprintf(stderr, _("%s: data directory is of wrong version\n"
-						  "File \"%s\" contains \"%s\", which is not compatible with this program's version \"%s\".\n"),
-				progname, ver_file, rawline, PG_MAJORVERSION);
+		pg_log_error("data directory is of wrong version");
+		pg_log_info("File \"%s\" contains \"%s\", which is not compatible with this program's version \"%s\".",
+					ver_file, rawline, PG_MAJORVERSION);
 		exit(1);
 	}
 
@@ -608,13 +596,13 @@ ReadControlFile(void)
 		 * are we've been handed a bad DataDir path, so give up. User can do
 		 * "touch pg_control" to force us to proceed.
 		 */
-		fprintf(stderr, _("%s: could not open file \"%s\" for reading: %s\n"),
-				progname, XLOG_CONTROL_FILE, strerror(errno));
+		pg_log_error("could not open file \"%s\" for reading: %m",
+					 XLOG_CONTROL_FILE);
 		if (errno == ENOENT)
-			fprintf(stderr, _("If you are sure the data directory path is correct, execute\n"
-							  "  touch %s\n"
-							  "and try again.\n"),
-					XLOG_CONTROL_FILE);
+			pg_log_info("If you are sure the data directory path is correct, execute\n"
+						"  touch %s\n"
+						"and try again.",
+						XLOG_CONTROL_FILE);
 		exit(1);
 	}
 
@@ -624,8 +612,7 @@ ReadControlFile(void)
 	len = read(fd, buffer, PG_CONTROL_FILE_SIZE);
 	if (len < 0)
 	{
-		fprintf(stderr, _("%s: could not read file \"%s\": %s\n"),
-				progname, XLOG_CONTROL_FILE, strerror(errno));
+		pg_log_error("could not read file \"%s\": %m", XLOG_CONTROL_FILE);
 		exit(1);
 	}
 	close(fd);
@@ -643,9 +630,7 @@ ReadControlFile(void)
 		if (!EQ_CRC32C(crc, ((ControlFileData *) buffer)->crc))
 		{
 			/* We will use the data but treat it as guessed. */
-			fprintf(stderr,
-					_("%s: pg_control exists but has invalid CRC; proceed with caution\n"),
-					progname);
+			pg_log_warning("pg_control exists but has invalid CRC; proceed with caution");
 			guessed = true;
 		}
 
@@ -654,11 +639,10 @@ ReadControlFile(void)
 		/* return false if WAL segment size is not valid */
 		if (!IsValidWalSegSize(ControlFile.xlog_seg_size))
 		{
-			fprintf(stderr,
-					ngettext("%s: pg_control specifies invalid WAL segment size (%d byte); proceed with caution\n",
-							 "%s: pg_control specifies invalid WAL segment size (%d bytes); proceed with caution\n",
-							 ControlFile.xlog_seg_size),
-					progname, ControlFile.xlog_seg_size);
+			pg_log_warning(ngettext("pg_control specifies invalid WAL segment size (%d byte); proceed with caution",
+									"pg_control specifies invalid WAL segment size (%d bytes); proceed with caution",
+									ControlFile.xlog_seg_size),
+						   ControlFile.xlog_seg_size);
 			return false;
 		}
 
@@ -666,8 +650,7 @@ ReadControlFile(void)
 	}
 
 	/* Looks like it's a mess. */
-	fprintf(stderr, _("%s: pg_control exists but is broken or wrong version; ignoring it\n"),
-			progname);
+	pg_log_warning("pg_control exists but is broken or wrong version; ignoring it");
 	return false;
 }
 
@@ -983,8 +966,7 @@ RewriteControlFile(void)
 			  pg_file_create_mode);
 	if (fd < 0)
 	{
-		fprintf(stderr, _("%s: could not create pg_control file: %s\n"),
-				progname, strerror(errno));
+		pg_log_error("could not create pg_control file: %m");
 		exit(1);
 	}
 
@@ -994,14 +976,13 @@ RewriteControlFile(void)
 		/* if write didn't set errno, assume problem is no disk space */
 		if (errno == 0)
 			errno = ENOSPC;
-		fprintf(stderr, _("%s: could not write pg_control file: %s\n"),
-				progname, strerror(errno));
+		pg_log_error("could not write pg_control file: %m");
 		exit(1);
 	}
 
 	if (fsync(fd) != 0)
 	{
-		fprintf(stderr, _("%s: fsync error: %s\n"), progname, strerror(errno));
+		pg_log_error("fsync error: %m");
 		exit(1);
 	}
 
@@ -1041,8 +1022,7 @@ FindEndOfXLOG(void)
 	xldir = opendir(XLOGDIR);
 	if (xldir == NULL)
 	{
-		fprintf(stderr, _("%s: could not open directory \"%s\": %s\n"),
-				progname, XLOGDIR, strerror(errno));
+		pg_log_error("could not open directory \"%s\": %m", XLOGDIR);
 		exit(1);
 	}
 
@@ -1077,15 +1057,13 @@ FindEndOfXLOG(void)
 
 	if (errno)
 	{
-		fprintf(stderr, _("%s: could not read directory \"%s\": %s\n"),
-				progname, XLOGDIR, strerror(errno));
+		pg_log_error("could not read directory \"%s\": %m", XLOGDIR);
 		exit(1);
 	}
 
 	if (closedir(xldir))
 	{
-		fprintf(stderr, _("%s: could not close directory \"%s\": %s\n"),
-				progname, XLOGDIR, strerror(errno));
+		pg_log_error("could not close directory \"%s\": %m", XLOGDIR);
 		exit(1);
 	}
 
@@ -1112,8 +1090,7 @@ KillExistingXLOG(void)
 	xldir = opendir(XLOGDIR);
 	if (xldir == NULL)
 	{
-		fprintf(stderr, _("%s: could not open directory \"%s\": %s\n"),
-				progname, XLOGDIR, strerror(errno));
+		pg_log_error("could not open directory \"%s\": %m", XLOGDIR);
 		exit(1);
 	}
 
@@ -1125,8 +1102,7 @@ KillExistingXLOG(void)
 			snprintf(path, sizeof(path), "%s/%s", XLOGDIR, xlde->d_name);
 			if (unlink(path) < 0)
 			{
-				fprintf(stderr, _("%s: could not delete file \"%s\": %s\n"),
-						progname, path, strerror(errno));
+				pg_log_error("could not delete file \"%s\": %m", path);
 				exit(1);
 			}
 		}
@@ -1134,15 +1110,13 @@ KillExistingXLOG(void)
 
 	if (errno)
 	{
-		fprintf(stderr, _("%s: could not read directory \"%s\": %s\n"),
-				progname, XLOGDIR, strerror(errno));
+		pg_log_error("could not read directory \"%s\": %m", XLOGDIR);
 		exit(1);
 	}
 
 	if (closedir(xldir))
 	{
-		fprintf(stderr, _("%s: could not close directory \"%s\": %s\n"),
-				progname, XLOGDIR, strerror(errno));
+		pg_log_error("could not close directory \"%s\": %m", XLOGDIR);
 		exit(1);
 	}
 }
@@ -1163,8 +1137,7 @@ KillExistingArchiveStatus(void)
 	xldir = opendir(ARCHSTATDIR);
 	if (xldir == NULL)
 	{
-		fprintf(stderr, _("%s: could not open directory \"%s\": %s\n"),
-				progname, ARCHSTATDIR, strerror(errno));
+		pg_log_error("could not open directory \"%s\": %m", ARCHSTATDIR);
 		exit(1);
 	}
 
@@ -1179,8 +1152,7 @@ KillExistingArchiveStatus(void)
 			snprintf(path, sizeof(path), "%s/%s", ARCHSTATDIR, xlde->d_name);
 			if (unlink(path) < 0)
 			{
-				fprintf(stderr, _("%s: could not delete file \"%s\": %s\n"),
-						progname, path, strerror(errno));
+				pg_log_error("could not delete file \"%s\": %m", path);
 				exit(1);
 			}
 		}
@@ -1188,15 +1160,13 @@ KillExistingArchiveStatus(void)
 
 	if (errno)
 	{
-		fprintf(stderr, _("%s: could not read directory \"%s\": %s\n"),
-				progname, ARCHSTATDIR, strerror(errno));
+		pg_log_error("could not read directory \"%s\": %m", ARCHSTATDIR);
 		exit(1);
 	}
 
 	if (closedir(xldir))
 	{
-		fprintf(stderr, _("%s: could not close directory \"%s\": %s\n"),
-				progname, ARCHSTATDIR, strerror(errno));
+		pg_log_error("could not close directory \"%s\": %m", ARCHSTATDIR);
 		exit(1);
 	}
 }
@@ -1263,8 +1233,7 @@ WriteEmptyXLOG(void)
 			  pg_file_create_mode);
 	if (fd < 0)
 	{
-		fprintf(stderr, _("%s: could not open file \"%s\": %s\n"),
-				progname, path, strerror(errno));
+		pg_log_error("could not open file \"%s\": %m", path);
 		exit(1);
 	}
 
@@ -1274,8 +1243,7 @@ WriteEmptyXLOG(void)
 		/* if write didn't set errno, assume problem is no disk space */
 		if (errno == 0)
 			errno = ENOSPC;
-		fprintf(stderr, _("%s: could not write file \"%s\": %s\n"),
-				progname, path, strerror(errno));
+		pg_log_error("could not write file \"%s\": %m", path);
 		exit(1);
 	}
 
@@ -1288,15 +1256,14 @@ WriteEmptyXLOG(void)
 		{
 			if (errno == 0)
 				errno = ENOSPC;
-			fprintf(stderr, _("%s: could not write file \"%s\": %s\n"),
-					progname, path, strerror(errno));
+			pg_log_error("could not write file \"%s\": %m", path);
 			exit(1);
 		}
 	}
 
 	if (fsync(fd) != 0)
 	{
-		fprintf(stderr, _("%s: fsync error: %s\n"), progname, strerror(errno));
+		pg_log_error("fsync error: %m");
 		exit(1);
 	}
 
diff --git a/src/bin/pg_resetwal/t/002_corrupted.pl b/src/bin/pg_resetwal/t/002_corrupted.pl
index 0022dcb8ff..f9940d7fc5 100644
--- a/src/bin/pg_resetwal/t/002_corrupted.pl
+++ b/src/bin/pg_resetwal/t/002_corrupted.pl
@@ -32,7 +32,7 @@
 	0,
 	[qr/pg_control version number/],
 	[
-		qr/pg_resetwal: pg_control exists but is broken or wrong version; ignoring it/
+		qr/pg_resetwal: warning: pg_control exists but is broken or wrong version; ignoring it/
 	],
 	'processes corrupted pg_control all zeroes');
 
@@ -48,6 +48,6 @@
 	0,
 	[qr/pg_control version number/],
 	[
-		qr/\Qpg_resetwal: pg_control specifies invalid WAL segment size (0 bytes); proceed with caution\E/
+		qr/\Qpg_resetwal: warning: pg_control specifies invalid WAL segment size (0 bytes); proceed with caution\E/
 	],
 	'processes zero WAL segment size');
diff --git a/src/bin/pg_rewind/Makefile b/src/bin/pg_rewind/Makefile
index 04f3b8f520..019e19986e 100644
--- a/src/bin/pg_rewind/Makefile
+++ b/src/bin/pg_rewind/Makefile
@@ -16,7 +16,7 @@ top_builddir = ../../..
 include $(top_builddir)/src/Makefile.global
 
 override CPPFLAGS := -I$(libpq_srcdir) -DFRONTEND $(CPPFLAGS)
-LDFLAGS_INTERNAL += $(libpq_pgport)
+LDFLAGS_INTERNAL += -L$(top_builddir)/src/fe_utils -lpgfeutils $(libpq_pgport)
 
 OBJS	= pg_rewind.o parsexlog.o xlogreader.o datapagemap.o timeline.o \
 	fetch.o file_ops.o copy_fetch.o libpq_fetch.o filemap.o logging.o \
@@ -26,7 +26,7 @@ EXTRA_CLEAN = xlogreader.c
 
 all: pg_rewind
 
-pg_rewind: $(OBJS) | submake-libpq submake-libpgport
+pg_rewind: $(OBJS) | submake-libpq submake-libpgport submake-libpgfeutils
 	$(CC) $(CFLAGS) $^ $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@$(X)
 
 xlogreader.c: % : $(top_srcdir)/src/backend/access/transam/%
diff --git a/src/bin/pg_rewind/copy_fetch.c b/src/bin/pg_rewind/copy_fetch.c
index a283405f6c..3fd0404ddf 100644
--- a/src/bin/pg_rewind/copy_fetch.c
+++ b/src/bin/pg_rewind/copy_fetch.c
@@ -57,8 +57,8 @@ recurse_dir(const char *datadir, const char *parentpath,
 
 	xldir = opendir(fullparentpath);
 	if (xldir == NULL)
-		pg_fatal("could not open directory \"%s\": %s\n",
-				 fullparentpath, strerror(errno));
+		pg_fatal("could not open directory \"%s\": %m",
+				 fullparentpath);
 
 	while (errno = 0, (xlde = readdir(xldir)) != NULL)
 	{
@@ -86,8 +86,8 @@ recurse_dir(const char *datadir, const char *parentpath,
 				 */
 			}
 			else
-				pg_fatal("could not stat file \"%s\": %s\n",
-						 fullpath, strerror(errno));
+				pg_fatal("could not stat file \"%s\": %m",
+						 fullpath);
 		}
 
 		if (parentpath)
@@ -115,10 +115,10 @@ recurse_dir(const char *datadir, const char *parentpath,
 
 			len = readlink(fullpath, link_target, sizeof(link_target));
 			if (len < 0)
-				pg_fatal("could not read symbolic link \"%s\": %s\n",
-						 fullpath, strerror(errno));
+				pg_fatal("could not read symbolic link \"%s\": %m",
+						 fullpath);
 			if (len >= sizeof(link_target))
-				pg_fatal("symbolic link \"%s\" target is too long\n",
+				pg_fatal("symbolic link \"%s\" target is too long",
 						 fullpath);
 			link_target[len] = '\0';
 
@@ -133,19 +133,19 @@ recurse_dir(const char *datadir, const char *parentpath,
 				strcmp(path, "pg_wal") == 0)
 				recurse_dir(datadir, path, callback);
 #else
-			pg_fatal("\"%s\" is a symbolic link, but symbolic links are not supported on this platform\n",
+			pg_fatal("\"%s\" is a symbolic link, but symbolic links are not supported on this platform",
 					 fullpath);
 #endif							/* HAVE_READLINK */
 		}
 	}
 
 	if (errno)
-		pg_fatal("could not read directory \"%s\": %s\n",
-				 fullparentpath, strerror(errno));
+		pg_fatal("could not read directory \"%s\": %m",
+				 fullparentpath);
 
 	if (closedir(xldir))
-		pg_fatal("could not close directory \"%s\": %s\n",
-				 fullparentpath, strerror(errno));
+		pg_fatal("could not close directory \"%s\": %m",
+				 fullparentpath);
 }
 
 /*
@@ -164,11 +164,11 @@ rewind_copy_file_range(const char *path, off_t begin, off_t end, bool trunc)
 
 	srcfd = open(srcpath, O_RDONLY | PG_BINARY, 0);
 	if (srcfd < 0)
-		pg_fatal("could not open source file \"%s\": %s\n",
-				 srcpath, strerror(errno));
+		pg_fatal("could not open source file \"%s\": %m",
+				 srcpath);
 
 	if (lseek(srcfd, begin, SEEK_SET) == -1)
-		pg_fatal("could not seek in source file: %s\n", strerror(errno));
+		pg_fatal("could not seek in source file: %m");
 
 	open_target_file(path, trunc);
 
@@ -185,17 +185,17 @@ rewind_copy_file_range(const char *path, off_t begin, off_t end, bool trunc)
 		readlen = read(srcfd, buf.data, len);
 
 		if (readlen < 0)
-			pg_fatal("could not read file \"%s\": %s\n",
-					 srcpath, strerror(errno));
+			pg_fatal("could not read file \"%s\": %m",
+					 srcpath);
 		else if (readlen == 0)
-			pg_fatal("unexpected EOF while reading file \"%s\"\n", srcpath);
+			pg_fatal("unexpected EOF while reading file \"%s\"", srcpath);
 
 		write_target_range(buf.data, begin, readlen);
 		begin += readlen;
 	}
 
 	if (close(srcfd) != 0)
-		pg_fatal("could not close file \"%s\": %s\n", srcpath, strerror(errno));
+		pg_fatal("could not close file \"%s\": %m", srcpath);
 }
 
 /*
diff --git a/src/bin/pg_rewind/datapagemap.c b/src/bin/pg_rewind/datapagemap.c
index 6262f1f870..fc70fe5706 100644
--- a/src/bin/pg_rewind/datapagemap.c
+++ b/src/bin/pg_rewind/datapagemap.c
@@ -13,7 +13,8 @@
 #include "postgres_fe.h"
 
 #include "datapagemap.h"
-#include "logging.h"
+
+#include "fe_utils/logging.h"
 
 struct datapagemap_iterator
 {
@@ -121,7 +122,7 @@ datapagemap_print(datapagemap_t *map)
 
 	iter = datapagemap_iterate(map);
 	while (datapagemap_next(iter, &blocknum))
-		pg_log(PG_DEBUG, "  block %u\n", blocknum);
+		pg_log_debug("block %u", blocknum);
 
 	pg_free(iter);
 }
diff --git a/src/bin/pg_rewind/file_ops.c b/src/bin/pg_rewind/file_ops.c
index bbdcbe44ac..e442f93555 100644
--- a/src/bin/pg_rewind/file_ops.c
+++ b/src/bin/pg_rewind/file_ops.c
@@ -60,8 +60,8 @@ open_target_file(const char *path, bool trunc)
 		mode |= O_TRUNC;
 	dstfd = open(dstpath, mode, pg_file_create_mode);
 	if (dstfd < 0)
-		pg_fatal("could not open target file \"%s\": %s\n",
-				 dstpath, strerror(errno));
+		pg_fatal("could not open target file \"%s\": %m",
+				 dstpath);
 }
 
 /*
@@ -74,8 +74,8 @@ close_target_file(void)
 		return;
 
 	if (close(dstfd) != 0)
-		pg_fatal("could not close target file \"%s\": %s\n",
-				 dstpath, strerror(errno));
+		pg_fatal("could not close target file \"%s\": %m",
+				 dstpath);
 
 	dstfd = -1;
 }
@@ -94,8 +94,8 @@ write_target_range(char *buf, off_t begin, size_t size)
 		return;
 
 	if (lseek(dstfd, begin, SEEK_SET) == -1)
-		pg_fatal("could not seek in target file \"%s\": %s\n",
-				 dstpath, strerror(errno));
+		pg_fatal("could not seek in target file \"%s\": %m",
+				 dstpath);
 
 	writeleft = size;
 	p = buf;
@@ -110,8 +110,8 @@ write_target_range(char *buf, off_t begin, size_t size)
 			/* if write didn't set errno, assume problem is no disk space */
 			if (errno == 0)
 				errno = ENOSPC;
-			pg_fatal("could not write file \"%s\": %s\n",
-					 dstpath, strerror(errno));
+			pg_fatal("could not write file \"%s\": %m",
+					 dstpath);
 		}
 
 		p += writelen;
@@ -160,7 +160,7 @@ create_target(file_entry_t *entry)
 
 		case FILE_TYPE_REGULAR:
 			/* can't happen. Regular files are created with open_target_file. */
-			pg_fatal("invalid action (CREATE) for regular file\n");
+			pg_fatal("invalid action (CREATE) for regular file");
 			break;
 	}
 }
@@ -183,8 +183,8 @@ remove_target_file(const char *path, bool missing_ok)
 		if (errno == ENOENT && missing_ok)
 			return;
 
-		pg_fatal("could not remove file \"%s\": %s\n",
-				 dstpath, strerror(errno));
+		pg_fatal("could not remove file \"%s\": %m",
+				 dstpath);
 	}
 }
 
@@ -201,12 +201,12 @@ truncate_target_file(const char *path, off_t newsize)
 
 	fd = open(dstpath, O_WRONLY, pg_file_create_mode);
 	if (fd < 0)
-		pg_fatal("could not open file \"%s\" for truncation: %s\n",
-				 dstpath, strerror(errno));
+		pg_fatal("could not open file \"%s\" for truncation: %m",
+				 dstpath);
 
 	if (ftruncate(fd, newsize) != 0)
-		pg_fatal("could not truncate file \"%s\" to %u: %s\n",
-				 dstpath, (unsigned int) newsize, strerror(errno));
+		pg_fatal("could not truncate file \"%s\" to %u: %m",
+				 dstpath, (unsigned int) newsize);
 
 	close(fd);
 }
@@ -221,8 +221,8 @@ create_target_dir(const char *path)
 
 	snprintf(dstpath, sizeof(dstpath), "%s/%s", datadir_target, path);
 	if (mkdir(dstpath, pg_dir_create_mode) != 0)
-		pg_fatal("could not create directory \"%s\": %s\n",
-				 dstpath, strerror(errno));
+		pg_fatal("could not create directory \"%s\": %m",
+				 dstpath);
 }
 
 static void
@@ -235,8 +235,8 @@ remove_target_dir(const char *path)
 
 	snprintf(dstpath, sizeof(dstpath), "%s/%s", datadir_target, path);
 	if (rmdir(dstpath) != 0)
-		pg_fatal("could not remove directory \"%s\": %s\n",
-				 dstpath, strerror(errno));
+		pg_fatal("could not remove directory \"%s\": %m",
+				 dstpath);
 }
 
 static void
@@ -249,8 +249,8 @@ create_target_symlink(const char *path, const char *link)
 
 	snprintf(dstpath, sizeof(dstpath), "%s/%s", datadir_target, path);
 	if (symlink(link, dstpath) != 0)
-		pg_fatal("could not create symbolic link at \"%s\": %s\n",
-				 dstpath, strerror(errno));
+		pg_fatal("could not create symbolic link at \"%s\": %m",
+				 dstpath);
 }
 
 static void
@@ -263,8 +263,8 @@ remove_target_symlink(const char *path)
 
 	snprintf(dstpath, sizeof(dstpath), "%s/%s", datadir_target, path);
 	if (unlink(dstpath) != 0)
-		pg_fatal("could not remove symbolic link \"%s\": %s\n",
-				 dstpath, strerror(errno));
+		pg_fatal("could not remove symbolic link \"%s\": %m",
+				 dstpath);
 }
 
 
@@ -294,12 +294,12 @@ slurpFile(const char *datadir, const char *path, size_t *filesize)
 	snprintf(fullpath, sizeof(fullpath), "%s/%s", datadir, path);
 
 	if ((fd = open(fullpath, O_RDONLY | PG_BINARY, 0)) == -1)
-		pg_fatal("could not open file \"%s\" for reading: %s\n",
-				 fullpath, strerror(errno));
+		pg_fatal("could not open file \"%s\" for reading: %m",
+				 fullpath);
 
 	if (fstat(fd, &statbuf) < 0)
-		pg_fatal("could not open file \"%s\" for reading: %s\n",
-				 fullpath, strerror(errno));
+		pg_fatal("could not open file \"%s\" for reading: %m",
+				 fullpath);
 
 	len = statbuf.st_size;
 
@@ -309,10 +309,10 @@ slurpFile(const char *datadir, const char *path, size_t *filesize)
 	if (r != len)
 	{
 		if (r < 0)
-			pg_fatal("could not read file \"%s\": %s\n",
-					 fullpath, strerror(errno));
+			pg_fatal("could not read file \"%s\": %m",
+					 fullpath);
 		else
-			pg_fatal("could not read file \"%s\": read %d of %zu\n",
+			pg_fatal("could not read file \"%s\": read %d of %zu",
 					 fullpath, r, (Size) len);
 	}
 	close(fd);
diff --git a/src/bin/pg_rewind/filemap.c b/src/bin/pg_rewind/filemap.c
index bb4ffd0e38..170dc64dda 100644
--- a/src/bin/pg_rewind/filemap.c
+++ b/src/bin/pg_rewind/filemap.c
@@ -20,6 +20,7 @@
 
 #include "common/string.h"
 #include "catalog/pg_tablespace_d.h"
+#include "fe_utils/logging.h"
 #include "storage/fd.h"
 
 filemap_t  *filemap = NULL;
@@ -174,7 +175,7 @@ process_source_file(const char *path, file_type_t type, size_t newsize,
 	 * regular file
 	 */
 	if (type != FILE_TYPE_REGULAR && isRelDataFile(path))
-		pg_fatal("data file \"%s\" in source is not a regular file\n", path);
+		pg_fatal("data file \"%s\" in source is not a regular file", path);
 
 	snprintf(localpath, sizeof(localpath), "%s/%s", datadir_target, path);
 
@@ -182,8 +183,8 @@ process_source_file(const char *path, file_type_t type, size_t newsize,
 	if (lstat(localpath, &statbuf) < 0)
 	{
 		if (errno != ENOENT)
-			pg_fatal("could not stat file \"%s\": %s\n",
-					 localpath, strerror(errno));
+			pg_fatal("could not stat file \"%s\": %m",
+					 localpath);
 
 		exists = false;
 	}
@@ -196,7 +197,7 @@ process_source_file(const char *path, file_type_t type, size_t newsize,
 			if (exists && !S_ISDIR(statbuf.st_mode) && strcmp(path, "pg_wal") != 0)
 			{
 				/* it's a directory in source, but not in target. Strange.. */
-				pg_fatal("\"%s\" is not a directory\n", localpath);
+				pg_fatal("\"%s\" is not a directory", localpath);
 			}
 
 			if (!exists)
@@ -219,7 +220,7 @@ process_source_file(const char *path, file_type_t type, size_t newsize,
 				 * It's a symbolic link in source, but not in target.
 				 * Strange..
 				 */
-				pg_fatal("\"%s\" is not a symbolic link\n", localpath);
+				pg_fatal("\"%s\" is not a symbolic link", localpath);
 			}
 
 			if (!exists)
@@ -231,7 +232,7 @@ process_source_file(const char *path, file_type_t type, size_t newsize,
 
 		case FILE_TYPE_REGULAR:
 			if (exists && !S_ISREG(statbuf.st_mode))
-				pg_fatal("\"%s\" is not a regular file\n", localpath);
+				pg_fatal("\"%s\" is not a regular file", localpath);
 
 			if (!exists || !isRelDataFile(path))
 			{
@@ -345,8 +346,8 @@ process_target_file(const char *path, file_type_t type, size_t oldsize,
 	if (lstat(localpath, &statbuf) < 0)
 	{
 		if (errno != ENOENT)
-			pg_fatal("could not stat file \"%s\": %s\n",
-					 localpath, strerror(errno));
+			pg_fatal("could not stat file \"%s\": %m",
+					 localpath);
 
 		exists = false;
 	}
@@ -357,7 +358,7 @@ process_target_file(const char *path, file_type_t type, size_t oldsize,
 		if (map->nlist == 0)
 		{
 			/* should not happen */
-			pg_fatal("source file list is empty\n");
+			pg_fatal("source file list is empty");
 		}
 
 		filemap_list_to_array(map);
@@ -472,7 +473,7 @@ process_block_change(ForkNumber forknum, RelFileNode rnode, BlockNumber blkno)
 				break;
 
 			case FILE_ACTION_CREATE:
-				pg_fatal("unexpected page modification for directory or symbolic link \"%s\"\n", entry->path);
+				pg_fatal("unexpected page modification for directory or symbolic link \"%s\"", entry->path);
 		}
 	}
 	else
@@ -507,10 +508,10 @@ check_file_excluded(const char *path, bool is_source)
 		if (strcmp(filename, excludeFiles[excludeIdx]) == 0)
 		{
 			if (is_source)
-				pg_log(PG_DEBUG, "entry \"%s\" excluded from source file list\n",
+				pg_log_debug("entry \"%s\" excluded from source file list",
 					   path);
 			else
-				pg_log(PG_DEBUG, "entry \"%s\" excluded from target file list\n",
+				pg_log_debug("entry \"%s\" excluded from target file list",
 					   path);
 			return true;
 		}
@@ -527,10 +528,10 @@ check_file_excluded(const char *path, bool is_source)
 		if (strstr(path, localpath) == path)
 		{
 			if (is_source)
-				pg_log(PG_DEBUG, "entry \"%s\" excluded from source file list\n",
+				pg_log_debug("entry \"%s\" excluded from source file list",
 					   path);
 			else
-				pg_log(PG_DEBUG, "entry \"%s\" excluded from target file list\n",
+				pg_log_debug("entry \"%s\" excluded from target file list",
 					   path);
 			return true;
 		}
@@ -658,10 +659,7 @@ print_filemap(void)
 		if (entry->action != FILE_ACTION_NONE ||
 			entry->pagemap.bitmapsize > 0)
 		{
-			pg_log(PG_DEBUG,
-			/*------
-			   translator: first %s is a file path, second is a keyword such as COPY */
-				   "%s (%s)\n", entry->path,
+			pg_log_debug("%s (%s)", entry->path,
 				   action_to_str(entry->action));
 
 			if (entry->pagemap.bitmapsize > 0)
diff --git a/src/bin/pg_rewind/libpq_fetch.c b/src/bin/pg_rewind/libpq_fetch.c
index d06e277432..c756b7019c 100644
--- a/src/bin/pg_rewind/libpq_fetch.c
+++ b/src/bin/pg_rewind/libpq_fetch.c
@@ -24,6 +24,7 @@
 #include "libpq-fe.h"
 #include "catalog/pg_type_d.h"
 #include "fe_utils/connect.h"
+#include "fe_utils/logging.h"
 #include "port/pg_bswap.h"
 
 static PGconn *conn = NULL;
@@ -52,7 +53,7 @@ libpqConnect(const char *connstr)
 		pg_fatal("could not connect to server: %s",
 				 PQerrorMessage(conn));
 
-	pg_log(PG_PROGRESS, "connected to server\n");
+	pg_log_info("connected to server");
 
 	res = PQexec(conn, ALWAYS_SECURE_SEARCH_PATH_SQL);
 	if (PQresultStatus(res) != PGRES_TUPLES_OK)
@@ -68,7 +69,7 @@ libpqConnect(const char *connstr)
 	 */
 	str = run_simple_query("SELECT pg_is_in_recovery()");
 	if (strcmp(str, "f") != 0)
-		pg_fatal("source server must not be in recovery mode\n");
+		pg_fatal("source server must not be in recovery mode");
 	pg_free(str);
 
 	/*
@@ -78,7 +79,7 @@ libpqConnect(const char *connstr)
 	 */
 	str = run_simple_query("SHOW full_page_writes");
 	if (strcmp(str, "on") != 0)
-		pg_fatal("full_page_writes must be enabled in the source server\n");
+		pg_fatal("full_page_writes must be enabled in the source server");
 	pg_free(str);
 
 	/*
@@ -113,7 +114,7 @@ run_simple_query(const char *sql)
 
 	/* sanity check the result set */
 	if (PQnfields(res) != 1 || PQntuples(res) != 1 || PQgetisnull(res, 0, 0))
-		pg_fatal("unexpected result set from query\n");
+		pg_fatal("unexpected result set from query");
 
 	result = pg_strdup(PQgetvalue(res, 0, 0));
 
@@ -136,7 +137,7 @@ libpqGetCurrentXlogInsertLocation(void)
 	val = run_simple_query("SELECT pg_current_wal_insert_lsn()");
 
 	if (sscanf(val, "%X/%X", &hi, &lo) != 2)
-		pg_fatal("unrecognized result \"%s\" for current WAL insert location\n", val);
+		pg_fatal("unrecognized result \"%s\" for current WAL insert location", val);
 
 	result = ((uint64) hi) << 32 | lo;
 
@@ -191,7 +192,7 @@ libpqProcessFileList(void)
 
 	/* sanity check the result set */
 	if (PQnfields(res) != 4)
-		pg_fatal("unexpected result set while fetching file list\n");
+		pg_fatal("unexpected result set while fetching file list");
 
 	/* Read result to local variables */
 	for (i = 0; i < PQntuples(res); i++)
@@ -241,10 +242,10 @@ receiveFileChunks(const char *sql)
 	if (PQsendQueryParams(conn, sql, 0, NULL, NULL, NULL, NULL, 1) != 1)
 		pg_fatal("could not send query: %s", PQerrorMessage(conn));
 
-	pg_log(PG_DEBUG, "getting file chunks\n");
+	pg_log_debug("getting file chunks");
 
 	if (PQsetSingleRowMode(conn) != 1)
-		pg_fatal("could not set libpq connection to single row mode\n");
+		pg_fatal("could not set libpq connection to single row mode");
 
 	while ((res = PQgetResult(conn)) != NULL)
 	{
@@ -271,13 +272,13 @@ receiveFileChunks(const char *sql)
 
 		/* sanity check the result set */
 		if (PQnfields(res) != 3 || PQntuples(res) != 1)
-			pg_fatal("unexpected result set size while fetching remote files\n");
+			pg_fatal("unexpected result set size while fetching remote files");
 
 		if (PQftype(res, 0) != TEXTOID ||
 			PQftype(res, 1) != INT8OID ||
 			PQftype(res, 2) != BYTEAOID)
 		{
-			pg_fatal("unexpected data types in result set while fetching remote files: %u %u %u\n",
+			pg_fatal("unexpected data types in result set while fetching remote files: %u %u %u",
 					 PQftype(res, 0), PQftype(res, 1), PQftype(res, 2));
 		}
 
@@ -285,17 +286,17 @@ receiveFileChunks(const char *sql)
 			PQfformat(res, 1) != 1 &&
 			PQfformat(res, 2) != 1)
 		{
-			pg_fatal("unexpected result format while fetching remote files\n");
+			pg_fatal("unexpected result format while fetching remote files");
 		}
 
 		if (PQgetisnull(res, 0, 0) ||
 			PQgetisnull(res, 0, 1))
 		{
-			pg_fatal("unexpected null values in result while fetching remote files\n");
+			pg_fatal("unexpected null values in result while fetching remote files");
 		}
 
 		if (PQgetlength(res, 0, 1) != sizeof(int64))
-			pg_fatal("unexpected result length while fetching remote files\n");
+			pg_fatal("unexpected result length while fetching remote files");
 
 		/* Read result set to local variables */
 		memcpy(&chunkoff, PQgetvalue(res, 0, 1), sizeof(int64));
@@ -319,8 +320,7 @@ receiveFileChunks(const char *sql)
 		 */
 		if (PQgetisnull(res, 0, 2))
 		{
-			pg_log(PG_DEBUG,
-				   "received null value for chunk for file \"%s\", file has been deleted\n",
+			pg_log_debug("received null value for chunk for file \"%s\", file has been deleted",
 				   filename);
 			remove_target_file(filename, true);
 			pg_free(filename);
@@ -333,7 +333,7 @@ receiveFileChunks(const char *sql)
 		 * translatable strings.
 		 */
 		snprintf(chunkoff_str, sizeof(chunkoff_str), INT64_FORMAT, chunkoff);
-		pg_log(PG_DEBUG, "received chunk for file \"%s\", offset %s, size %d\n",
+		pg_log_debug("received chunk for file \"%s\", offset %s, size %d",
 			   filename, chunkoff_str, chunksize);
 
 		open_target_file(filename, false);
@@ -367,7 +367,7 @@ libpqGetFile(const char *filename, size_t *filesize)
 
 	/* sanity check the result set */
 	if (PQntuples(res) != 1 || PQgetisnull(res, 0, 0))
-		pg_fatal("unexpected result set while fetching remote file \"%s\"\n",
+		pg_fatal("unexpected result set while fetching remote file \"%s\"",
 				 filename);
 
 	/* Read result to local variables */
@@ -378,7 +378,7 @@ libpqGetFile(const char *filename, size_t *filesize)
 
 	PQclear(res);
 
-	pg_log(PG_DEBUG, "fetched file \"%s\", length %d\n", filename, len);
+	pg_log_debug("fetched file \"%s\", length %d", filename, len);
 
 	if (filesize)
 		*filesize = len;
diff --git a/src/bin/pg_rewind/logging.c b/src/bin/pg_rewind/logging.c
index 572a759937..85f2567441 100644
--- a/src/bin/pg_rewind/logging.c
+++ b/src/bin/pg_rewind/logging.c
@@ -23,72 +23,6 @@ uint64		fetch_done;
 
 static pg_time_t last_progress_report = 0;
 
-#define QUERY_ALLOC			8192
-
-static
-pg_attribute_printf(2, 0)
-void
-pg_log_v(eLogType type, const char *fmt, va_list ap)
-{
-	char		message[QUERY_ALLOC];
-
-	vsnprintf(message, sizeof(message), _(fmt), ap);
-
-	switch (type)
-	{
-		case PG_DEBUG:
-			if (debug)
-				printf("%s", message);
-			break;
-
-		case PG_PROGRESS:
-			if (showprogress)
-				printf("%s", message);
-			break;
-
-		case PG_WARNING:
-			printf("%s", message);
-			break;
-
-		case PG_FATAL:
-			printf("\n%s", message);
-			printf("%s", _("Failure, exiting\n"));
-			exit(1);
-			break;
-
-		default:
-			break;
-	}
-	fflush(stdout);
-}
-
-
-void
-pg_log(eLogType type, const char *fmt,...)
-{
-	va_list		args;
-
-	va_start(args, fmt);
-	pg_log_v(type, fmt, args);
-	va_end(args);
-}
-
-
-/*
- * Print an error message, and exit.
- */
-void
-pg_fatal(const char *fmt,...)
-{
-	va_list		args;
-
-	va_start(args, fmt);
-	pg_log_v(PG_FATAL, fmt, args);
-	va_end(args);
-	/* should not get here, pg_log_v() exited already */
-	exit(1);
-}
-
 
 /*
  * Print a progress report based on the global variables.
@@ -135,8 +69,9 @@ progress_report(bool force)
 	snprintf(fetch_size_str, sizeof(fetch_size_str), INT64_FORMAT,
 			 fetch_size / 1024);
 
-	pg_log(PG_PROGRESS, "%*s/%s kB (%d%%) copied",
+	printf(_("%*s/%s kB (%d%%) copied"),
 		   (int) strlen(fetch_size_str), fetch_done_str, fetch_size_str,
 		   percent);
 	printf("\r");
+	fflush(stdout);
 }
diff --git a/src/bin/pg_rewind/logging.h b/src/bin/pg_rewind/logging.h
index 5c031e1821..81e17ac1f2 100644
--- a/src/bin/pg_rewind/logging.h
+++ b/src/bin/pg_rewind/logging.h
@@ -12,24 +12,14 @@
 #ifndef PG_REWIND_LOGGING_H
 #define PG_REWIND_LOGGING_H
 
+#include "fe_utils/logging.h"
+
 /* progress counters */
 extern uint64 fetch_size;
 extern uint64 fetch_done;
 
-/*
- * Enumeration to denote pg_log modes
- */
-typedef enum
-{
-	PG_DEBUG,
-	PG_PROGRESS,
-	PG_WARNING,
-	PG_FATAL
-} eLogType;
-
-extern void pg_log(eLogType type, const char *fmt,...) pg_attribute_printf(2, 3);
-extern void pg_fatal(const char *fmt,...) pg_attribute_printf(1, 2) pg_attribute_noreturn();
-
 extern void progress_report(bool force);
 
+#define pg_fatal(...) do { pg_log_fatal(__VA_ARGS__); exit(1); } while(0)
+
 #endif							/* PG_REWIND_LOGGING_H */
diff --git a/src/bin/pg_rewind/nls.mk b/src/bin/pg_rewind/nls.mk
index 2fb63bead8..58c9ede548 100644
--- a/src/bin/pg_rewind/nls.mk
+++ b/src/bin/pg_rewind/nls.mk
@@ -1,9 +1,8 @@
 # src/bin/pg_rewind/nls.mk
 CATALOG_NAME     = pg_rewind
 AVAIL_LANGUAGES  =de es fr it ja ko pl pt_BR ru sv tr zh_CN
-GETTEXT_FILES    = copy_fetch.c datapagemap.c fetch.c file_ops.c filemap.c libpq_fetch.c logging.c parsexlog.c pg_rewind.c timeline.c ../../common/fe_memutils.c ../../common/restricted_token.c xlogreader.c
-
-GETTEXT_TRIGGERS = pg_log:2 pg_fatal report_invalid_record:2
-GETTEXT_FLAGS    = pg_log:2:c-format \
+GETTEXT_FILES    = $(FRONTEND_COMMON_GETTEXT_FILES) copy_fetch.c datapagemap.c fetch.c file_ops.c filemap.c libpq_fetch.c logging.c parsexlog.c pg_rewind.c timeline.c ../../common/fe_memutils.c ../../common/restricted_token.c xlogreader.c
+GETTEXT_TRIGGERS = $(FRONTEND_COMMON_GETTEXT_TRIGGERS) pg_fatal report_invalid_record:2
+GETTEXT_FLAGS    = $(FRONTEND_COMMON_GETTEXT_FLAGS) \
     pg_fatal:1:c-format \
     report_invalid_record:2:c-format
diff --git a/src/bin/pg_rewind/parsexlog.c b/src/bin/pg_rewind/parsexlog.c
index e19c265cbb..841e0694b3 100644
--- a/src/bin/pg_rewind/parsexlog.c
+++ b/src/bin/pg_rewind/parsexlog.c
@@ -72,7 +72,7 @@ extractPageMap(const char *datadir, XLogRecPtr startpoint, int tliIndex,
 	xlogreader = XLogReaderAllocate(WalSegSz, &SimpleXLogPageRead,
 									&private);
 	if (xlogreader == NULL)
-		pg_fatal("out of memory\n");
+		pg_fatal("out of memory");
 
 	do
 	{
@@ -85,11 +85,11 @@ extractPageMap(const char *datadir, XLogRecPtr startpoint, int tliIndex,
 			errptr = startpoint ? startpoint : xlogreader->EndRecPtr;
 
 			if (errormsg)
-				pg_fatal("could not read WAL record at %X/%X: %s\n",
+				pg_fatal("could not read WAL record at %X/%X: %s",
 						 (uint32) (errptr >> 32), (uint32) (errptr),
 						 errormsg);
 			else
-				pg_fatal("could not read WAL record at %X/%X\n",
+				pg_fatal("could not read WAL record at %X/%X",
 						 (uint32) (startpoint >> 32),
 						 (uint32) (startpoint));
 		}
@@ -126,16 +126,16 @@ readOneRecord(const char *datadir, XLogRecPtr ptr, int tliIndex)
 	xlogreader = XLogReaderAllocate(WalSegSz, &SimpleXLogPageRead,
 									&private);
 	if (xlogreader == NULL)
-		pg_fatal("out of memory\n");
+		pg_fatal("out of memory");
 
 	record = XLogReadRecord(xlogreader, ptr, &errormsg);
 	if (record == NULL)
 	{
 		if (errormsg)
-			pg_fatal("could not read WAL record at %X/%X: %s\n",
+			pg_fatal("could not read WAL record at %X/%X: %s",
 					 (uint32) (ptr >> 32), (uint32) (ptr), errormsg);
 		else
-			pg_fatal("could not read WAL record at %X/%X\n",
+			pg_fatal("could not read WAL record at %X/%X",
 					 (uint32) (ptr >> 32), (uint32) (ptr));
 	}
 	endptr = xlogreader->EndRecPtr;
@@ -184,7 +184,7 @@ findLastCheckpoint(const char *datadir, XLogRecPtr forkptr, int tliIndex,
 	xlogreader = XLogReaderAllocate(WalSegSz, &SimpleXLogPageRead,
 									&private);
 	if (xlogreader == NULL)
-		pg_fatal("out of memory\n");
+		pg_fatal("out of memory");
 
 	searchptr = forkptr;
 	for (;;)
@@ -196,11 +196,11 @@ findLastCheckpoint(const char *datadir, XLogRecPtr forkptr, int tliIndex,
 		if (record == NULL)
 		{
 			if (errormsg)
-				pg_fatal("could not find previous WAL record at %X/%X: %s\n",
+				pg_fatal("could not find previous WAL record at %X/%X: %s",
 						 (uint32) (searchptr >> 32), (uint32) (searchptr),
 						 errormsg);
 			else
-				pg_fatal("could not find previous WAL record at %X/%X\n",
+				pg_fatal("could not find previous WAL record at %X/%X",
 						 (uint32) (searchptr >> 32), (uint32) (searchptr));
 		}
 
@@ -387,8 +387,8 @@ extractPageInfo(XLogReaderState *record)
 		 * we don't recognize the type. That's bad - we don't know how to
 		 * track that change.
 		 */
-		pg_fatal("WAL record modifies a relation, but record type is not recognized\n"
-				 "lsn: %X/%X, rmgr: %s, info: %02X\n",
+		pg_fatal("WAL record modifies a relation, but record type is not recognized: "
+				 "lsn: %X/%X, rmgr: %s, info: %02X",
 				 (uint32) (record->ReadRecPtr >> 32), (uint32) (record->ReadRecPtr),
 				 RmgrNames[rmid], info);
 	}
diff --git a/src/bin/pg_rewind/pg_rewind.c b/src/bin/pg_rewind/pg_rewind.c
index a0dfda701e..a77b19f607 100644
--- a/src/bin/pg_rewind/pg_rewind.c
+++ b/src/bin/pg_rewind/pg_rewind.c
@@ -27,6 +27,7 @@
 #include "common/file_perm.h"
 #include "common/file_utils.h"
 #include "common/restricted_token.h"
+#include "fe_utils/logging.h"
 #include "getopt_long.h"
 #include "storage/bufpage.h"
 
@@ -53,7 +54,7 @@ char	   *datadir_target = NULL;
 char	   *datadir_source = NULL;
 char	   *connstr_source = NULL;
 
-bool		debug = false;
+static bool	debug = false;
 bool		showprogress = false;
 bool		dry_run = false;
 bool		do_sync = true;
@@ -112,6 +113,8 @@ main(int argc, char **argv)
 	ControlFileData ControlFile_new;
 
 	set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_rewind"));
+	pg_logging_init(argv[0]);
+	pg_logging_set_level(PG_LOG_WARNING);
 	progname = get_progname(argv[0]);
 
 	/* Process command-line arguments */
@@ -139,6 +142,7 @@ main(int argc, char **argv)
 
 			case 'P':
 				showprogress = true;
+				pg_logging_set_level(PG_LOG_INFO);
 				break;
 
 			case 'n':
@@ -151,6 +155,7 @@ main(int argc, char **argv)
 
 			case 3:
 				debug = true;
+				pg_logging_set_level(PG_LOG_DEBUG);
 				break;
 
 			case 'D':			/* -D or --target-pgdata */
@@ -168,29 +173,29 @@ main(int argc, char **argv)
 
 	if (datadir_source == NULL && connstr_source == NULL)
 	{
-		fprintf(stderr, _("%s: no source specified (--source-pgdata or --source-server)\n"), progname);
+		pg_log_error("no source specified (--source-pgdata or --source-server)");
 		fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
 		exit(1);
 	}
 
 	if (datadir_source != NULL && connstr_source != NULL)
 	{
-		fprintf(stderr, _("%s: only one of --source-pgdata or --source-server can be specified\n"), progname);
+		pg_log_error("only one of --source-pgdata or --source-server can be specified");
 		fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
 		exit(1);
 	}
 
 	if (datadir_target == NULL)
 	{
-		fprintf(stderr, _("%s: no target data directory specified (--target-pgdata)\n"), progname);
+		pg_log_error("no target data directory specified (--target-pgdata)");
 		fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
 		exit(1);
 	}
 
 	if (optind < argc)
 	{
-		fprintf(stderr, _("%s: too many command-line arguments (first is \"%s\")\n"),
-				progname, argv[optind]);
+		pg_log_error("too many command-line arguments (first is \"%s\")",
+					 argv[optind]);
 		fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
 		exit(1);
 	}
@@ -204,20 +209,20 @@ main(int argc, char **argv)
 #ifndef WIN32
 	if (geteuid() == 0)
 	{
-		fprintf(stderr, _("cannot be executed by \"root\"\n"));
+		pg_log_error("cannot be executed by \"root\"");
 		fprintf(stderr, _("You must run %s as the PostgreSQL superuser.\n"),
 				progname);
 		exit(1);
 	}
 #endif
 
-	get_restricted_token(progname);
+	get_restricted_token();
 
 	/* Set mask based on PGDATA permissions */
 	if (!GetDataDirectoryCreatePerm(datadir_target))
 	{
-		fprintf(stderr, _("%s: could not read permissions of directory \"%s\": %s\n"),
-				progname, datadir_target, strerror(errno));
+		pg_log_error("could not read permissions of directory \"%s\": %m",
+					 datadir_target);
 		exit(1);
 	}
 
@@ -305,9 +310,9 @@ main(int argc, char **argv)
 	 * Build the filemap, by comparing the source and target data directories.
 	 */
 	filemap_create();
-	pg_log(PG_PROGRESS, "reading source file list\n");
+	pg_log_info("reading source file list");
 	fetchSourceFileList();
-	pg_log(PG_PROGRESS, "reading target file list\n");
+	pg_log_info("reading target file list");
 	traverse_datadir(datadir_target, &process_target_file);
 
 	/*
@@ -317,7 +322,7 @@ main(int argc, char **argv)
 	 * XXX: If we supported rewinding a server that was not shut down cleanly,
 	 * we would need to replay until the end of WAL here.
 	 */
-	pg_log(PG_PROGRESS, "reading WAL in target\n");
+	pg_log_info("reading WAL in target");
 	extractPageMap(datadir_target, chkptrec, lastcommontliIndex,
 				   ControlFile_target.checkPoint);
 	filemap_finalize();
@@ -334,7 +339,7 @@ main(int argc, char **argv)
 	 */
 	if (showprogress)
 	{
-		pg_log(PG_PROGRESS, "need to copy %lu MB (total source directory size is %lu MB)\n",
+		pg_log_info("need to copy %lu MB (total source directory size is %lu MB)",
 			   (unsigned long) (filemap->fetch_size / (1024 * 1024)),
 			   (unsigned long) (filemap->total_size / (1024 * 1024)));
 
@@ -350,8 +355,9 @@ main(int argc, char **argv)
 	executeFileMap();
 
 	progress_report(true);
+	printf("\n");
 
-	pg_log(PG_PROGRESS, "\ncreating backup label and updating control file\n");
+	pg_log_info("creating backup label and updating control file");
 	createBackupLabel(chkptredo, chkpttli, chkptrec);
 
 	/*
@@ -379,7 +385,7 @@ main(int argc, char **argv)
 	ControlFile_new.state = DB_IN_ARCHIVE_RECOVERY;
 	updateControlFile(&ControlFile_new);
 
-	pg_log(PG_PROGRESS, "syncing target data directory\n");
+	pg_log_info("syncing target data directory");
 	syncTargetDirectory(argv[0]);
 
 	printf(_("Done!\n"));
@@ -394,7 +400,7 @@ sanityChecks(void)
 
 	/* Check system_id match */
 	if (ControlFile_target.system_identifier != ControlFile_source.system_identifier)
-		pg_fatal("source and target clusters are from different systems\n");
+		pg_fatal("source and target clusters are from different systems");
 
 	/* check version */
 	if (ControlFile_target.pg_control_version != PG_CONTROL_VERSION ||
@@ -402,7 +408,7 @@ sanityChecks(void)
 		ControlFile_target.catalog_version_no != CATALOG_VERSION_NO ||
 		ControlFile_source.catalog_version_no != CATALOG_VERSION_NO)
 	{
-		pg_fatal("clusters are not compatible with this version of pg_rewind\n");
+		pg_fatal("clusters are not compatible with this version of pg_rewind");
 	}
 
 	/*
@@ -412,7 +418,7 @@ sanityChecks(void)
 	if (ControlFile_target.data_checksum_version != PG_DATA_CHECKSUM_VERSION &&
 		!ControlFile_target.wal_log_hints)
 	{
-		pg_fatal("target server needs to use either data checksums or \"wal_log_hints = on\"\n");
+		pg_fatal("target server needs to use either data checksums or \"wal_log_hints = on\"");
 	}
 
 	/*
@@ -423,7 +429,7 @@ sanityChecks(void)
 	 */
 	if (ControlFile_target.state != DB_SHUTDOWNED &&
 		ControlFile_target.state != DB_SHUTDOWNED_IN_RECOVERY)
-		pg_fatal("target server must be shut down cleanly\n");
+		pg_fatal("target server must be shut down cleanly");
 
 	/*
 	 * When the source is a data directory, also require that the source
@@ -433,7 +439,7 @@ sanityChecks(void)
 	if (datadir_source &&
 		ControlFile_source.state != DB_SHUTDOWNED &&
 		ControlFile_source.state != DB_SHUTDOWNED_IN_RECOVERY)
-		pg_fatal("source data directory must be shut down cleanly\n");
+		pg_fatal("source data directory must be shut down cleanly");
 }
 
 /*
@@ -499,9 +505,9 @@ getTimelineHistory(ControlFileData *controlFile, int *nentries)
 		int			i;
 
 		if (controlFile == &ControlFile_source)
-			pg_log(PG_DEBUG, "Source timeline history:\n");
+			pg_log_debug("Source timeline history:");
 		else if (controlFile == &ControlFile_target)
-			pg_log(PG_DEBUG, "Target timeline history:\n");
+			pg_log_debug("Target timeline history:");
 		else
 			Assert(false);
 
@@ -513,9 +519,7 @@ getTimelineHistory(ControlFileData *controlFile, int *nentries)
 			TimeLineHistoryEntry *entry;
 
 			entry = &history[i];
-			pg_log(PG_DEBUG,
-			/* translator: %d is a timeline number, others are LSN positions */
-				   "%d: %X/%X - %X/%X\n", entry->tli,
+			pg_log_debug("%d: %X/%X - %X/%X", entry->tli,
 				   (uint32) (entry->begin >> 32), (uint32) (entry->begin),
 				   (uint32) (entry->end >> 32), (uint32) (entry->end));
 		}
@@ -574,7 +578,7 @@ findCommonAncestorTimeline(XLogRecPtr *recptr, int *tliIndex)
 	}
 	else
 	{
-		pg_fatal("could not find common ancestor of the source and target cluster's timelines\n");
+		pg_fatal("could not find common ancestor of the source and target cluster's timelines");
 	}
 }
 
@@ -615,7 +619,7 @@ createBackupLabel(XLogRecPtr startpoint, TimeLineID starttli, XLogRecPtr checkpo
 				   (uint32) (checkpointloc >> 32), (uint32) checkpointloc,
 				   strfbuf);
 	if (len >= sizeof(buf))
-		pg_fatal("backup label buffer too small\n");	/* shouldn't happen */
+		pg_fatal("backup label buffer too small");	/* shouldn't happen */
 
 	/* TODO: move old file out of the way, if any. */
 	open_target_file("backup_label", true); /* BACKUP_LABEL_FILE */
@@ -638,7 +642,7 @@ checkControlFile(ControlFileData *ControlFile)
 
 	/* And simply compare it */
 	if (!EQ_CRC32C(crc, ControlFile->crc))
-		pg_fatal("unexpected control file CRC\n");
+		pg_fatal("unexpected control file CRC");
 }
 
 /*
@@ -648,7 +652,7 @@ static void
 digestControlFile(ControlFileData *ControlFile, char *src, size_t size)
 {
 	if (size != PG_CONTROL_FILE_SIZE)
-		pg_fatal("unexpected control file size %d, expected %d\n",
+		pg_fatal("unexpected control file size %d, expected %d",
 				 (int) size, PG_CONTROL_FILE_SIZE);
 
 	memcpy(ControlFile, src, sizeof(ControlFileData));
@@ -657,8 +661,8 @@ digestControlFile(ControlFileData *ControlFile, char *src, size_t size)
 	WalSegSz = ControlFile->xlog_seg_size;
 
 	if (!IsValidWalSegSize(WalSegSz))
-		pg_fatal(ngettext("WAL segment size must be a power of two between 1 MB and 1 GB, but the control file specifies %d byte\n",
-						  "WAL segment size must be a power of two between 1 MB and 1 GB, but the control file specifies %d bytes\n",
+		pg_fatal(ngettext("WAL segment size must be a power of two between 1 MB and 1 GB, but the control file specifies %d byte",
+						  "WAL segment size must be a power of two between 1 MB and 1 GB, but the control file specifies %d bytes",
 						  WalSegSz),
 				 WalSegSz);
 
@@ -720,5 +724,5 @@ syncTargetDirectory(const char *argv0)
 	if (!do_sync || dry_run)
 		return;
 
-	fsync_pgdata(datadir_target, progname, PG_VERSION_NUM);
+	fsync_pgdata(datadir_target, PG_VERSION_NUM);
 }
diff --git a/src/bin/pg_rewind/pg_rewind.h b/src/bin/pg_rewind/pg_rewind.h
index 83b2898b8b..f2cc2800aa 100644
--- a/src/bin/pg_rewind/pg_rewind.h
+++ b/src/bin/pg_rewind/pg_rewind.h
@@ -21,7 +21,6 @@
 extern char *datadir_target;
 extern char *datadir_source;
 extern char *connstr_source;
-extern bool debug;
 extern bool showprogress;
 extern bool dry_run;
 extern int	WalSegSz;
diff --git a/src/bin/pg_rewind/timeline.c b/src/bin/pg_rewind/timeline.c
index 1d343de52b..12b19b353c 100644
--- a/src/bin/pg_rewind/timeline.c
+++ b/src/bin/pg_rewind/timeline.c
@@ -13,6 +13,7 @@
 
 #include "access/timeline.h"
 #include "access/xlog_internal.h"
+#include "fe_utils/logging.h"
 
 /*
  * This is copy-pasted from the backend readTimeLineHistory, modified to
@@ -73,20 +74,20 @@ rewind_parseTimeLineHistory(char *buffer, TimeLineID targetTLI, int *nentries)
 		if (nfields < 1)
 		{
 			/* expect a numeric timeline ID as first field of line */
-			fprintf(stderr, _("syntax error in history file: %s\n"), fline);
-			fprintf(stderr, _("Expected a numeric timeline ID.\n"));
+			pg_log_error("syntax error in history file: %s", fline);
+			pg_log_error("Expected a numeric timeline ID.");
 			exit(1);
 		}
 		if (nfields != 3)
 		{
-			fprintf(stderr, _("syntax error in history file: %s\n"), fline);
-			fprintf(stderr, _("Expected a write-ahead log switchpoint location.\n"));
+			pg_log_error("syntax error in history file: %s", fline);
+			pg_log_error("Expected a write-ahead log switchpoint location.");
 			exit(1);
 		}
 		if (entries && tli <= lasttli)
 		{
-			fprintf(stderr, _("invalid data in history file: %s\n"), fline);
-			fprintf(stderr, _("Timeline IDs must be in increasing sequence.\n"));
+			pg_log_error("invalid data in history file: %s", fline);
+			pg_log_error("Timeline IDs must be in increasing sequence.");
 			exit(1);
 		}
 
@@ -106,8 +107,8 @@ rewind_parseTimeLineHistory(char *buffer, TimeLineID targetTLI, int *nentries)
 
 	if (entries && targetTLI <= lasttli)
 	{
-		fprintf(stderr, _("invalid data in history file\n"));
-		fprintf(stderr, _("Timeline IDs must be less than child timeline's ID.\n"));
+		pg_log_error("invalid data in history file");
+		pg_log_error("Timeline IDs must be less than child timeline's ID.");
 		exit(1);
 	}
 
diff --git a/src/bin/pg_test_fsync/Makefile b/src/bin/pg_test_fsync/Makefile
index 90496df566..769daecf2b 100644
--- a/src/bin/pg_test_fsync/Makefile
+++ b/src/bin/pg_test_fsync/Makefile
@@ -7,11 +7,13 @@ subdir = src/bin/pg_test_fsync
 top_builddir = ../../..
 include $(top_builddir)/src/Makefile.global
 
+LDFLAGS_INTERNAL += -L$(top_builddir)/src/fe_utils -lpgfeutils
+
 OBJS = pg_test_fsync.o $(WIN32RES)
 
 all: pg_test_fsync
 
-pg_test_fsync: $(OBJS) | submake-libpgport
+pg_test_fsync: $(OBJS) | submake-libpgport submake-libpgfeutils
 	$(CC) $(CFLAGS) $^ $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@$(X)
 
 install: all installdirs
diff --git a/src/bin/pg_test_fsync/pg_test_fsync.c b/src/bin/pg_test_fsync/pg_test_fsync.c
index e6f7ef8557..2c005a942a 100644
--- a/src/bin/pg_test_fsync/pg_test_fsync.c
+++ b/src/bin/pg_test_fsync/pg_test_fsync.c
@@ -14,6 +14,7 @@
 
 #include "getopt_long.h"
 #include "access/xlogdefs.h"
+#include "fe_utils/logging.h"
 
 
 /*
@@ -46,7 +47,7 @@ do { \
 	if (CreateThread(NULL, 0, process_alarm, NULL, 0, NULL) == \
 		INVALID_HANDLE_VALUE) \
 	{ \
-		fprintf(stderr, _("Could not create thread for alarm\n")); \
+		pg_log_error("could not create thread for alarm"); \
 		exit(1); \
 	} \
 	gettimeofday(&start_t, NULL); \
@@ -92,13 +93,15 @@ static void signal_cleanup(int sig);
 static int	pg_fsync_writethrough(int fd);
 #endif
 static void print_elapse(struct timeval start_t, struct timeval stop_t, int ops);
-static void die(const char *str);
+
+#define die(msg) do { pg_log_error("%s: %m", _(msg)); exit(1); } while(0)
 
 
 int
 main(int argc, char *argv[])
 {
 	set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_test_fsync"));
+	pg_logging_init(argv[0]);
 	progname = get_progname(argv[0]);
 
 	handle_args(argc, argv);
@@ -184,9 +187,8 @@ handle_args(int argc, char *argv[])
 
 	if (argc > optind)
 	{
-		fprintf(stderr,
-				_("%s: too many command-line arguments (first is \"%s\")\n"),
-				progname, argv[optind]);
+		pg_log_error("too many command-line arguments (first is \"%s\")",
+					 argv[optind]);
 		fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
 				progname);
 		exit(1);
@@ -601,10 +603,3 @@ process_alarm(LPVOID param)
 	ExitThread(0);
 }
 #endif
-
-static void
-die(const char *str)
-{
-	fprintf(stderr, _("%s: %s\n"), _(str), strerror(errno));
-	exit(1);
-}
diff --git a/src/bin/pg_upgrade/pg_upgrade.c b/src/bin/pg_upgrade/pg_upgrade.c
index 92d8940a9f..056b667ea4 100644
--- a/src/bin/pg_upgrade/pg_upgrade.c
+++ b/src/bin/pg_upgrade/pg_upgrade.c
@@ -41,6 +41,7 @@
 #include "catalog/pg_class_d.h"
 #include "common/file_perm.h"
 #include "common/restricted_token.h"
+#include "fe_utils/logging.h"
 #include "fe_utils/string_utils.h"
 
 #ifdef HAVE_LANGINFO_H
@@ -79,13 +80,14 @@ main(int argc, char **argv)
 	bool		live_check = false;
 
 	set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_upgrade"));
+	pg_logging_init(argv[0]);
 
 	/* Set default restrictive mask until new cluster permissions are read */
 	umask(PG_MODE_MASK_OWNER);
 
 	parseCommandLine(argc, argv);
 
-	get_restricted_token(os_info.progname);
+	get_restricted_token();
 
 	adjust_data_dir(&old_cluster);
 	adjust_data_dir(&new_cluster);
diff --git a/src/bin/pg_verify_checksums/Makefile b/src/bin/pg_verify_checksums/Makefile
index ab6d3ea9e2..27fa33aea4 100644
--- a/src/bin/pg_verify_checksums/Makefile
+++ b/src/bin/pg_verify_checksums/Makefile
@@ -15,11 +15,13 @@ subdir = src/bin/pg_verify_checksums
 top_builddir = ../../..
 include $(top_builddir)/src/Makefile.global
 
+LDFLAGS_INTERNAL += -L$(top_builddir)/src/fe_utils -lpgfeutils
+
 OBJS= pg_verify_checksums.o $(WIN32RES)
 
 all: pg_verify_checksums
 
-pg_verify_checksums: $(OBJS) | submake-libpgport
+pg_verify_checksums: $(OBJS) | submake-libpgport submake-libpgfeutils
 	$(CC) $(CFLAGS) $^ $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@$(X)
 
 install: all installdirs
diff --git a/src/bin/pg_verify_checksums/nls.mk b/src/bin/pg_verify_checksums/nls.mk
index 893efaf0f0..9e1fa99d3f 100644
--- a/src/bin/pg_verify_checksums/nls.mk
+++ b/src/bin/pg_verify_checksums/nls.mk
@@ -1,4 +1,6 @@
 # src/bin/pg_verify_checksums/nls.mk
 CATALOG_NAME     = pg_verify_checksums
 AVAIL_LANGUAGES  =
-GETTEXT_FILES    = pg_verify_checksums.c
+GETTEXT_FILES    = $(FRONTEND_COMMON_GETTEXT_FILES) pg_verify_checksums.c
+GETTEXT_TRIGGERS = $(FRONTEND_COMMON_GETTEXT_TRIGGERS)
+GETTEXT_FLAGS    = $(FRONTEND_COMMON_GETTEXT_FLAGS)
diff --git a/src/bin/pg_verify_checksums/pg_verify_checksums.c b/src/bin/pg_verify_checksums/pg_verify_checksums.c
index cc6ebb9df0..0a50097a26 100644
--- a/src/bin/pg_verify_checksums/pg_verify_checksums.c
+++ b/src/bin/pg_verify_checksums/pg_verify_checksums.c
@@ -15,6 +15,7 @@
 
 #include "catalog/pg_control.h"
 #include "common/controldata_utils.h"
+#include "fe_utils/logging.h"
 #include "getopt_long.h"
 #include "pg_getopt.h"
 #include "storage/bufpage.h"
@@ -90,8 +91,7 @@ scan_file(const char *fn, BlockNumber segmentno)
 	f = open(fn, O_RDONLY | PG_BINARY, 0);
 	if (f < 0)
 	{
-		fprintf(stderr, _("%s: could not open file \"%s\": %s\n"),
-				progname, fn, strerror(errno));
+		pg_log_error("could not open file \"%s\": %m", fn);
 		exit(1);
 	}
 
@@ -106,8 +106,8 @@ scan_file(const char *fn, BlockNumber segmentno)
 			break;
 		if (r != BLCKSZ)
 		{
-			fprintf(stderr, _("%s: could not read block %u in file \"%s\": read %d of %d\n"),
-					progname, blockno, fn, r, BLCKSZ);
+			pg_log_error("could not read block %u in file \"%s\": read %d of %d",
+						 blockno, fn, r, BLCKSZ);
 			exit(1);
 		}
 		blocks++;
@@ -120,15 +120,14 @@ scan_file(const char *fn, BlockNumber segmentno)
 		if (csum != header->pd_checksum)
 		{
 			if (ControlFile->data_checksum_version == PG_DATA_CHECKSUM_VERSION)
-				fprintf(stderr, _("%s: checksum verification failed in file \"%s\", block %u: calculated checksum %X but block contains %X\n"),
-						progname, fn, blockno, csum, header->pd_checksum);
+				pg_log_error("checksum verification failed in file \"%s\", block %u: calculated checksum %X but block contains %X",
+							 fn, blockno, csum, header->pd_checksum);
 			badblocks++;
 		}
 	}
 
 	if (verbose)
-		fprintf(stderr,
-				_("%s: checksums verified in file \"%s\"\n"), progname, fn);
+		pg_log_info("checksums verified in file \"%s\"", fn);
 
 	close(f);
 }
@@ -144,8 +143,7 @@ scan_directory(const char *basedir, const char *subdir)
 	dir = opendir(path);
 	if (!dir)
 	{
-		fprintf(stderr, _("%s: could not open directory \"%s\": %s\n"),
-				progname, path, strerror(errno));
+		pg_log_error("could not open directory \"%s\": %m", path);
 		exit(1);
 	}
 	while ((de = readdir(dir)) != NULL)
@@ -172,8 +170,7 @@ scan_directory(const char *basedir, const char *subdir)
 		snprintf(fn, sizeof(fn), "%s/%s", path, de->d_name);
 		if (lstat(fn, &st) < 0)
 		{
-			fprintf(stderr, _("%s: could not stat file \"%s\": %s\n"),
-					progname, fn, strerror(errno));
+			pg_log_error("could not stat file \"%s\": %m", fn);
 			exit(1);
 		}
 		if (S_ISREG(st.st_mode))
@@ -200,8 +197,8 @@ scan_directory(const char *basedir, const char *subdir)
 				segmentno = atoi(segmentpath);
 				if (segmentno == 0)
 				{
-					fprintf(stderr, _("%s: invalid segment number %d in file name \"%s\"\n"),
-							progname, segmentno, fn);
+					pg_log_error("invalid segment number %d in file name \"%s\"",
+								 segmentno, fn);
 					exit(1);
 				}
 			}
@@ -241,7 +238,7 @@ main(int argc, char *argv[])
 	bool		crc_ok;
 
 	set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_verify_checksums"));
-
+	pg_logging_init(argv[0]);
 	progname = get_progname(argv[0]);
 
 	if (argc > 1)
@@ -271,7 +268,7 @@ main(int argc, char *argv[])
 			case 'r':
 				if (atoi(optarg) == 0)
 				{
-					fprintf(stderr, _("%s: invalid relfilenode specification, must be numeric: %s\n"), progname, optarg);
+					pg_log_error("invalid relfilenode specification, must be numeric: %s", optarg);
 					exit(1);
 				}
 				only_relfilenode = pstrdup(optarg);
@@ -292,7 +289,7 @@ main(int argc, char *argv[])
 		/* If no DataDir was specified, and none could be found, error out */
 		if (DataDir == NULL)
 		{
-			fprintf(stderr, _("%s: no data directory specified\n"), progname);
+			pg_log_error("no data directory specified");
 			fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
 			exit(1);
 		}
@@ -301,31 +298,31 @@ main(int argc, char *argv[])
 	/* Complain if any arguments remain */
 	if (optind < argc)
 	{
-		fprintf(stderr, _("%s: too many command-line arguments (first is \"%s\")\n"),
-				progname, argv[optind]);
+		pg_log_error("too many command-line arguments (first is \"%s\")",
+					 argv[optind]);
 		fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
 				progname);
 		exit(1);
 	}
 
 	/* Check if cluster is running */
-	ControlFile = get_controlfile(DataDir, progname, &crc_ok);
+	ControlFile = get_controlfile(DataDir, &crc_ok);
 	if (!crc_ok)
 	{
-		fprintf(stderr, _("%s: pg_control CRC value is incorrect\n"), progname);
+		pg_log_error("pg_control CRC value is incorrect");
 		exit(1);
 	}
 
 	if (ControlFile->state != DB_SHUTDOWNED &&
 		ControlFile->state != DB_SHUTDOWNED_IN_RECOVERY)
 	{
-		fprintf(stderr, _("%s: cluster must be shut down to verify checksums\n"), progname);
+		pg_log_error("cluster must be shut down to verify checksums");
 		exit(1);
 	}
 
 	if (ControlFile->data_checksum_version == 0)
 	{
-		fprintf(stderr, _("%s: data checksums are not enabled in cluster\n"), progname);
+		pg_log_error("data checksums are not enabled in cluster");
 		exit(1);
 	}
 
diff --git a/src/bin/pg_waldump/Makefile b/src/bin/pg_waldump/Makefile
index f5957bd75a..bfe9498b80 100644
--- a/src/bin/pg_waldump/Makefile
+++ b/src/bin/pg_waldump/Makefile
@@ -11,6 +11,7 @@ OBJS = pg_waldump.o compat.o xlogreader.o rmgrdesc.o \
 	$(RMGRDESCOBJS) $(WIN32RES)
 
 override CPPFLAGS := -DFRONTEND $(CPPFLAGS)
+LDFLAGS_INTERNAL += -L$(top_builddir)/src/fe_utils -lpgfeutils
 
 RMGRDESCSOURCES = $(sort $(notdir $(wildcard $(top_srcdir)/src/backend/access/rmgrdesc/*desc.c)))
 RMGRDESCOBJS = $(patsubst %.c,%.o,$(RMGRDESCSOURCES))
@@ -18,7 +19,7 @@ RMGRDESCOBJS = $(patsubst %.c,%.o,$(RMGRDESCSOURCES))
 
 all: pg_waldump
 
-pg_waldump: $(OBJS) | submake-libpgport
+pg_waldump: $(OBJS) | submake-libpgport submake-libpgfeutils
 	$(CC) $(CFLAGS) $^ $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@$(X)
 
 xlogreader.c: % : $(top_srcdir)/src/backend/access/transam/%
diff --git a/src/bin/pg_waldump/nls.mk b/src/bin/pg_waldump/nls.mk
index c618f93145..2ee2da7901 100644
--- a/src/bin/pg_waldump/nls.mk
+++ b/src/bin/pg_waldump/nls.mk
@@ -1,6 +1,6 @@
 # src/bin/pg_waldump/nls.mk
 CATALOG_NAME     = pg_waldump
 AVAIL_LANGUAGES  = de es fr ja ko ru sv tr vi
-GETTEXT_FILES    = pg_waldump.c
-GETTEXT_TRIGGERS = fatal_error
-GETTEXT_FLAGS    = fatal_error:1:c-format
+GETTEXT_FILES    = $(FRONTEND_COMMON_GETTEXT_FILES) pg_waldump.c
+GETTEXT_TRIGGERS = $(FRONTEND_COMMON_GETTEXT_TRIGGERS) fatal_error
+GETTEXT_FLAGS    = $(FRONTEND_COMMON_GETTEXT_FLAGS) fatal_error:1:c-format
diff --git a/src/bin/pg_waldump/pg_waldump.c b/src/bin/pg_waldump/pg_waldump.c
index 1e5379eb3e..7091fff3c4 100644
--- a/src/bin/pg_waldump/pg_waldump.c
+++ b/src/bin/pg_waldump/pg_waldump.c
@@ -21,6 +21,7 @@
 #include "access/xlog_internal.h"
 #include "access/transam.h"
 #include "common/fe_memutils.h"
+#include "fe_utils/logging.h"
 #include "getopt_long.h"
 #include "rmgrdesc.h"
 
@@ -70,26 +71,7 @@ typedef struct XLogDumpStats
 	Stats		record_stats[RM_NEXT_ID][MAX_XLINFO_TYPES];
 } XLogDumpStats;
 
-static void fatal_error(const char *fmt,...) pg_attribute_printf(1, 2);
-
-/*
- * Big red button to push when things go horribly wrong.
- */
-static void
-fatal_error(const char *fmt,...)
-{
-	va_list		args;
-
-	fflush(stdout);
-
-	fprintf(stderr, _("%s: FATAL:  "), progname);
-	va_start(args, fmt);
-	vfprintf(stderr, _(fmt), args);
-	va_end(args);
-	fputc('\n', stderr);
-
-	exit(EXIT_FAILURE);
-}
+#define fatal_error(...) do { pg_log_error(__VA_ARGS__); exit(EXIT_FAILURE); } while(0)
 
 static void
 print_rmgr_list(void)
@@ -859,6 +841,7 @@ main(int argc, char **argv)
 	int			optindex = 0;
 
 	set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_waldump"));
+	pg_logging_init(argv[0]);
 	progname = get_progname(argv[0]);
 
 	memset(&private, 0, sizeof(XLogDumpPrivate));
@@ -882,7 +865,7 @@ main(int argc, char **argv)
 
 	if (argc <= 1)
 	{
-		fprintf(stderr, _("%s: no arguments specified\n"), progname);
+		pg_log_error("no arguments specified");
 		goto bad_argument;
 	}
 
@@ -897,8 +880,8 @@ main(int argc, char **argv)
 			case 'e':
 				if (sscanf(optarg, "%X/%X", &xlogid, &xrecoff) != 2)
 				{
-					fprintf(stderr, _("%s: could not parse end WAL location \"%s\"\n"),
-							progname, optarg);
+					pg_log_error("could not parse end WAL location \"%s\"",
+								 optarg);
 					goto bad_argument;
 				}
 				private.endptr = (uint64) xlogid << 32 | xrecoff;
@@ -913,8 +896,7 @@ main(int argc, char **argv)
 			case 'n':
 				if (sscanf(optarg, "%d", &config.stop_after_records) != 1)
 				{
-					fprintf(stderr, _("%s: could not parse limit \"%s\"\n"),
-							progname, optarg);
+					pg_log_error("could not parse limit \"%s\"", optarg);
 					goto bad_argument;
 				}
 				break;
@@ -942,8 +924,8 @@ main(int argc, char **argv)
 
 					if (config.filter_by_rmgr == -1)
 					{
-						fprintf(stderr, _("%s: resource manager \"%s\" does not exist\n"),
-								progname, optarg);
+						pg_log_error("resource manager \"%s\" does not exist",
+									 optarg);
 						goto bad_argument;
 					}
 				}
@@ -951,8 +933,8 @@ main(int argc, char **argv)
 			case 's':
 				if (sscanf(optarg, "%X/%X", &xlogid, &xrecoff) != 2)
 				{
-					fprintf(stderr, _("%s: could not parse start WAL location \"%s\"\n"),
-							progname, optarg);
+					pg_log_error("could not parse start WAL location \"%s\"",
+								 optarg);
 					goto bad_argument;
 				}
 				else
@@ -961,8 +943,7 @@ main(int argc, char **argv)
 			case 't':
 				if (sscanf(optarg, "%d", &private.timeline) != 1)
 				{
-					fprintf(stderr, _("%s: could not parse timeline \"%s\"\n"),
-							progname, optarg);
+					pg_log_error("could not parse timeline \"%s\"", optarg);
 					goto bad_argument;
 				}
 				break;
@@ -973,8 +954,8 @@ main(int argc, char **argv)
 			case 'x':
 				if (sscanf(optarg, "%u", &config.filter_by_xid) != 1)
 				{
-					fprintf(stderr, _("%s: could not parse \"%s\" as a transaction ID\n"),
-							progname, optarg);
+					pg_log_error("could not parse \"%s\" as a transaction ID",
+								 optarg);
 					goto bad_argument;
 				}
 				config.filter_by_xid_enabled = true;
@@ -988,8 +969,8 @@ main(int argc, char **argv)
 						config.stats_per_record = true;
 					else if (strcmp(optarg, "rmgr") != 0)
 					{
-						fprintf(stderr, _("%s: unrecognized argument to --stats: %s\n"),
-								progname, optarg);
+						pg_log_error("unrecognized argument to --stats: %s",
+									 optarg);
 						goto bad_argument;
 					}
 				}
@@ -1001,9 +982,8 @@ main(int argc, char **argv)
 
 	if ((optind + 2) < argc)
 	{
-		fprintf(stderr,
-				_("%s: too many command-line arguments (first is \"%s\")\n"),
-				progname, argv[optind + 2]);
+		pg_log_error("too many command-line arguments (first is \"%s\")",
+					 argv[optind + 2]);
 		goto bad_argument;
 	}
 
@@ -1012,9 +992,8 @@ main(int argc, char **argv)
 		/* validate path points to directory */
 		if (!verify_directory(private.inpath))
 		{
-			fprintf(stderr,
-					_("%s: path \"%s\" could not be opened: %s\n"),
-					progname, private.inpath, strerror(errno));
+			pg_log_error("path \"%s\" could not be opened: %s",
+						 private.inpath, strerror(errno));
 			goto bad_argument;
 		}
 	}
@@ -1051,9 +1030,7 @@ main(int argc, char **argv)
 			XLogSegNoOffsetToRecPtr(segno, 0, WalSegSz, private.startptr);
 		else if (!XLByteInSeg(private.startptr, segno, WalSegSz))
 		{
-			fprintf(stderr,
-					_("%s: start WAL location %X/%X is not inside file \"%s\"\n"),
-					progname,
+			pg_log_error("start WAL location %X/%X is not inside file \"%s\"",
 					(uint32) (private.startptr >> 32),
 					(uint32) private.startptr,
 					fname);
@@ -1096,9 +1073,7 @@ main(int argc, char **argv)
 		if (!XLByteInSeg(private.endptr, segno, WalSegSz) &&
 			private.endptr != (segno + 1) * WalSegSz)
 		{
-			fprintf(stderr,
-					_("%s: end WAL location %X/%X is not inside file \"%s\"\n"),
-					progname,
+			pg_log_error("end WAL location %X/%X is not inside file \"%s\"",
 					(uint32) (private.endptr >> 32),
 					(uint32) private.endptr,
 					argv[argc - 1]);
@@ -1111,7 +1086,7 @@ main(int argc, char **argv)
 	/* we don't know what to print */
 	if (XLogRecPtrIsInvalid(private.startptr))
 	{
-		fprintf(stderr, _("%s: no start WAL location given\n"), progname);
+		pg_log_error("no start WAL location given");
 		goto bad_argument;
 	}
 
diff --git a/src/bin/pgbench/pgbench.c b/src/bin/pgbench/pgbench.c
index 49670768f5..b3e86f7a5d 100644
--- a/src/bin/pgbench/pgbench.c
+++ b/src/bin/pgbench/pgbench.c
@@ -34,6 +34,7 @@
 #include "postgres_fe.h"
 #include "common/int.h"
 #include "fe_utils/conditional.h"
+#include "fe_utils/logging.h"
 #include "getopt_long.h"
 #include "libpq-fe.h"
 #include "portability/instr_time.h"
@@ -610,7 +611,6 @@ static void doLog(TState *thread, CState *st,
 	  StatsData *agg, bool skipped, double latency, double lag);
 static void processXactStats(TState *thread, CState *st, instr_time *now,
 				 bool skipped, StatsData *agg);
-static void pgbench_error(const char *fmt,...) pg_attribute_printf(1, 2);
 static void allocate_command_varprefix(Command *cmd, int totalqueries);
 static void addScript(ParsedScript script);
 static void *threadRun(void *arg);
@@ -627,7 +627,6 @@ static bool socket_has_input(socket_set *sa, int fd, int idx);
 /* callback functions for our flex lexer */
 static const PsqlScanCallbacks pgbench_callbacks = {
 	NULL,						/* don't need get_variable functionality */
-	pgbench_error
 };
 
 
@@ -4139,20 +4138,6 @@ parseQuery(Command *cmd)
 	return true;
 }
 
-/*
- * Simple error-printing function, might be needed by lexer
- */
-static void
-pgbench_error(const char *fmt,...)
-{
-	va_list		ap;
-
-	fflush(stdout);
-	va_start(ap, fmt);
-	vfprintf(stderr, _(fmt), ap);
-	va_end(ap);
-}
-
 /*
  * syntax error while parsing a script (in practice, while parsing a
  * backslash command, because we don't detect syntax errors in SQL)
@@ -5254,6 +5239,7 @@ main(int argc, char **argv)
 	int			exit_code = 0;
 
 	progname = get_progname(argv[0]);
+	pg_logging_init(argv[0]);
 
 	if (argc > 1)
 	{
diff --git a/src/bin/psql/command.c b/src/bin/psql/command.c
index cbe5e518c9..06cfec3f5f 100644
--- a/src/bin/psql/command.c
+++ b/src/bin/psql/command.c
@@ -28,6 +28,7 @@
 
 #include "libpq-fe.h"
 #include "pqexpbuffer.h"
+#include "fe_utils/logging.h"
 #include "fe_utils/string_utils.h"
 
 #include "common.h"
@@ -216,10 +217,9 @@ HandleSlashCmds(PsqlScanState scan_state,
 
 	if (status == PSQL_CMD_UNKNOWN)
 	{
+		pg_log_error("invalid command \\%s", cmd);
 		if (pset.cur_cmd_interactive)
-			psql_error("Invalid command \\%s. Try \\? for help.\n", cmd);
-		else
-			psql_error("invalid command \\%s\n", cmd);
+			pg_log_info("Try \\? for help.");
 		status = PSQL_CMD_ERROR;
 	}
 
@@ -237,7 +237,7 @@ HandleSlashCmds(PsqlScanState scan_state,
 											 OT_NORMAL, NULL, false)))
 		{
 			if (active_branch)
-				psql_error("\\%s: extra argument \"%s\" ignored\n", cmd, arg);
+				pg_log_warning("\\%s: extra argument \"%s\" ignored", cmd, arg);
 			free(arg);
 		}
 		conditional_stack_pop(cstack);
@@ -289,7 +289,7 @@ exec_command(const char *cmd,
 	if (pset.cur_cmd_interactive && !active_branch &&
 		!is_branching_command(cmd))
 	{
-		psql_error("\\%s command ignored; use \\endif or Ctrl-C to exit current \\if block\n",
+		pg_log_warning("\\%s command ignored; use \\endif or Ctrl-C to exit current \\if block",
 				   cmd);
 	}
 
@@ -549,7 +549,7 @@ exec_command_cd(PsqlScanState scan_state, bool active_branch, const char *cmd)
 			pw = getpwuid(user_id);
 			if (!pw)
 			{
-				psql_error("could not get home directory for user ID %ld: %s\n",
+				pg_log_error("could not get home directory for user ID %ld: %s",
 						   (long) user_id,
 						   errno ? strerror(errno) : _("user does not exist"));
 				exit(EXIT_FAILURE);
@@ -567,8 +567,8 @@ exec_command_cd(PsqlScanState scan_state, bool active_branch, const char *cmd)
 
 		if (chdir(dir) == -1)
 		{
-			psql_error("\\%s: could not change directory to \"%s\": %s\n",
-					   cmd, dir, strerror(errno));
+			pg_log_error("\\%s: could not change directory to \"%s\": %m",
+						 cmd, dir);
 			success = false;
 		}
 
@@ -908,7 +908,7 @@ exec_command_edit(PsqlScanState scan_state, bool active_branch,
 	{
 		if (!query_buf)
 		{
-			psql_error("no query buffer\n");
+			pg_log_error("no query buffer");
 			status = PSQL_CMD_ERROR;
 		}
 		else
@@ -941,7 +941,7 @@ exec_command_edit(PsqlScanState scan_state, bool active_branch,
 				lineno = atoi(ln);
 				if (lineno < 1)
 				{
-					psql_error("invalid line number: %s\n", ln);
+					pg_log_error("invalid line number: %s", ln);
 					status = PSQL_CMD_ERROR;
 				}
 			}
@@ -995,16 +995,16 @@ exec_command_ef_ev(PsqlScanState scan_state, bool active_branch,
 			formatPGVersionNumber(pset.sversion, false,
 								  sverbuf, sizeof(sverbuf));
 			if (is_func)
-				psql_error("The server (version %s) does not support editing function source.\n",
+				pg_log_error("The server (version %s) does not support editing function source.",
 						   sverbuf);
 			else
-				psql_error("The server (version %s) does not support editing view definitions.\n",
+				pg_log_error("The server (version %s) does not support editing view definitions.",
 						   sverbuf);
 			status = PSQL_CMD_ERROR;
 		}
 		else if (!query_buf)
 		{
-			psql_error("no query buffer\n");
+			pg_log_error("no query buffer");
 			status = PSQL_CMD_ERROR;
 		}
 		else
@@ -1157,7 +1157,7 @@ exec_command_encoding(PsqlScanState scan_state, bool active_branch)
 		{
 			/* set encoding */
 			if (PQsetClientEncoding(pset.db, encoding) == -1)
-				psql_error("%s: invalid encoding name or conversion procedure not found\n", encoding);
+				pg_log_error("%s: invalid encoding name or conversion procedure not found", encoding);
 			else
 			{
 				/* save encoding info into psql internal data */
@@ -1192,7 +1192,7 @@ exec_command_errverbose(PsqlScanState scan_state, bool active_branch)
 											  PQSHOW_CONTEXT_ALWAYS);
 			if (msg)
 			{
-				psql_error("%s", msg);
+				pg_log_error("%s", msg);
 				PQfreemem(msg);
 			}
 			else
@@ -1387,7 +1387,7 @@ exec_command_include(PsqlScanState scan_state, bool active_branch, const char *c
 
 		if (!fname)
 		{
-			psql_error("\\%s: missing required argument\n", cmd);
+			pg_log_error("\\%s: missing required argument", cmd);
 			success = false;
 		}
 		else
@@ -1518,12 +1518,12 @@ exec_command_elif(PsqlScanState scan_state, ConditionalStack cstack,
 			break;
 		case IFSTATE_ELSE_TRUE:
 		case IFSTATE_ELSE_FALSE:
-			psql_error("\\elif: cannot occur after \\else\n");
+			pg_log_error("\\elif: cannot occur after \\else");
 			success = false;
 			break;
 		case IFSTATE_NONE:
 			/* no \if to elif from */
-			psql_error("\\elif: no matching \\if\n");
+			pg_log_error("\\elif: no matching \\if");
 			success = false;
 			break;
 	}
@@ -1587,12 +1587,12 @@ exec_command_else(PsqlScanState scan_state, ConditionalStack cstack,
 			break;
 		case IFSTATE_ELSE_TRUE:
 		case IFSTATE_ELSE_FALSE:
-			psql_error("\\else: cannot occur after \\else\n");
+			pg_log_error("\\else: cannot occur after \\else");
 			success = false;
 			break;
 		case IFSTATE_NONE:
 			/* no \if to else from */
-			psql_error("\\else: no matching \\if\n");
+			pg_log_error("\\else: no matching \\if");
 			success = false;
 			break;
 	}
@@ -1632,7 +1632,7 @@ exec_command_endif(PsqlScanState scan_state, ConditionalStack cstack,
 			break;
 		case IFSTATE_NONE:
 			/* no \if to end */
-			psql_error("\\endif: no matching \\if\n");
+			pg_log_error("\\endif: no matching \\if");
 			success = false;
 			break;
 	}
@@ -1692,7 +1692,7 @@ exec_command_lo(PsqlScanState scan_state, bool active_branch, const char *cmd)
 		{
 			if (!opt2)
 			{
-				psql_error("\\%s: missing required argument\n", cmd);
+				pg_log_error("\\%s: missing required argument", cmd);
 				success = false;
 			}
 			else
@@ -1706,7 +1706,7 @@ exec_command_lo(PsqlScanState scan_state, bool active_branch, const char *cmd)
 		{
 			if (!opt1)
 			{
-				psql_error("\\%s: missing required argument\n", cmd);
+				pg_log_error("\\%s: missing required argument", cmd);
 				success = false;
 			}
 			else
@@ -1723,7 +1723,7 @@ exec_command_lo(PsqlScanState scan_state, bool active_branch, const char *cmd)
 		{
 			if (!opt1)
 			{
-				psql_error("\\%s: missing required argument\n", cmd);
+				pg_log_error("\\%s: missing required argument", cmd);
 				success = false;
 			}
 			else
@@ -1814,7 +1814,7 @@ exec_command_password(PsqlScanState scan_state, bool active_branch)
 
 		if (strcmp(pw1, pw2) != 0)
 		{
-			psql_error("Passwords didn't match.\n");
+			pg_log_error("Passwords didn't match.");
 			success = false;
 		}
 		else
@@ -1831,7 +1831,7 @@ exec_command_password(PsqlScanState scan_state, bool active_branch)
 
 			if (!encrypted_password)
 			{
-				psql_error("%s", PQerrorMessage(pset.db));
+				pg_log_error("%s", PQerrorMessage(pset.db));
 				success = false;
 			}
 			else
@@ -1883,7 +1883,7 @@ exec_command_prompt(PsqlScanState scan_state, bool active_branch,
 
 		if (!arg1)
 		{
-			psql_error("\\%s: missing required argument\n", cmd);
+			pg_log_error("\\%s: missing required argument", cmd);
 			success = false;
 		}
 		else
@@ -1913,7 +1913,7 @@ exec_command_prompt(PsqlScanState scan_state, bool active_branch,
 				result = gets_fromFile(stdin);
 				if (!result)
 				{
-					psql_error("\\%s: could not read value for variable\n",
+					pg_log_error("\\%s: could not read value for variable",
 							   cmd);
 					success = false;
 				}
@@ -2120,12 +2120,12 @@ exec_command_setenv(PsqlScanState scan_state, bool active_branch,
 
 		if (!envvar)
 		{
-			psql_error("\\%s: missing required argument\n", cmd);
+			pg_log_error("\\%s: missing required argument", cmd);
 			success = false;
 		}
 		else if (strchr(envvar, '=') != NULL)
 		{
-			psql_error("\\%s: environment variable name must not contain \"=\"\n",
+			pg_log_error("\\%s: environment variable name must not contain \"=\"",
 					   cmd);
 			success = false;
 		}
@@ -2186,19 +2186,19 @@ exec_command_sf_sv(PsqlScanState scan_state, bool active_branch,
 			formatPGVersionNumber(pset.sversion, false,
 								  sverbuf, sizeof(sverbuf));
 			if (is_func)
-				psql_error("The server (version %s) does not support showing function source.\n",
+				pg_log_error("The server (version %s) does not support showing function source.",
 						   sverbuf);
 			else
-				psql_error("The server (version %s) does not support showing view definitions.\n",
+				pg_log_error("The server (version %s) does not support showing view definitions.",
 						   sverbuf);
 			status = PSQL_CMD_ERROR;
 		}
 		else if (!obj_desc)
 		{
 			if (is_func)
-				psql_error("function name is required\n");
+				pg_log_error("function name is required");
 			else
-				psql_error("view name is required\n");
+				pg_log_error("view name is required");
 			status = PSQL_CMD_ERROR;
 		}
 		else if (!lookup_object_oid(eot, obj_desc, &obj_oid))
@@ -2356,7 +2356,7 @@ exec_command_unset(PsqlScanState scan_state, bool active_branch,
 
 		if (!opt)
 		{
-			psql_error("\\%s: missing required argument\n", cmd);
+			pg_log_error("\\%s: missing required argument", cmd);
 			success = false;
 		}
 		else if (!SetVariable(pset.vars, opt, NULL))
@@ -2389,14 +2389,14 @@ exec_command_write(PsqlScanState scan_state, bool active_branch,
 
 		if (!query_buf)
 		{
-			psql_error("no query buffer\n");
+			pg_log_error("no query buffer");
 			status = PSQL_CMD_ERROR;
 		}
 		else
 		{
 			if (!fname)
 			{
-				psql_error("\\%s: missing required argument\n", cmd);
+				pg_log_error("\\%s: missing required argument", cmd);
 				status = PSQL_CMD_ERROR;
 			}
 			else
@@ -2415,7 +2415,7 @@ exec_command_write(PsqlScanState scan_state, bool active_branch,
 				}
 				if (!fd)
 				{
-					psql_error("%s: %s\n", fname, strerror(errno));
+					pg_log_error("%s: %m", fname);
 					status = PSQL_CMD_ERROR;
 				}
 			}
@@ -2443,7 +2443,7 @@ exec_command_write(PsqlScanState scan_state, bool active_branch,
 
 			if (result == EOF)
 			{
-				psql_error("%s: %s\n", fname, strerror(errno));
+				pg_log_error("%s: %m", fname);
 				status = PSQL_CMD_ERROR;
 			}
 		}
@@ -2883,8 +2883,8 @@ do_connect(enum trivalue reuse_previous_specification,
 		 * connect to the wrong database by using defaults, so require all
 		 * parameters to be specified.
 		 */
-		psql_error("All connection parameters must be supplied because no "
-				   "database connection exists\n");
+		pg_log_error("All connection parameters must be supplied because no "
+					 "database connection exists");
 		return false;
 	}
 
@@ -3067,15 +3067,15 @@ do_connect(enum trivalue reuse_previous_specification,
 		 */
 		if (pset.cur_cmd_interactive)
 		{
-			psql_error("%s", PQerrorMessage(n_conn));
+			pg_log_error("%s", PQerrorMessage(n_conn));
 
 			/* pset.db is left unmodified */
 			if (o_conn)
-				psql_error("Previous connection kept\n");
+				pg_log_error("Previous connection kept");
 		}
 		else
 		{
-			psql_error("\\connect: %s", PQerrorMessage(n_conn));
+			pg_log_error("\\connect: %s", PQerrorMessage(n_conn));
 			if (o_conn)
 			{
 				PQfinish(o_conn);
@@ -3337,7 +3337,7 @@ editFile(const char *fname, int lineno)
 #endif
 		if (!editor_lineno_arg)
 		{
-			psql_error("environment variable PSQL_EDITOR_LINENUMBER_ARG must be set to specify a line number\n");
+			pg_log_error("environment variable PSQL_EDITOR_LINENUMBER_ARG must be set to specify a line number");
 			return false;
 		}
 	}
@@ -3366,9 +3366,9 @@ editFile(const char *fname, int lineno)
 #endif
 	result = system(sys);
 	if (result == -1)
-		psql_error("could not start editor \"%s\"\n", editorName);
+		pg_log_error("could not start editor \"%s\"", editorName);
 	else if (result == 127)
-		psql_error("could not start /bin/sh\n");
+		pg_log_error("could not start /bin/sh");
 	free(sys);
 
 	return result == 0;
@@ -3406,7 +3406,7 @@ do_edit(const char *filename_arg, PQExpBuffer query_buf,
 		ret = GetTempPath(MAXPGPATH, tmpdir);
 		if (ret == 0 || ret > MAXPGPATH)
 		{
-			psql_error("could not locate temporary directory: %s\n",
+			pg_log_error("could not locate temporary directory: %s",
 					   !ret ? strerror(errno) : "");
 			return false;
 		}
@@ -3433,7 +3433,7 @@ do_edit(const char *filename_arg, PQExpBuffer query_buf,
 
 		if (fd == -1 || !stream)
 		{
-			psql_error("could not open temporary file \"%s\": %s\n", fname, strerror(errno));
+			pg_log_error("could not open temporary file \"%s\": %m", fname);
 			error = true;
 		}
 		else
@@ -3448,21 +3448,21 @@ do_edit(const char *filename_arg, PQExpBuffer query_buf,
 
 			if (fwrite(query_buf->data, 1, ql, stream) != ql)
 			{
-				psql_error("%s: %s\n", fname, strerror(errno));
+				pg_log_error("%s: %m", fname);
 
 				if (fclose(stream) != 0)
-					psql_error("%s: %s\n", fname, strerror(errno));
+					pg_log_error("%s: %m", fname);
 
 				if (remove(fname) != 0)
-					psql_error("%s: %s\n", fname, strerror(errno));
+					pg_log_error("%s: %m", fname);
 
 				error = true;
 			}
 			else if (fclose(stream) != 0)
 			{
-				psql_error("%s: %s\n", fname, strerror(errno));
+				pg_log_error("%s: %m", fname);
 				if (remove(fname) != 0)
-					psql_error("%s: %s\n", fname, strerror(errno));
+					pg_log_error("%s: %m", fname);
 				error = true;
 			}
 		}
@@ -3470,7 +3470,7 @@ do_edit(const char *filename_arg, PQExpBuffer query_buf,
 
 	if (!error && stat(fname, &before) != 0)
 	{
-		psql_error("%s: %s\n", fname, strerror(errno));
+		pg_log_error("%s: %m", fname);
 		error = true;
 	}
 
@@ -3480,7 +3480,7 @@ do_edit(const char *filename_arg, PQExpBuffer query_buf,
 
 	if (!error && stat(fname, &after) != 0)
 	{
-		psql_error("%s: %s\n", fname, strerror(errno));
+		pg_log_error("%s: %m", fname);
 		error = true;
 	}
 
@@ -3489,7 +3489,7 @@ do_edit(const char *filename_arg, PQExpBuffer query_buf,
 		stream = fopen(fname, PG_BINARY_R);
 		if (!stream)
 		{
-			psql_error("%s: %s\n", fname, strerror(errno));
+			pg_log_error("%s: %m", fname);
 			error = true;
 		}
 		else
@@ -3503,7 +3503,7 @@ do_edit(const char *filename_arg, PQExpBuffer query_buf,
 
 			if (ferror(stream))
 			{
-				psql_error("%s: %s\n", fname, strerror(errno));
+				pg_log_error("%s: %m", fname);
 				error = true;
 			}
 			else if (edited)
@@ -3520,7 +3520,7 @@ do_edit(const char *filename_arg, PQExpBuffer query_buf,
 	{
 		if (remove(fname) == -1)
 		{
-			psql_error("%s: %s\n", fname, strerror(errno));
+			pg_log_error("%s: %m", fname);
 			error = true;
 		}
 	}
@@ -3578,7 +3578,7 @@ process_file(char *filename, bool use_relative_path)
 
 		if (!fd)
 		{
-			psql_error("%s: %s\n", filename, strerror(errno));
+			pg_log_error("%s: %m", filename);
 			return EXIT_FAILURE;
 		}
 	}
@@ -3591,12 +3591,17 @@ process_file(char *filename, bool use_relative_path)
 	oldfilename = pset.inputfile;
 	pset.inputfile = filename;
 
+	pg_logging_config(pset.inputfile ? 0 : PG_LOG_FLAG_TERSE);
+
 	result = MainLoop(fd);
 
 	if (fd != stdin)
 		fclose(fd);
 
 	pset.inputfile = oldfilename;
+
+	pg_logging_config(pset.inputfile ? 0 : PG_LOG_FLAG_TERSE);
+
 	return result;
 }
 
@@ -3721,7 +3726,7 @@ do_pset(const char *param, const char *value, printQueryOpt *popt, bool quiet)
 						match_pos = i;
 					else
 					{
-						psql_error("\\pset: ambiguous abbreviation \"%s\" matches both \"%s\" and \"%s\"\n",
+						pg_log_error("\\pset: ambiguous abbreviation \"%s\" matches both \"%s\" and \"%s\"",
 								   value,
 								   formats[match_pos].name, formats[i].name);
 						return false;
@@ -3741,7 +3746,7 @@ do_pset(const char *param, const char *value, printQueryOpt *popt, bool quiet)
 			}
 			else
 			{
-				psql_error("\\pset: allowed formats are aligned, asciidoc, csv, html, latex, latex-longtable, troff-ms, unaligned, wrapped\n");
+				pg_log_error("\\pset: allowed formats are aligned, asciidoc, csv, html, latex, latex-longtable, troff-ms, unaligned, wrapped");
 				return false;
 			}
 		}
@@ -3760,7 +3765,7 @@ do_pset(const char *param, const char *value, printQueryOpt *popt, bool quiet)
 			popt->topt.line_style = &pg_utf8format;
 		else
 		{
-			psql_error("\\pset: allowed line styles are ascii, old-ascii, unicode\n");
+			pg_log_error("\\pset: allowed line styles are ascii, old-ascii, unicode");
 			return false;
 		}
 	}
@@ -3775,7 +3780,7 @@ do_pset(const char *param, const char *value, printQueryOpt *popt, bool quiet)
 			refresh_utf8format(&(popt->topt));
 		else
 		{
-			psql_error("\\pset: allowed Unicode border line styles are single, double\n");
+			pg_log_error("\\pset: allowed Unicode border line styles are single, double");
 			return false;
 		}
 	}
@@ -3790,7 +3795,7 @@ do_pset(const char *param, const char *value, printQueryOpt *popt, bool quiet)
 			refresh_utf8format(&(popt->topt));
 		else
 		{
-			psql_error("\\pset: allowed Unicode column line styles are single, double\n");
+			pg_log_error("\\pset: allowed Unicode column line styles are single, double");
 			return false;
 		}
 	}
@@ -3805,7 +3810,7 @@ do_pset(const char *param, const char *value, printQueryOpt *popt, bool quiet)
 			refresh_utf8format(&(popt->topt));
 		else
 		{
-			psql_error("\\pset: allowed Unicode header line styles are single, double\n");
+			pg_log_error("\\pset: allowed Unicode header line styles are single, double");
 			return false;
 		}
 	}
@@ -3848,12 +3853,12 @@ do_pset(const char *param, const char *value, printQueryOpt *popt, bool quiet)
 			/* CSV separator has to be a one-byte character */
 			if (strlen(value) != 1)
 			{
-				psql_error("\\pset: csv_fieldsep must be a single one-byte character\n");
+				pg_log_error("\\pset: csv_fieldsep must be a single one-byte character");
 				return false;
 			}
 			if (value[0] == '"' || value[0] == '\n' || value[0] == '\r')
 			{
-				psql_error("\\pset: csv_fieldsep cannot be a double quote, a newline, or a carriage return\n");
+				pg_log_error("\\pset: csv_fieldsep cannot be a double quote, a newline, or a carriage return");
 				return false;
 			}
 			popt->topt.csvFieldSep[0] = value[0];
@@ -3990,7 +3995,7 @@ do_pset(const char *param, const char *value, printQueryOpt *popt, bool quiet)
 	}
 	else
 	{
-		psql_error("\\pset: unknown option: %s\n", param);
+		pg_log_error("\\pset: unknown option: %s", param);
 		return false;
 	}
 
@@ -4176,7 +4181,7 @@ printPsetInfo(const char *param, struct printQueryOpt *popt)
 
 	else
 	{
-		psql_error("\\pset: unknown option: %s\n", param);
+		pg_log_error("\\pset: unknown option: %s", param);
 		return false;
 	}
 
@@ -4332,7 +4337,7 @@ do_shell(const char *command)
 
 	if (result == 127 || result == -1)
 	{
-		psql_error("\\!: failed\n");
+		pg_log_error("\\!: failed");
 		return false;
 	}
 	return true;
@@ -4357,7 +4362,7 @@ do_watch(PQExpBuffer query_buf, double sleep)
 
 	if (!query_buf || query_buf->len <= 0)
 	{
-		psql_error("\\watch cannot be used with an empty query\n");
+		pg_log_error("\\watch cannot be used with an empty query");
 		return false;
 	}
 
@@ -4654,7 +4659,7 @@ get_create_object_cmd(EditableObjectType obj_type, Oid oid,
 							appendPQExpBufferStr(buf, "CREATE OR REPLACE VIEW ");
 							break;
 						default:
-							psql_error("\"%s.%s\" is not a view\n",
+							pg_log_error("\"%s.%s\" is not a view",
 									   nspname, relname);
 							result = false;
 							break;
@@ -4670,7 +4675,7 @@ get_create_object_cmd(EditableObjectType obj_type, Oid oid,
 												   pset.encoding,
 												   standard_strings()))
 						{
-							psql_error("could not parse reloptions array\n");
+							pg_log_error("could not parse reloptions array");
 							result = false;
 						}
 						appendPQExpBufferChar(buf, ')');
@@ -4759,7 +4764,7 @@ strip_lineno_from_objdesc(char *obj)
 	lineno = atoi(c);
 	if (lineno < 1)
 	{
-		psql_error("invalid line number: %s\n", c);
+		pg_log_error("invalid line number: %s", c);
 		return 0;
 	}
 
@@ -4861,7 +4866,7 @@ minimal_error_message(PGresult *res)
 		appendPQExpBufferStr(msg, "(not available)");
 	appendPQExpBufferChar(msg, '\n');
 
-	psql_error("%s", msg->data);
+	pg_log_error("%s", msg->data);
 
 	destroyPQExpBuffer(msg);
 }
diff --git a/src/bin/psql/common.c b/src/bin/psql/common.c
index b11d7ac6ce..6df17d3678 100644
--- a/src/bin/psql/common.c
+++ b/src/bin/psql/common.c
@@ -19,6 +19,7 @@
 #include <win32.h>
 #endif
 
+#include "fe_utils/logging.h"
 #include "fe_utils/string_utils.h"
 #include "portability/instr_time.h"
 
@@ -67,7 +68,7 @@ openQueryOutputFile(const char *fname, FILE **fout, bool *is_pipe)
 
 	if (*fout == NULL)
 	{
-		psql_error("%s: %s\n", fname, strerror(errno));
+		pg_log_error("%s: %m", fname);
 		return false;
 	}
 
@@ -156,7 +157,7 @@ psql_get_variable(const char *varname, PsqlScanQuoteType quote,
 
 				if (!pset.db)
 				{
-					psql_error("cannot escape without active connection\n");
+					pg_log_error("cannot escape without active connection");
 					return NULL;
 				}
 
@@ -171,7 +172,7 @@ psql_get_variable(const char *varname, PsqlScanQuoteType quote,
 				{
 					const char *error = PQerrorMessage(pset.db);
 
-					psql_error("%s", error);
+					pg_log_error("%s", error);
 					return NULL;
 				}
 
@@ -197,7 +198,7 @@ psql_get_variable(const char *varname, PsqlScanQuoteType quote,
 				initPQExpBuffer(&buf);
 				if (!appendShellStringNoError(&buf, value))
 				{
-					psql_error("shell command argument contains a newline or carriage return: \"%s\"\n",
+					pg_log_error("shell command argument contains a newline or carriage return: \"%s\"",
 							   value);
 					free(buf.data);
 					return NULL;
@@ -213,28 +214,6 @@ psql_get_variable(const char *varname, PsqlScanQuoteType quote,
 }
 
 
-/*
- * Error reporting for scripts. Errors should look like
- *	 psql:filename:lineno: message
- */
-void
-psql_error(const char *fmt,...)
-{
-	va_list		ap;
-
-	fflush(stdout);
-	if (pset.queryFout && pset.queryFout != stdout)
-		fflush(pset.queryFout);
-
-	if (pset.inputfile)
-		fprintf(stderr, "%s:%s:" UINT64_FORMAT ": ", pset.progname, pset.inputfile, pset.lineno);
-	va_start(ap, fmt);
-	vfprintf(stderr, _(fmt), ap);
-	va_end(ap);
-}
-
-
-
 /*
  * for backend Notice messages (INFO, WARNING, etc)
  */
@@ -242,7 +221,7 @@ void
 NoticeProcessor(void *arg, const char *message)
 {
 	(void) arg;					/* not used */
-	psql_error("%s", message);
+	pg_log_info("%s", message);
 }
 
 
@@ -413,23 +392,23 @@ CheckConnection(void)
 	{
 		if (!pset.cur_cmd_interactive)
 		{
-			psql_error("connection to server was lost\n");
+			pg_log_fatal("connection to server was lost");
 			exit(EXIT_BADCONN);
 		}
 
-		psql_error("The connection to the server was lost. Attempting reset: ");
+		fprintf(stderr, _("The connection to the server was lost. Attempting reset: "));
 		PQreset(pset.db);
 		OK = ConnectionUp();
 		if (!OK)
 		{
-			psql_error("Failed.\n");
+			fprintf(stderr, _("Failed.\n"));
 			PQfinish(pset.db);
 			pset.db = NULL;
 			ResetCancelConn();
 			UnsyncVariables();
 		}
 		else
-			psql_error("Succeeded.\n");
+			fprintf(stderr, _("Succeeded.\n"));
 	}
 
 	return OK;
@@ -529,7 +508,7 @@ AcceptResult(const PGresult *result)
 
 			default:
 				OK = false;
-				psql_error("unexpected PQresultStatus: %d\n",
+				pg_log_error("unexpected PQresultStatus: %d",
 						   PQresultStatus(result));
 				break;
 		}
@@ -539,7 +518,7 @@ AcceptResult(const PGresult *result)
 		const char *error = PQerrorMessage(pset.db);
 
 		if (strlen(error))
-			psql_error("%s", error);
+			pg_log_error("%s", error);
 
 		CheckConnection();
 	}
@@ -693,7 +672,7 @@ PSQLexec(const char *query)
 
 	if (!pset.db)
 	{
-		psql_error("You are currently not connected to a database.\n");
+		pg_log_error("You are currently not connected to a database.");
 		return NULL;
 	}
 
@@ -751,7 +730,7 @@ PSQLexecWatch(const char *query, const printQueryOpt *opt)
 
 	if (!pset.db)
 	{
-		psql_error("You are currently not connected to a database.\n");
+		pg_log_error("You are currently not connected to a database.");
 		return 0;
 	}
 
@@ -799,19 +778,19 @@ PSQLexecWatch(const char *query, const printQueryOpt *opt)
 			break;
 
 		case PGRES_EMPTY_QUERY:
-			psql_error("\\watch cannot be used with an empty query\n");
+			pg_log_error("\\watch cannot be used with an empty query");
 			PQclear(res);
 			return -1;
 
 		case PGRES_COPY_OUT:
 		case PGRES_COPY_IN:
 		case PGRES_COPY_BOTH:
-			psql_error("\\watch cannot be used with COPY\n");
+			pg_log_error("\\watch cannot be used with COPY");
 			PQclear(res);
 			return -1;
 
 		default:
-			psql_error("unexpected result status for \\watch\n");
+			pg_log_error("unexpected result status for \\watch");
 			PQclear(res);
 			return -1;
 	}
@@ -907,12 +886,12 @@ StoreQueryTuple(const PGresult *result)
 
 	if (PQntuples(result) < 1)
 	{
-		psql_error("no rows returned for \\gset\n");
+		pg_log_error("no rows returned for \\gset");
 		success = false;
 	}
 	else if (PQntuples(result) > 1)
 	{
-		psql_error("more than one row returned for \\gset\n");
+		pg_log_error("more than one row returned for \\gset");
 		success = false;
 	}
 	else
@@ -1081,7 +1060,7 @@ ProcessResult(PGresult **results)
 			default:
 				/* AcceptResult() should have caught anything else. */
 				is_copy = false;
-				psql_error("unexpected PQresultStatus: %d\n", result_status);
+				pg_log_error("unexpected PQresultStatus: %d", result_status);
 				break;
 		}
 
@@ -1255,7 +1234,7 @@ PrintQueryResults(PGresult *results)
 
 		default:
 			success = false;
-			psql_error("unexpected PQresultStatus: %d\n",
+			pg_log_error("unexpected PQresultStatus: %d",
 					   PQresultStatus(results));
 			break;
 	}
@@ -1291,7 +1270,7 @@ SendQuery(const char *query)
 
 	if (!pset.db)
 	{
-		psql_error("You are currently not connected to a database.\n");
+		pg_log_error("You are currently not connected to a database.");
 		goto sendquery_cleanup;
 	}
 
@@ -1337,7 +1316,7 @@ SendQuery(const char *query)
 		results = PQexec(pset.db, "BEGIN");
 		if (PQresultStatus(results) != PGRES_COMMAND_OK)
 		{
-			psql_error("%s", PQerrorMessage(pset.db));
+			pg_log_error("%s", PQerrorMessage(pset.db));
 			ClearOrSaveResult(results);
 			ResetCancelConn();
 			goto sendquery_cleanup;
@@ -1355,7 +1334,7 @@ SendQuery(const char *query)
 		{
 			char		sverbuf[32];
 
-			psql_error("The server (version %s) does not support savepoints for ON_ERROR_ROLLBACK.\n",
+			pg_log_warning("The server (version %s) does not support savepoints for ON_ERROR_ROLLBACK.",
 					   formatPGVersionNumber(pset.sversion, false,
 											 sverbuf, sizeof(sverbuf)));
 			on_error_rollback_warning = true;
@@ -1365,7 +1344,7 @@ SendQuery(const char *query)
 			results = PQexec(pset.db, "SAVEPOINT pg_psql_temporary_savepoint");
 			if (PQresultStatus(results) != PGRES_COMMAND_OK)
 			{
-				psql_error("%s", PQerrorMessage(pset.db));
+				pg_log_error("%s", PQerrorMessage(pset.db));
 				ClearOrSaveResult(results);
 				ResetCancelConn();
 				goto sendquery_cleanup;
@@ -1418,7 +1397,7 @@ SendQuery(const char *query)
 	}
 
 	if (!OK && pset.echo == PSQL_ECHO_ERRORS)
-		psql_error("STATEMENT:  %s\n", query);
+		pg_log_info("STATEMENT:  %s", query);
 
 	/* If we made a temporary savepoint, possibly release/rollback */
 	if (on_error_rollback_savepoint)
@@ -1461,7 +1440,7 @@ SendQuery(const char *query)
 				OK = false;
 				/* PQTRANS_UNKNOWN is expected given a broken connection. */
 				if (transaction_status != PQTRANS_UNKNOWN || ConnectionUp())
-					psql_error("unexpected transaction status (%d)\n",
+					pg_log_error("unexpected transaction status (%d)",
 							   transaction_status);
 				break;
 		}
@@ -1473,7 +1452,7 @@ SendQuery(const char *query)
 			svptres = PQexec(pset.db, svptcmd);
 			if (PQresultStatus(svptres) != PGRES_COMMAND_OK)
 			{
-				psql_error("%s", PQerrorMessage(pset.db));
+				pg_log_error("%s", PQerrorMessage(pset.db));
 				ClearOrSaveResult(svptres);
 				OK = false;
 
@@ -1576,7 +1555,7 @@ DescribeQuery(const char *query, double *elapsed_msec)
 	results = PQprepare(pset.db, "", query, 0, NULL);
 	if (PQresultStatus(results) != PGRES_COMMAND_OK)
 	{
-		psql_error("%s", PQerrorMessage(pset.db));
+		pg_log_error("%s", PQerrorMessage(pset.db));
 		SetResultVariables(results, false);
 		ClearOrSaveResult(results);
 		return false;
@@ -1614,7 +1593,7 @@ DescribeQuery(const char *query, double *elapsed_msec)
 
 				if (escname == NULL)
 				{
-					psql_error("%s", PQerrorMessage(pset.db));
+					pg_log_error("%s", PQerrorMessage(pset.db));
 					PQclear(results);
 					termPQExpBuffer(&buf);
 					return false;
diff --git a/src/bin/psql/common.h b/src/bin/psql/common.h
index 1f2a4bf1ae..4739b8ee33 100644
--- a/src/bin/psql/common.h
+++ b/src/bin/psql/common.h
@@ -20,8 +20,6 @@ extern bool setQFout(const char *fname);
 extern char *psql_get_variable(const char *varname, PsqlScanQuoteType quote,
 				  void *passthrough);
 
-extern void psql_error(const char *fmt,...) pg_attribute_printf(1, 2);
-
 extern void NoticeProcessor(void *arg, const char *message);
 
 extern volatile bool sigint_interrupt_enabled;
diff --git a/src/bin/psql/copy.c b/src/bin/psql/copy.c
index 02c85119fe..8f54f496fb 100644
--- a/src/bin/psql/copy.c
+++ b/src/bin/psql/copy.c
@@ -24,6 +24,7 @@
 #include "prompt.h"
 #include "stringutils.h"
 
+#include "fe_utils/logging.h"
 
 /*
  * parse_slash_copy
@@ -96,7 +97,7 @@ parse_slash_copy(const char *args)
 
 	if (!args)
 	{
-		psql_error("\\copy: arguments required\n");
+		pg_log_error("\\copy: arguments required");
 		return NULL;
 	}
 
@@ -251,9 +252,9 @@ parse_slash_copy(const char *args)
 
 error:
 	if (token)
-		psql_error("\\copy: parse error at \"%s\"\n", token);
+		pg_log_error("\\copy: parse error at \"%s\"", token);
 	else
-		psql_error("\\copy: parse error at end of line\n");
+		pg_log_error("\\copy: parse error at end of line");
 	free_copy_options(result);
 
 	return NULL;
@@ -326,11 +327,11 @@ do_copy(const char *args)
 	if (!copystream)
 	{
 		if (options->program)
-			psql_error("could not execute command \"%s\": %s\n",
-					   options->file, strerror(errno));
+			pg_log_error("could not execute command \"%s\": %m",
+						 options->file);
 		else
-			psql_error("%s: %s\n",
-					   options->file, strerror(errno));
+			pg_log_error("%s: %m",
+						 options->file);
 		free_copy_options(options);
 		return false;
 	}
@@ -342,12 +343,12 @@ do_copy(const char *args)
 
 		/* make sure the specified file is not a directory */
 		if ((result = fstat(fileno(copystream), &st)) < 0)
-			psql_error("could not stat file \"%s\": %s\n",
-					   options->file, strerror(errno));
+			pg_log_error("could not stat file \"%s\": %m",
+						 options->file);
 
 		if (result == 0 && S_ISDIR(st.st_mode))
-			psql_error("%s: cannot copy from/to a directory\n",
-					   options->file);
+			pg_log_error("%s: cannot copy from/to a directory",
+						 options->file);
 
 		if (result < 0 || S_ISDIR(st.st_mode))
 		{
@@ -383,13 +384,12 @@ do_copy(const char *args)
 			if (pclose_rc != 0)
 			{
 				if (pclose_rc < 0)
-					psql_error("could not close pipe to external command: %s\n",
-							   strerror(errno));
+					pg_log_error("could not close pipe to external command: %m");
 				else
 				{
 					char	   *reason = wait_result_to_str(pclose_rc);
 
-					psql_error("%s: %s\n", options->file,
+					pg_log_error("%s: %s", options->file,
 							   reason ? reason : "");
 					if (reason)
 						free(reason);
@@ -402,7 +402,7 @@ do_copy(const char *args)
 		{
 			if (fclose(copystream) != 0)
 			{
-				psql_error("%s: %s\n", options->file, strerror(errno));
+				pg_log_error("%s: %m", options->file);
 				success = false;
 			}
 		}
@@ -449,8 +449,7 @@ handleCopyOut(PGconn *conn, FILE *copystream, PGresult **res)
 		{
 			if (OK && fwrite(buf, 1, ret, copystream) != ret)
 			{
-				psql_error("could not write COPY data: %s\n",
-						   strerror(errno));
+				pg_log_error("could not write COPY data: %m");
 				/* complain only once, keep reading data from server */
 				OK = false;
 			}
@@ -460,14 +459,13 @@ handleCopyOut(PGconn *conn, FILE *copystream, PGresult **res)
 
 	if (OK && fflush(copystream))
 	{
-		psql_error("could not write COPY data: %s\n",
-				   strerror(errno));
+		pg_log_error("could not write COPY data: %m");
 		OK = false;
 	}
 
 	if (ret == -2)
 	{
-		psql_error("COPY data transfer failed: %s", PQerrorMessage(conn));
+		pg_log_error("COPY data transfer failed: %s", PQerrorMessage(conn));
 		OK = false;
 	}
 
@@ -486,7 +484,7 @@ handleCopyOut(PGconn *conn, FILE *copystream, PGresult **res)
 	*res = PQgetResult(conn);
 	if (PQresultStatus(*res) != PGRES_COMMAND_OK)
 	{
-		psql_error("%s", PQerrorMessage(conn));
+		pg_log_error("%s", PQerrorMessage(conn));
 		OK = false;
 	}
 
@@ -705,7 +703,7 @@ handleCopyIn(PGconn *conn, FILE *copystream, bool isbinary, PGresult **res)
 	}
 	if (PQresultStatus(*res) != PGRES_COMMAND_OK)
 	{
-		psql_error("%s", PQerrorMessage(conn));
+		pg_log_error("%s", PQerrorMessage(conn));
 		OK = false;
 	}
 
diff --git a/src/bin/psql/crosstabview.c b/src/bin/psql/crosstabview.c
index fb77ce7033..6afd3e0939 100644
--- a/src/bin/psql/crosstabview.c
+++ b/src/bin/psql/crosstabview.c
@@ -13,6 +13,7 @@
 #include "psqlscanslash.h"
 #include "settings.h"
 
+#include "fe_utils/logging.h"
 
 /*
  * Value/position from the resultset that goes into the horizontal or vertical
@@ -120,13 +121,13 @@ PrintResultsInCrosstab(const PGresult *res)
 
 	if (PQresultStatus(res) != PGRES_TUPLES_OK)
 	{
-		psql_error("\\crosstabview: statement did not return a result set\n");
+		pg_log_error("\\crosstabview: statement did not return a result set");
 		goto error_return;
 	}
 
 	if (PQnfields(res) < 3)
 	{
-		psql_error("\\crosstabview: query must return at least three columns\n");
+		pg_log_error("\\crosstabview: query must return at least three columns");
 		goto error_return;
 	}
 
@@ -153,7 +154,7 @@ PrintResultsInCrosstab(const PGresult *res)
 	/* Insist that header columns be distinct */
 	if (field_for_columns == field_for_rows)
 	{
-		psql_error("\\crosstabview: vertical and horizontal headers must be different columns\n");
+		pg_log_error("\\crosstabview: vertical and horizontal headers must be different columns");
 		goto error_return;
 	}
 
@@ -169,7 +170,7 @@ PrintResultsInCrosstab(const PGresult *res)
 		 */
 		if (PQnfields(res) != 3)
 		{
-			psql_error("\\crosstabview: data column must be specified when query returns more than three columns\n");
+			pg_log_error("\\crosstabview: data column must be specified when query returns more than three columns");
 			goto error_return;
 		}
 
@@ -225,7 +226,7 @@ PrintResultsInCrosstab(const PGresult *res)
 
 		if (piv_columns.count > CROSSTABVIEW_MAX_COLUMNS)
 		{
-			psql_error("\\crosstabview: maximum number of columns (%d) exceeded\n",
+			pg_log_error("\\crosstabview: maximum number of columns (%d) exceeded",
 					   CROSSTABVIEW_MAX_COLUMNS);
 			goto error_return;
 		}
@@ -394,7 +395,7 @@ printCrosstab(const PGresult *results,
 			 */
 			if (cont.cells[idx] != NULL)
 			{
-				psql_error("\\crosstabview: query result contains multiple data values for row \"%s\", column \"%s\"\n",
+				pg_log_error("\\crosstabview: query result contains multiple data values for row \"%s\", column \"%s\"",
 						   rp->name ? rp->name :
 						   (popt.nullPrint ? popt.nullPrint : "(null)"),
 						   cp->name ? cp->name :
@@ -642,7 +643,7 @@ indexOfColumn(char *arg, const PGresult *res)
 		idx = atoi(arg) - 1;
 		if (idx < 0 || idx >= PQnfields(res))
 		{
-			psql_error("\\crosstabview: column number %d is out of range 1..%d\n",
+			pg_log_error("\\crosstabview: column number %d is out of range 1..%d",
 					   idx + 1, PQnfields(res));
 			return -1;
 		}
@@ -667,7 +668,7 @@ indexOfColumn(char *arg, const PGresult *res)
 				if (idx >= 0)
 				{
 					/* another idx was already found for the same name */
-					psql_error("\\crosstabview: ambiguous column name: \"%s\"\n", arg);
+					pg_log_error("\\crosstabview: ambiguous column name: \"%s\"", arg);
 					return -1;
 				}
 				idx = i;
@@ -675,7 +676,7 @@ indexOfColumn(char *arg, const PGresult *res)
 		}
 		if (idx == -1)
 		{
-			psql_error("\\crosstabview: column name not found: \"%s\"\n", arg);
+			pg_log_error("\\crosstabview: column name not found: \"%s\"", arg);
 			return -1;
 		}
 	}
diff --git a/src/bin/psql/describe.c b/src/bin/psql/describe.c
index 4da6719ce7..7f6bcba08d 100644
--- a/src/bin/psql/describe.c
+++ b/src/bin/psql/describe.c
@@ -18,6 +18,7 @@
 #include "catalog/pg_cast_d.h"
 #include "catalog/pg_class_d.h"
 #include "catalog/pg_default_acl_d.h"
+#include "fe_utils/logging.h"
 #include "fe_utils/string_utils.h"
 
 #include "common.h"
@@ -157,7 +158,7 @@ describeAccessMethods(const char *pattern, bool verbose)
 	{
 		char		sverbuf[32];
 
-		psql_error("The server (version %s) does not support access methods.\n",
+		pg_log_error("The server (version %s) does not support access methods.",
 				   formatPGVersionNumber(pset.sversion, false,
 										 sverbuf, sizeof(sverbuf)));
 		return true;
@@ -224,7 +225,7 @@ describeTablespaces(const char *pattern, bool verbose)
 	{
 		char		sverbuf[32];
 
-		psql_error("The server (version %s) does not support tablespaces.\n",
+		pg_log_info("The server (version %s) does not support tablespaces.",
 				   formatPGVersionNumber(pset.sversion, false,
 										 sverbuf, sizeof(sverbuf)));
 		return true;
@@ -327,7 +328,7 @@ describeFunctions(const char *functypes, const char *pattern, bool verbose, bool
 
 	if (strlen(functypes) != strspn(functypes, "anptwS+"))
 	{
-		psql_error("\\df only takes [anptwS+] as options\n");
+		pg_log_error("\\df only takes [anptwS+] as options");
 		return true;
 	}
 
@@ -335,7 +336,7 @@ describeFunctions(const char *functypes, const char *pattern, bool verbose, bool
 	{
 		char		sverbuf[32];
 
-		psql_error("\\df does not take a \"%c\" option with server version %s\n",
+		pg_log_error("\\df does not take a \"%c\" option with server version %s",
 				   'p',
 				   formatPGVersionNumber(pset.sversion, false,
 										 sverbuf, sizeof(sverbuf)));
@@ -346,7 +347,7 @@ describeFunctions(const char *functypes, const char *pattern, bool verbose, bool
 	{
 		char		sverbuf[32];
 
-		psql_error("\\df does not take a \"%c\" option with server version %s\n",
+		pg_log_error("\\df does not take a \"%c\" option with server version %s",
 				   'w',
 				   formatPGVersionNumber(pset.sversion, false,
 										 sverbuf, sizeof(sverbuf)));
@@ -1095,7 +1096,7 @@ listDefaultACLs(const char *pattern)
 	{
 		char		sverbuf[32];
 
-		psql_error("The server (version %s) does not support altering default privileges.\n",
+		pg_log_error("The server (version %s) does not support altering default privileges.",
 				   formatPGVersionNumber(pset.sversion, false,
 										 sverbuf, sizeof(sverbuf)));
 		return true;
@@ -1396,10 +1397,10 @@ describeTableDetails(const char *pattern, bool verbose, bool showSystem)
 		if (!pset.quiet)
 		{
 			if (pattern)
-				psql_error("Did not find any relation named \"%s\".\n",
+				pg_log_error("Did not find any relation named \"%s\".",
 						   pattern);
 			else
-				psql_error("Did not find any relations.\n");
+				pg_log_error("Did not find any relations.");
 		}
 		PQclear(res);
 		return false;
@@ -1633,7 +1634,7 @@ describeOneTableDetails(const char *schemaname,
 	if (PQntuples(res) == 0)
 	{
 		if (!pset.quiet)
-			psql_error("Did not find any relation with OID %s.\n", oid);
+			pg_log_error("Did not find any relation with OID %s.", oid);
 		goto error_return;
 	}
 
@@ -3427,7 +3428,7 @@ listDbRoleSettings(const char *pattern, const char *pattern2)
 	{
 		char		sverbuf[32];
 
-		psql_error("The server (version %s) does not support per-database role settings.\n",
+		pg_log_error("The server (version %s) does not support per-database role settings.",
 				   formatPGVersionNumber(pset.sversion, false,
 										 sverbuf, sizeof(sverbuf)));
 		return true;
@@ -3463,13 +3464,13 @@ listDbRoleSettings(const char *pattern, const char *pattern2)
 	if (PQntuples(res) == 0 && !pset.quiet)
 	{
 		if (pattern && pattern2)
-			psql_error("Did not find any settings for role \"%s\" and database \"%s\".\n",
+			pg_log_error("Did not find any settings for role \"%s\" and database \"%s\".",
 					   pattern, pattern2);
 		else if (pattern)
-			psql_error("Did not find any settings for role \"%s\".\n",
+			pg_log_error("Did not find any settings for role \"%s\".",
 					   pattern);
 		else
-			psql_error("Did not find any settings.\n");
+			pg_log_error("Did not find any settings.");
 	}
 	else
 	{
@@ -3639,10 +3640,10 @@ listTables(const char *tabtypes, const char *pattern, bool verbose, bool showSys
 	if (PQntuples(res) == 0 && !pset.quiet)
 	{
 		if (pattern)
-			psql_error("Did not find any relation named \"%s\".\n",
+			pg_log_error("Did not find any relation named \"%s\".",
 					   pattern);
 		else
-			psql_error("Did not find any relations.\n");
+			pg_log_error("Did not find any relations.");
 	}
 	else
 	{
@@ -4098,7 +4099,7 @@ listCollations(const char *pattern, bool verbose, bool showSystem)
 	{
 		char		sverbuf[32];
 
-		psql_error("The server (version %s) does not support collations.\n",
+		pg_log_error("The server (version %s) does not support collations.",
 				   formatPGVersionNumber(pset.sversion, false,
 										 sverbuf, sizeof(sverbuf)));
 		return true;
@@ -4238,7 +4239,7 @@ listTSParsers(const char *pattern, bool verbose)
 	{
 		char		sverbuf[32];
 
-		psql_error("The server (version %s) does not support full text search.\n",
+		pg_log_error("The server (version %s) does not support full text search.",
 				   formatPGVersionNumber(pset.sversion, false,
 										 sverbuf, sizeof(sverbuf)));
 		return true;
@@ -4318,10 +4319,10 @@ listTSParsersVerbose(const char *pattern)
 		if (!pset.quiet)
 		{
 			if (pattern)
-				psql_error("Did not find any text search parser named \"%s\".\n",
+				pg_log_error("Did not find any text search parser named \"%s\".",
 						   pattern);
 			else
-				psql_error("Did not find any text search parsers.\n");
+				pg_log_error("Did not find any text search parsers.");
 		}
 		PQclear(res);
 		return false;
@@ -4485,7 +4486,7 @@ listTSDictionaries(const char *pattern, bool verbose)
 	{
 		char		sverbuf[32];
 
-		psql_error("The server (version %s) does not support full text search.\n",
+		pg_log_error("The server (version %s) does not support full text search.",
 				   formatPGVersionNumber(pset.sversion, false,
 										 sverbuf, sizeof(sverbuf)));
 		return true;
@@ -4556,7 +4557,7 @@ listTSTemplates(const char *pattern, bool verbose)
 	{
 		char		sverbuf[32];
 
-		psql_error("The server (version %s) does not support full text search.\n",
+		pg_log_error("The server (version %s) does not support full text search.",
 				   formatPGVersionNumber(pset.sversion, false,
 										 sverbuf, sizeof(sverbuf)));
 		return true;
@@ -4627,7 +4628,7 @@ listTSConfigs(const char *pattern, bool verbose)
 	{
 		char		sverbuf[32];
 
-		psql_error("The server (version %s) does not support full text search.\n",
+		pg_log_error("The server (version %s) does not support full text search.",
 				   formatPGVersionNumber(pset.sversion, false,
 										 sverbuf, sizeof(sverbuf)));
 		return true;
@@ -4708,10 +4709,10 @@ listTSConfigsVerbose(const char *pattern)
 		if (!pset.quiet)
 		{
 			if (pattern)
-				psql_error("Did not find any text search configuration named \"%s\".\n",
+				pg_log_error("Did not find any text search configuration named \"%s\".",
 						   pattern);
 			else
-				psql_error("Did not find any text search configurations.\n");
+				pg_log_error("Did not find any text search configurations.");
 		}
 		PQclear(res);
 		return false;
@@ -4833,7 +4834,7 @@ listForeignDataWrappers(const char *pattern, bool verbose)
 	{
 		char		sverbuf[32];
 
-		psql_error("The server (version %s) does not support foreign-data wrappers.\n",
+		pg_log_error("The server (version %s) does not support foreign-data wrappers.",
 				   formatPGVersionNumber(pset.sversion, false,
 										 sverbuf, sizeof(sverbuf)));
 		return true;
@@ -4916,7 +4917,7 @@ listForeignServers(const char *pattern, bool verbose)
 	{
 		char		sverbuf[32];
 
-		psql_error("The server (version %s) does not support foreign servers.\n",
+		pg_log_error("The server (version %s) does not support foreign servers.",
 				   formatPGVersionNumber(pset.sversion, false,
 										 sverbuf, sizeof(sverbuf)));
 		return true;
@@ -4998,7 +4999,7 @@ listUserMappings(const char *pattern, bool verbose)
 	{
 		char		sverbuf[32];
 
-		psql_error("The server (version %s) does not support user mappings.\n",
+		pg_log_error("The server (version %s) does not support user mappings.",
 				   formatPGVersionNumber(pset.sversion, false,
 										 sverbuf, sizeof(sverbuf)));
 		return true;
@@ -5059,7 +5060,7 @@ listForeignTables(const char *pattern, bool verbose)
 	{
 		char		sverbuf[32];
 
-		psql_error("The server (version %s) does not support foreign tables.\n",
+		pg_log_error("The server (version %s) does not support foreign tables.",
 				   formatPGVersionNumber(pset.sversion, false,
 										 sverbuf, sizeof(sverbuf)));
 		return true;
@@ -5137,7 +5138,7 @@ listExtensions(const char *pattern)
 	{
 		char		sverbuf[32];
 
-		psql_error("The server (version %s) does not support extensions.\n",
+		pg_log_error("The server (version %s) does not support extensions.",
 				   formatPGVersionNumber(pset.sversion, false,
 										 sverbuf, sizeof(sverbuf)));
 		return true;
@@ -5194,7 +5195,7 @@ listExtensionContents(const char *pattern)
 	{
 		char		sverbuf[32];
 
-		psql_error("The server (version %s) does not support extensions.\n",
+		pg_log_error("The server (version %s) does not support extensions.",
 				   formatPGVersionNumber(pset.sversion, false,
 										 sverbuf, sizeof(sverbuf)));
 		return true;
@@ -5222,10 +5223,10 @@ listExtensionContents(const char *pattern)
 		if (!pset.quiet)
 		{
 			if (pattern)
-				psql_error("Did not find any extension named \"%s\".\n",
+				pg_log_error("Did not find any extension named \"%s\".",
 						   pattern);
 			else
-				psql_error("Did not find any extensions.\n");
+				pg_log_error("Did not find any extensions.");
 		}
 		PQclear(res);
 		return false;
@@ -5308,7 +5309,7 @@ listPublications(const char *pattern)
 	{
 		char		sverbuf[32];
 
-		psql_error("The server (version %s) does not support publications.\n",
+		pg_log_error("The server (version %s) does not support publications.",
 				   formatPGVersionNumber(pset.sversion, false,
 										 sverbuf, sizeof(sverbuf)));
 		return true;
@@ -5379,7 +5380,7 @@ describePublications(const char *pattern)
 	{
 		char		sverbuf[32];
 
-		psql_error("The server (version %s) does not support publications.\n",
+		pg_log_error("The server (version %s) does not support publications.",
 				   formatPGVersionNumber(pset.sversion, false,
 										 sverbuf, sizeof(sverbuf)));
 		return true;
@@ -5417,10 +5418,10 @@ describePublications(const char *pattern)
 		if (!pset.quiet)
 		{
 			if (pattern)
-				psql_error("Did not find any publication named \"%s\".\n",
+				pg_log_error("Did not find any publication named \"%s\".",
 						   pattern);
 			else
-				psql_error("Did not find any publications.\n");
+				pg_log_error("Did not find any publications.");
 		}
 
 		termPQExpBuffer(&buf);
@@ -5535,7 +5536,7 @@ describeSubscriptions(const char *pattern, bool verbose)
 	{
 		char		sverbuf[32];
 
-		psql_error("The server (version %s) does not support subscriptions.\n",
+		pg_log_error("The server (version %s) does not support subscriptions.",
 				   formatPGVersionNumber(pset.sversion, false,
 										 sverbuf, sizeof(sverbuf)));
 		return true;
diff --git a/src/bin/psql/help.c b/src/bin/psql/help.c
index a403431760..415f669cd2 100644
--- a/src/bin/psql/help.c
+++ b/src/bin/psql/help.c
@@ -28,6 +28,7 @@
 #include "settings.h"
 #include "sql_help.h"
 
+#include "fe_utils/logging.h"
 
 /*
  * PLEASE:
@@ -59,7 +60,7 @@ usage(unsigned short int pager)
 		user = get_user_name(&errstr);
 		if (!user)
 		{
-			psql_error("%s\n", errstr);
+			pg_log_fatal("%s", errstr);
 			exit(EXIT_FAILURE);
 		}
 	}
diff --git a/src/bin/psql/input.c b/src/bin/psql/input.c
index 0830b7bb09..93c0d4c49e 100644
--- a/src/bin/psql/input.c
+++ b/src/bin/psql/input.c
@@ -18,6 +18,8 @@
 #include "tab-complete.h"
 #include "common.h"
 
+#include "fe_utils/logging.h"
+
 #ifndef WIN32
 #define PSQLHISTORY ".psql_history"
 #else
@@ -213,8 +215,7 @@ gets_fromFile(FILE *source)
 		{
 			if (ferror(source))
 			{
-				psql_error("could not read from input file: %s\n",
-						   strerror(errno));
+				pg_log_error("could not read from input file: %m");
 				return NULL;
 			}
 			break;
@@ -224,7 +225,7 @@ gets_fromFile(FILE *source)
 
 		if (PQExpBufferBroken(buffer))
 		{
-			psql_error("out of memory\n");
+			pg_log_error("out of memory");
 			return NULL;
 		}
 
@@ -468,8 +469,7 @@ saveHistory(char *fname, int max_lines)
 		}
 #endif
 
-		psql_error("could not save history to file \"%s\": %s\n",
-				   fname, strerror(errnum));
+		pg_log_error("could not save history to file \"%s\": %m", fname);
 	}
 	return false;
 }
@@ -507,8 +507,7 @@ printHistory(const char *fname, unsigned short int pager)
 		output = fopen(fname, "w");
 		if (output == NULL)
 		{
-			psql_error("could not save history to file \"%s\": %s\n",
-					   fname, strerror(errno));
+			pg_log_error("could not save history to file \"%s\": %m", fname);
 			return false;
 		}
 		is_pager = false;
@@ -527,7 +526,7 @@ printHistory(const char *fname, unsigned short int pager)
 
 	return true;
 #else
-	psql_error("history is not supported by this installation\n");
+	pg_log_error("history is not supported by this installation");
 	return false;
 #endif
 }
diff --git a/src/bin/psql/large_obj.c b/src/bin/psql/large_obj.c
index 2047393441..7dc2e1edc4 100644
--- a/src/bin/psql/large_obj.c
+++ b/src/bin/psql/large_obj.c
@@ -8,10 +8,11 @@
 #include "postgres_fe.h"
 #include "large_obj.h"
 
-
 #include "settings.h"
 #include "common.h"
 
+#include "fe_utils/logging.h"
+
 static void print_lo_result(const char *fmt,...) pg_attribute_printf(1, 2);
 
 static void
@@ -61,7 +62,7 @@ start_lo_xact(const char *operation, bool *own_transaction)
 
 	if (!pset.db)
 	{
-		psql_error("%s: not connected to a database\n", operation);
+		pg_log_error("%s: not connected to a database", operation);
 		return false;
 	}
 
@@ -80,10 +81,10 @@ start_lo_xact(const char *operation, bool *own_transaction)
 			/* use the existing xact */
 			break;
 		case PQTRANS_INERROR:
-			psql_error("%s: current transaction is aborted\n", operation);
+			pg_log_error("%s: current transaction is aborted", operation);
 			return false;
 		default:
-			psql_error("%s: unknown transaction status\n", operation);
+			pg_log_error("%s: unknown transaction status", operation);
 			return false;
 	}
 
@@ -153,7 +154,7 @@ do_lo_export(const char *loid_arg, const char *filename_arg)
 	/* of course this status is documented nowhere :( */
 	if (status != 1)
 	{
-		psql_error("%s", PQerrorMessage(pset.db));
+		pg_log_error("%s", PQerrorMessage(pset.db));
 		return fail_lo_xact("\\lo_export", own_transaction);
 	}
 
@@ -188,7 +189,7 @@ do_lo_import(const char *filename_arg, const char *comment_arg)
 
 	if (loid == InvalidOid)
 	{
-		psql_error("%s", PQerrorMessage(pset.db));
+		pg_log_error("%s", PQerrorMessage(pset.db));
 		return fail_lo_xact("\\lo_import", own_transaction);
 	}
 
@@ -250,7 +251,7 @@ do_lo_unlink(const char *loid_arg)
 
 	if (status == -1)
 	{
-		psql_error("%s", PQerrorMessage(pset.db));
+		pg_log_error("%s", PQerrorMessage(pset.db));
 		return fail_lo_xact("\\lo_unlink", own_transaction);
 	}
 
diff --git a/src/bin/psql/mainloop.c b/src/bin/psql/mainloop.c
index 481d012fb0..3ae447041f 100644
--- a/src/bin/psql/mainloop.c
+++ b/src/bin/psql/mainloop.c
@@ -14,13 +14,13 @@
 #include "prompt.h"
 #include "settings.h"
 
+#include "fe_utils/logging.h"
 #include "mb/pg_wchar.h"
 
 
 /* callback functions for our flex lexer */
 const PsqlScanCallbacks psqlscan_callbacks = {
 	psql_get_variable,
-	psql_error
 };
 
 
@@ -79,7 +79,7 @@ MainLoop(FILE *source)
 		PQExpBufferBroken(previous_buf) ||
 		PQExpBufferBroken(history_buf))
 	{
-		psql_error("out of memory\n");
+		pg_log_error("out of memory");
 		exit(EXIT_FAILURE);
 	}
 
@@ -133,7 +133,7 @@ MainLoop(FILE *source)
 				 */
 				if (!conditional_stack_empty(cond_stack))
 				{
-					psql_error("\\if: escaped\n");
+					pg_log_error("\\if: escaped");
 					conditional_stack_pop(cond_stack);
 				}
 			}
@@ -383,7 +383,7 @@ MainLoop(FILE *source)
 
 			if (PQExpBufferBroken(query_buf))
 			{
-				psql_error("out of memory\n");
+				pg_log_error("out of memory");
 				exit(EXIT_FAILURE);
 			}
 
@@ -446,7 +446,7 @@ MainLoop(FILE *source)
 				{
 					/* if interactive, warn about non-executed query */
 					if (pset.cur_cmd_interactive)
-						psql_error("query ignored; use \\endif or Ctrl-C to exit current \\if block\n");
+						pg_log_error("query ignored; use \\endif or Ctrl-C to exit current \\if block");
 					/* fake an OK result for purposes of loop checks */
 					success = true;
 					slashCmdStatus = PSQL_CMD_SEND;
@@ -588,7 +588,7 @@ MainLoop(FILE *source)
 		else
 		{
 			if (pset.cur_cmd_interactive)
-				psql_error("query ignored; use \\endif or Ctrl-C to exit current \\if block\n");
+				pg_log_error("query ignored; use \\endif or Ctrl-C to exit current \\if block");
 			success = true;
 		}
 
@@ -606,7 +606,7 @@ MainLoop(FILE *source)
 		successResult != EXIT_USER &&
 		!conditional_stack_empty(cond_stack))
 	{
-		psql_error("reached EOF without finding closing \\endif(s)\n");
+		pg_log_error("reached EOF without finding closing \\endif(s)");
 		if (die_on_error && !pset.cur_cmd_interactive)
 			successResult = EXIT_USER;
 	}
diff --git a/src/bin/psql/nls.mk b/src/bin/psql/nls.mk
index e355f219b9..2e707f441c 100644
--- a/src/bin/psql/nls.mk
+++ b/src/bin/psql/nls.mk
@@ -1,12 +1,14 @@
 # src/bin/psql/nls.mk
 CATALOG_NAME     = psql
 AVAIL_LANGUAGES  = cs de es fr he it ja ko pl pt_BR ru sv zh_CN zh_TW
-GETTEXT_FILES    = command.c common.c copy.c crosstabview.c help.c input.c large_obj.c \
+GETTEXT_FILES    = $(FRONTEND_COMMON_GETTEXT_FILES) \
+                   command.c common.c copy.c crosstabview.c help.c input.c large_obj.c \
                    mainloop.c psqlscanslash.c startup.c \
                    describe.c sql_help.h sql_help.c \
                    tab-complete.c variables.c \
                    ../../fe_utils/print.c ../../fe_utils/psqlscan.c \
                    ../../common/exec.c ../../common/fe_memutils.c ../../common/username.c \
                    ../../common/wait_error.c
-GETTEXT_TRIGGERS = N_ psql_error simple_prompt write_error
-GETTEXT_FLAGS    = psql_error:1:c-format write_error:1:c-format
+GETTEXT_TRIGGERS = $(FRONTEND_COMMON_GETTEXT_TRIGGERS) \
+                   N_ simple_prompt
+GETTEXT_FLAGS    = $(FRONTEND_COMMON_GETTEXT_FLAGS)
diff --git a/src/bin/psql/psqlscanslash.l b/src/bin/psql/psqlscanslash.l
index 1514aa74d3..f7818e6e60 100644
--- a/src/bin/psql/psqlscanslash.l
+++ b/src/bin/psql/psqlscanslash.l
@@ -20,6 +20,7 @@
 
 #include "psqlscanslash.h"
 #include "fe_utils/conditional.h"
+#include "fe_utils/logging.h"
 
 #include "libpq-fe.h"
 }
@@ -633,7 +634,7 @@ psql_scan_slash_option(PsqlScanState state,
 		case xslashbackquote:
 		case xslashdquote:
 			/* must have hit EOL inside quotes */
-			state->callbacks->write_error("unterminated quoted string\n");
+			pg_log_error("unterminated quoted string");
 			termPQExpBuffer(&mybuf);
 			return NULL;
 		case xslashwholeline:
@@ -779,7 +780,7 @@ evaluate_backtick(PsqlScanState state)
 	fd = popen(cmd, PG_BINARY_R);
 	if (!fd)
 	{
-		state->callbacks->write_error("%s: %s\n", cmd, strerror(errno));
+		pg_log_error("%s: %m", cmd);
 		error = true;
 	}
 
@@ -790,7 +791,7 @@ evaluate_backtick(PsqlScanState state)
 			result = fread(buf, 1, sizeof(buf), fd);
 			if (ferror(fd))
 			{
-				state->callbacks->write_error("%s: %s\n", cmd, strerror(errno));
+				pg_log_error("%s: %m", cmd);
 				error = true;
 				break;
 			}
@@ -800,13 +801,13 @@ evaluate_backtick(PsqlScanState state)
 
 	if (fd && pclose(fd) == -1)
 	{
-		state->callbacks->write_error("%s: %s\n", cmd, strerror(errno));
+		pg_log_error("%s: %m", cmd);
 		error = true;
 	}
 
 	if (PQExpBufferDataBroken(cmd_output))
 	{
-		state->callbacks->write_error("%s: out of memory\n", cmd);
+		pg_log_error("%s: out of memory", cmd);
 		error = true;
 	}
 
diff --git a/src/bin/psql/startup.c b/src/bin/psql/startup.c
index f3ceefda9b..de76c9e7fe 100644
--- a/src/bin/psql/startup.c
+++ b/src/bin/psql/startup.c
@@ -22,6 +22,7 @@
 #include "help.h"
 #include "input.h"
 #include "mainloop.h"
+#include "fe_utils/logging.h"
 #include "fe_utils/print.h"
 #include "settings.h"
 
@@ -89,6 +90,28 @@ static void EstablishVariableSpace(void);
 
 #define NOPAGER		0
 
+static void
+log_pre_callback(void)
+{
+	if (pset.queryFout && pset.queryFout != stdout)
+		fflush(pset.queryFout);
+}
+
+static void
+log_locus_callback(const char **filename, uint64 *lineno)
+{
+	if (pset.inputfile)
+	{
+		*filename = pset.inputfile;
+		*lineno =  pset.lineno;
+	}
+	else
+	{
+		*filename = NULL;
+		*lineno = 0;
+	}
+}
+
 /*
  *
  * main
@@ -104,6 +127,9 @@ main(int argc, char *argv[])
 	bool		new_pass;
 
 	set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("psql"));
+	pg_logging_init(argv[0]);
+	pg_logging_set_pre_callback(log_pre_callback);
+	pg_logging_set_locus_callback(log_locus_callback);
 
 	if (argc > 1)
 	{
@@ -190,7 +216,7 @@ main(int argc, char *argv[])
 	/* Bail out if -1 was specified but will be ignored. */
 	if (options.single_txn && options.actions.head == NULL)
 	{
-		fprintf(stderr, _("%s: -1 can only be used in non-interactive mode\n"), pset.progname);
+		pg_log_fatal("-1 can only be used in non-interactive mode");
 		exit(EXIT_FAILURE);
 	}
 
@@ -277,7 +303,7 @@ main(int argc, char *argv[])
 
 	if (PQstatus(pset.db) == CONNECTION_BAD)
 	{
-		fprintf(stderr, "%s: %s", pset.progname, PQerrorMessage(pset.db));
+		pg_log_fatal("%s", PQerrorMessage(pset.db));
 		PQfinish(pset.db);
 		exit(EXIT_BADCONN);
 	}
@@ -305,8 +331,8 @@ main(int argc, char *argv[])
 		pset.logfile = fopen(options.logfilename, "a");
 		if (!pset.logfile)
 		{
-			fprintf(stderr, _("%s: could not open log file \"%s\": %s\n"),
-					pset.progname, options.logfilename, strerror(errno));
+			pg_log_fatal("could not open log file \"%s\": %m",
+						 options.logfilename);
 			exit(EXIT_FAILURE);
 		}
 	}
@@ -562,7 +588,7 @@ parse_psql_options(int argc, char *argv[], struct adhoc_opts *options)
 
 					if (!result)
 					{
-						fprintf(stderr, _("%s: could not set printing parameter \"%s\"\n"), pset.progname, value);
+						pg_log_fatal("could not set printing parameter \"%s\"", value);
 						exit(EXIT_FAILURE);
 					}
 
@@ -684,8 +710,8 @@ parse_psql_options(int argc, char *argv[], struct adhoc_opts *options)
 		else if (!options->username)
 			options->username = argv[optind];
 		else if (!pset.quiet)
-			fprintf(stderr, _("%s: warning: extra command-line argument \"%s\" ignored\n"),
-					pset.progname, argv[optind]);
+			pg_log_warning("extra command-line argument \"%s\" ignored",
+						   argv[optind]);
 
 		optind++;
 	}
@@ -733,7 +759,7 @@ process_psqlrc(char *argv0)
 
 	if (find_my_exec(argv0, my_exec_path) < 0)
 	{
-		fprintf(stderr, _("%s: could not find own program executable\n"), argv0);
+		pg_log_fatal("could not find own program executable");
 		exit(EXIT_FAILURE);
 	}
 
diff --git a/src/bin/psql/variables.c b/src/bin/psql/variables.c
index 72fddf256c..5d47d5a8ab 100644
--- a/src/bin/psql/variables.c
+++ b/src/bin/psql/variables.c
@@ -10,6 +10,8 @@
 #include "common.h"
 #include "variables.h"
 
+#include "fe_utils/logging.h"
+
 
 /*
  * Check whether a variable's name is allowed.
@@ -136,7 +138,7 @@ ParseVariableBool(const char *value, const char *name, bool *result)
 	{
 		/* string is not recognized; don't clobber *result */
 		if (name)
-			psql_error("unrecognized value \"%s\" for \"%s\": Boolean expected\n",
+			pg_log_error("unrecognized value \"%s\" for \"%s\": Boolean expected",
 					   value, name);
 		valid = false;
 	}
@@ -173,7 +175,7 @@ ParseVariableNum(const char *value, const char *name, int *result)
 	{
 		/* string is not recognized; don't clobber *result */
 		if (name)
-			psql_error("invalid value \"%s\" for \"%s\": integer expected\n",
+			pg_log_error("invalid value \"%s\" for \"%s\": integer expected",
 					   value, name);
 		return false;
 	}
@@ -221,7 +223,7 @@ SetVariable(VariableSpace space, const char *name, const char *value)
 		/* Deletion of non-existent variable is not an error */
 		if (!value)
 			return true;
-		psql_error("invalid variable name: \"%s\"\n", name);
+		pg_log_error("invalid variable name: \"%s\"", name);
 		return false;
 	}
 
@@ -390,6 +392,7 @@ DeleteVariable(VariableSpace space, const char *name)
 void
 PsqlVarEnumError(const char *name, const char *value, const char *suggestions)
 {
-	psql_error("unrecognized value \"%s\" for \"%s\"\nAvailable values are: %s.\n",
+	pg_log_error("unrecognized value \"%s\" for \"%s\"\n"
+				 "Available values are: %s.",
 			   value, name, suggestions);
 }
diff --git a/src/bin/scripts/clusterdb.c b/src/bin/scripts/clusterdb.c
index 41dd2a5758..55ba1c80b7 100644
--- a/src/bin/scripts/clusterdb.c
+++ b/src/bin/scripts/clusterdb.c
@@ -11,6 +11,7 @@
 
 #include "postgres_fe.h"
 #include "common.h"
+#include "fe_utils/logging.h"
 #include "fe_utils/simple_list.h"
 #include "fe_utils/string_utils.h"
 
@@ -64,6 +65,7 @@ main(int argc, char *argv[])
 
 	progname = get_progname(argv[0]);
 	set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pgscripts"));
+	pg_logging_init(argv[0]);
 
 	handle_help_version_opts(argc, argv, "clusterdb", help);
 
@@ -125,8 +127,8 @@ main(int argc, char *argv[])
 
 	if (optind < argc)
 	{
-		fprintf(stderr, _("%s: too many command-line arguments (first is \"%s\")\n"),
-				progname, argv[optind]);
+		pg_log_error("too many command-line arguments (first is \"%s\")",
+					 argv[optind]);
 		fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
 		exit(1);
 	}
@@ -137,15 +139,13 @@ main(int argc, char *argv[])
 	{
 		if (dbname)
 		{
-			fprintf(stderr, _("%s: cannot cluster all databases and a specific one at the same time\n"),
-					progname);
+			pg_log_error("cannot cluster all databases and a specific one at the same time");
 			exit(1);
 		}
 
 		if (tables.head != NULL)
 		{
-			fprintf(stderr, _("%s: cannot cluster specific table(s) in all databases\n"),
-					progname);
+			pg_log_error("cannot cluster specific table(s) in all databases");
 			exit(1);
 		}
 
@@ -213,11 +213,11 @@ cluster_one_database(const char *dbname, bool verbose, const char *table,
 	if (!executeMaintenanceCommand(conn, sql.data, echo))
 	{
 		if (table)
-			fprintf(stderr, _("%s: clustering of table \"%s\" in database \"%s\" failed: %s"),
-					progname, table, PQdb(conn), PQerrorMessage(conn));
+			pg_log_error("clustering of table \"%s\" in database \"%s\" failed: %s",
+						 table, PQdb(conn), PQerrorMessage(conn));
 		else
-			fprintf(stderr, _("%s: clustering of database \"%s\" failed: %s"),
-					progname, PQdb(conn), PQerrorMessage(conn));
+			pg_log_error("clustering of database \"%s\" failed: %s",
+						 PQdb(conn), PQerrorMessage(conn));
 		PQfinish(conn);
 		exit(1);
 	}
diff --git a/src/bin/scripts/common.c b/src/bin/scripts/common.c
index 4215bc3d6e..ab4d95b258 100644
--- a/src/bin/scripts/common.c
+++ b/src/bin/scripts/common.c
@@ -19,6 +19,7 @@
 
 #include "common.h"
 #include "fe_utils/connect.h"
+#include "fe_utils/logging.h"
 #include "fe_utils/string_utils.h"
 
 
@@ -113,8 +114,8 @@ connectDatabase(const char *dbname, const char *pghost,
 
 		if (!conn)
 		{
-			fprintf(stderr, _("%s: could not connect to database %s: out of memory\n"),
-					progname, dbname);
+			pg_log_error("could not connect to database %s: out of memory",
+						 dbname);
 			exit(1);
 		}
 
@@ -140,8 +141,8 @@ connectDatabase(const char *dbname, const char *pghost,
 			PQfinish(conn);
 			return NULL;
 		}
-		fprintf(stderr, _("%s: could not connect to database %s: %s"),
-				progname, dbname, PQerrorMessage(conn));
+		pg_log_error("could not connect to database %s: %s",
+					 dbname, PQerrorMessage(conn));
 		exit(1);
 	}
 
@@ -193,10 +194,8 @@ executeQuery(PGconn *conn, const char *query, const char *progname, bool echo)
 	if (!res ||
 		PQresultStatus(res) != PGRES_TUPLES_OK)
 	{
-		fprintf(stderr, _("%s: query failed: %s"),
-				progname, PQerrorMessage(conn));
-		fprintf(stderr, _("%s: query was: %s\n"),
-				progname, query);
+		pg_log_error("query failed: %s", PQerrorMessage(conn));
+		pg_log_info("query was: %s", query);
 		PQfinish(conn);
 		exit(1);
 	}
@@ -221,10 +220,8 @@ executeCommand(PGconn *conn, const char *query,
 	if (!res ||
 		PQresultStatus(res) != PGRES_COMMAND_OK)
 	{
-		fprintf(stderr, _("%s: query failed: %s"),
-				progname, PQerrorMessage(conn));
-		fprintf(stderr, _("%s: query was: %s\n"),
-				progname, query);
+		pg_log_error("query failed: %s", PQerrorMessage(conn));
+		pg_log_info("query was: %s", query);
 		PQfinish(conn);
 		exit(1);
 	}
@@ -347,11 +344,10 @@ appendQualifiedRelation(PQExpBuffer buf, const char *spec,
 	ntups = PQntuples(res);
 	if (ntups != 1)
 	{
-		fprintf(stderr,
-				ngettext("%s: query returned %d row instead of one: %s\n",
-						 "%s: query returned %d rows instead of one: %s\n",
-						 ntups),
-				progname, ntups, sql.data);
+		pg_log_error(ngettext("query returned %d row instead of one: %s",
+							  "query returned %d rows instead of one: %s",
+							  ntups),
+					 ntups, sql.data);
 		PQfinish(conn);
 		exit(1);
 	}
diff --git a/src/bin/scripts/createdb.c b/src/bin/scripts/createdb.c
index c765b8ec66..884b868f88 100644
--- a/src/bin/scripts/createdb.c
+++ b/src/bin/scripts/createdb.c
@@ -12,6 +12,7 @@
 #include "postgres_fe.h"
 
 #include "common.h"
+#include "fe_utils/logging.h"
 #include "fe_utils/string_utils.h"
 
 
@@ -66,6 +67,7 @@ main(int argc, char *argv[])
 
 	progname = get_progname(argv[0]);
 	set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pgscripts"));
+	pg_logging_init(argv[0]);
 
 	handle_help_version_opts(argc, argv, "createdb", help);
 
@@ -133,8 +135,8 @@ main(int argc, char *argv[])
 			comment = argv[optind + 1];
 			break;
 		default:
-			fprintf(stderr, _("%s: too many command-line arguments (first is \"%s\")\n"),
-					progname, argv[optind + 2]);
+			pg_log_error("too many command-line arguments (first is \"%s\")",
+						 argv[optind + 2]);
 			fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
 			exit(1);
 	}
@@ -143,14 +145,12 @@ main(int argc, char *argv[])
 	{
 		if (lc_ctype)
 		{
-			fprintf(stderr, _("%s: only one of --locale and --lc-ctype can be specified\n"),
-					progname);
+			pg_log_error("only one of --locale and --lc-ctype can be specified");
 			exit(1);
 		}
 		if (lc_collate)
 		{
-			fprintf(stderr, _("%s: only one of --locale and --lc-collate can be specified\n"),
-					progname);
+			pg_log_error("only one of --locale and --lc-collate can be specified");
 			exit(1);
 		}
 		lc_ctype = locale;
@@ -161,8 +161,7 @@ main(int argc, char *argv[])
 	{
 		if (pg_char_to_encoding(encoding) < 0)
 		{
-			fprintf(stderr, _("%s: \"%s\" is not a valid encoding name\n"),
-					progname, encoding);
+			pg_log_error("\"%s\" is not a valid encoding name", encoding);
 			exit(1);
 		}
 	}
@@ -210,8 +209,7 @@ main(int argc, char *argv[])
 
 	if (PQresultStatus(result) != PGRES_COMMAND_OK)
 	{
-		fprintf(stderr, _("%s: database creation failed: %s"),
-				progname, PQerrorMessage(conn));
+		pg_log_error("database creation failed: %s", PQerrorMessage(conn));
 		PQfinish(conn);
 		exit(1);
 	}
@@ -230,8 +228,8 @@ main(int argc, char *argv[])
 
 		if (PQresultStatus(result) != PGRES_COMMAND_OK)
 		{
-			fprintf(stderr, _("%s: comment creation failed (database was created): %s"),
-					progname, PQerrorMessage(conn));
+			pg_log_error("comment creation failed (database was created): %s",
+						 PQerrorMessage(conn));
 			PQfinish(conn);
 			exit(1);
 		}
diff --git a/src/bin/scripts/createuser.c b/src/bin/scripts/createuser.c
index 8098f482bb..782c924cd3 100644
--- a/src/bin/scripts/createuser.c
+++ b/src/bin/scripts/createuser.c
@@ -12,6 +12,7 @@
 
 #include "postgres_fe.h"
 #include "common.h"
+#include "fe_utils/logging.h"
 #include "fe_utils/simple_list.h"
 #include "fe_utils/string_utils.h"
 
@@ -83,6 +84,7 @@ main(int argc, char *argv[])
 
 	progname = get_progname(argv[0]);
 	set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pgscripts"));
+	pg_logging_init(argv[0]);
 
 	handle_help_version_opts(argc, argv, "createuser", help);
 
@@ -176,8 +178,8 @@ main(int argc, char *argv[])
 			newuser = argv[optind];
 			break;
 		default:
-			fprintf(stderr, _("%s: too many command-line arguments (first is \"%s\")\n"),
-					progname, argv[optind + 1]);
+			pg_log_error("too many command-line arguments (first is \"%s\")",
+						 argv[optind + 1]);
 			fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
 			exit(1);
 	}
@@ -269,8 +271,8 @@ main(int argc, char *argv[])
 												   NULL);
 		if (!encrypted_password)
 		{
-			fprintf(stderr, _("%s: password encryption failed: %s"),
-					progname, PQerrorMessage(conn));
+			pg_log_error("password encryption failed: %s",
+						 PQerrorMessage(conn));
 			exit(1);
 		}
 		appendStringLiteralConn(&sql, encrypted_password, conn);
@@ -324,8 +326,7 @@ main(int argc, char *argv[])
 
 	if (PQresultStatus(result) != PGRES_COMMAND_OK)
 	{
-		fprintf(stderr, _("%s: creation of new role failed: %s"),
-				progname, PQerrorMessage(conn));
+		pg_log_error("creation of new role failed: %s", PQerrorMessage(conn));
 		PQfinish(conn);
 		exit(1);
 	}
diff --git a/src/bin/scripts/dropdb.c b/src/bin/scripts/dropdb.c
index 45680dde27..797aec09b9 100644
--- a/src/bin/scripts/dropdb.c
+++ b/src/bin/scripts/dropdb.c
@@ -12,6 +12,7 @@
 
 #include "postgres_fe.h"
 #include "common.h"
+#include "fe_utils/logging.h"
 #include "fe_utils/string_utils.h"
 
 
@@ -56,6 +57,7 @@ main(int argc, char *argv[])
 
 	progname = get_progname(argv[0]);
 	set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pgscripts"));
+	pg_logging_init(argv[0]);
 
 	handle_help_version_opts(argc, argv, "dropdb", help);
 
@@ -99,15 +101,15 @@ main(int argc, char *argv[])
 	switch (argc - optind)
 	{
 		case 0:
-			fprintf(stderr, _("%s: missing required argument database name\n"), progname);
+			pg_log_error("missing required argument database name");
 			fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
 			exit(1);
 		case 1:
 			dbname = argv[optind];
 			break;
 		default:
-			fprintf(stderr, _("%s: too many command-line arguments (first is \"%s\")\n"),
-					progname, argv[optind + 1]);
+			pg_log_error("too many command-line arguments (first is \"%s\")",
+						 argv[optind + 1]);
 			fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
 			exit(1);
 	}
@@ -137,8 +139,7 @@ main(int argc, char *argv[])
 	result = PQexec(conn, sql.data);
 	if (PQresultStatus(result) != PGRES_COMMAND_OK)
 	{
-		fprintf(stderr, _("%s: database removal failed: %s"),
-				progname, PQerrorMessage(conn));
+		pg_log_error("database removal failed: %s", PQerrorMessage(conn));
 		PQfinish(conn);
 		exit(1);
 	}
diff --git a/src/bin/scripts/dropuser.c b/src/bin/scripts/dropuser.c
index 2b6f721844..37a0c98582 100644
--- a/src/bin/scripts/dropuser.c
+++ b/src/bin/scripts/dropuser.c
@@ -12,6 +12,7 @@
 
 #include "postgres_fe.h"
 #include "common.h"
+#include "fe_utils/logging.h"
 #include "fe_utils/string_utils.h"
 
 
@@ -55,6 +56,7 @@ main(int argc, char *argv[])
 
 	progname = get_progname(argv[0]);
 	set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pgscripts"));
+	pg_logging_init(argv[0]);
 
 	handle_help_version_opts(argc, argv, "dropuser", help);
 
@@ -100,8 +102,8 @@ main(int argc, char *argv[])
 			dropuser = argv[optind];
 			break;
 		default:
-			fprintf(stderr, _("%s: too many command-line arguments (first is \"%s\")\n"),
-					progname, argv[optind + 1]);
+			pg_log_error("too many command-line arguments (first is \"%s\")",
+						 argv[optind + 1]);
 			fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
 			exit(1);
 	}
@@ -116,7 +118,7 @@ main(int argc, char *argv[])
 		}
 		else
 		{
-			fprintf(stderr, _("%s: missing required argument role name\n"), progname);
+			pg_log_error("missing required argument role name");
 			fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
 			exit(1);
 		}
@@ -142,8 +144,8 @@ main(int argc, char *argv[])
 
 	if (PQresultStatus(result) != PGRES_COMMAND_OK)
 	{
-		fprintf(stderr, _("%s: removal of role \"%s\" failed: %s"),
-				progname, dropuser, PQerrorMessage(conn));
+		pg_log_error("removal of role \"%s\" failed: %s",
+					 dropuser, PQerrorMessage(conn));
 		PQfinish(conn);
 		exit(1);
 	}
diff --git a/src/bin/scripts/nls.mk b/src/bin/scripts/nls.mk
index 4038cdb3b6..2c99a6a461 100644
--- a/src/bin/scripts/nls.mk
+++ b/src/bin/scripts/nls.mk
@@ -1,11 +1,13 @@
 # src/bin/scripts/nls.mk
 CATALOG_NAME     = pgscripts
 AVAIL_LANGUAGES  = cs de es fr he it ja ko pl pt_BR ru sv tr zh_CN
-GETTEXT_FILES    = createdb.c createuser.c \
+GETTEXT_FILES    = $(FRONTEND_COMMON_GETTEXT_FILES) \
+                   createdb.c createuser.c \
                    dropdb.c dropuser.c \
                    clusterdb.c vacuumdb.c reindexdb.c \
                    pg_isready.c \
                    common.c \
                    ../../fe_utils/print.c \
                    ../../common/fe_memutils.c ../../common/username.c
-GETTEXT_TRIGGERS = simple_prompt yesno_prompt
+GETTEXT_TRIGGERS = $(FRONTEND_COMMON_GETTEXT_TRIGGERS) simple_prompt yesno_prompt
+GETTEXT_FLAGS    = $(FRONTEND_COMMON_GETTEXT_FLAGS)
diff --git a/src/bin/scripts/pg_isready.c b/src/bin/scripts/pg_isready.c
index 467c22891c..7025df5202 100644
--- a/src/bin/scripts/pg_isready.c
+++ b/src/bin/scripts/pg_isready.c
@@ -11,6 +11,7 @@
 
 #include "postgres_fe.h"
 #include "common.h"
+#include "fe_utils/logging.h"
 
 #define DEFAULT_CONNECT_TIMEOUT "3"
 
@@ -65,6 +66,7 @@ main(int argc, char **argv)
 
 	progname = get_progname(argv[0]);
 	set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pgscripts"));
+	pg_logging_init(argv[0]);
 	handle_help_version_opts(argc, argv, progname, help);
 
 	while ((c = getopt_long(argc, argv, "d:h:p:qt:U:", long_options, NULL)) != -1)
@@ -102,8 +104,8 @@ main(int argc, char **argv)
 
 	if (optind < argc)
 	{
-		fprintf(stderr, _("%s: too many command-line arguments (first is \"%s\")\n"),
-				progname, argv[optind]);
+		pg_log_error("too many command-line arguments (first is \"%s\")",
+					 argv[optind]);
 		fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
 
 		/*
@@ -139,7 +141,7 @@ main(int argc, char **argv)
 		opts = PQconninfoParse(pgdbname, &errmsg);
 		if (opts == NULL)
 		{
-			fprintf(stderr, _("%s: %s"), progname, errmsg);
+			pg_log_error("%s", errmsg);
 			exit(PQPING_NO_ATTEMPT);
 		}
 	}
@@ -147,7 +149,7 @@ main(int argc, char **argv)
 	defs = PQconndefaults();
 	if (defs == NULL)
 	{
-		fprintf(stderr, _("%s: could not fetch default options\n"), progname);
+		pg_log_error("could not fetch default options");
 		exit(PQPING_NO_ATTEMPT);
 	}
 
diff --git a/src/bin/scripts/reindexdb.c b/src/bin/scripts/reindexdb.c
index 69fb2f8fd2..5526ebbc1b 100644
--- a/src/bin/scripts/reindexdb.c
+++ b/src/bin/scripts/reindexdb.c
@@ -11,6 +11,7 @@
 
 #include "postgres_fe.h"
 #include "common.h"
+#include "fe_utils/logging.h"
 #include "fe_utils/simple_list.h"
 #include "fe_utils/string_utils.h"
 
@@ -74,6 +75,7 @@ main(int argc, char *argv[])
 
 	progname = get_progname(argv[0]);
 	set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pgscripts"));
+	pg_logging_init(argv[0]);
 
 	handle_help_version_opts(argc, argv, "reindexdb", help);
 
@@ -145,8 +147,8 @@ main(int argc, char *argv[])
 
 	if (optind < argc)
 	{
-		fprintf(stderr, _("%s: too many command-line arguments (first is \"%s\")\n"),
-				progname, argv[optind]);
+		pg_log_error("too many command-line arguments (first is \"%s\")",
+					 argv[optind]);
 		fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
 		exit(1);
 	}
@@ -157,27 +159,27 @@ main(int argc, char *argv[])
 	{
 		if (dbname)
 		{
-			fprintf(stderr, _("%s: cannot reindex all databases and a specific one at the same time\n"), progname);
+			pg_log_error("cannot reindex all databases and a specific one at the same time");
 			exit(1);
 		}
 		if (syscatalog)
 		{
-			fprintf(stderr, _("%s: cannot reindex all databases and system catalogs at the same time\n"), progname);
+			pg_log_error("cannot reindex all databases and system catalogs at the same time");
 			exit(1);
 		}
 		if (schemas.head != NULL)
 		{
-			fprintf(stderr, _("%s: cannot reindex specific schema(s) in all databases\n"), progname);
+			pg_log_error("cannot reindex specific schema(s) in all databases");
 			exit(1);
 		}
 		if (tables.head != NULL)
 		{
-			fprintf(stderr, _("%s: cannot reindex specific table(s) in all databases\n"), progname);
+			pg_log_error("cannot reindex specific table(s) in all databases");
 			exit(1);
 		}
 		if (indexes.head != NULL)
 		{
-			fprintf(stderr, _("%s: cannot reindex specific index(es) in all databases\n"), progname);
+			pg_log_error("cannot reindex specific index(es) in all databases");
 			exit(1);
 		}
 
@@ -188,17 +190,17 @@ main(int argc, char *argv[])
 	{
 		if (schemas.head != NULL)
 		{
-			fprintf(stderr, _("%s: cannot reindex specific schema(s) and system catalogs at the same time\n"), progname);
+			pg_log_error("cannot reindex specific schema(s) and system catalogs at the same time");
 			exit(1);
 		}
 		if (tables.head != NULL)
 		{
-			fprintf(stderr, _("%s: cannot reindex specific table(s) and system catalogs at the same time\n"), progname);
+			pg_log_error("cannot reindex specific table(s) and system catalogs at the same time");
 			exit(1);
 		}
 		if (indexes.head != NULL)
 		{
-			fprintf(stderr, _("%s: cannot reindex specific index(es) and system catalogs at the same time\n"), progname);
+			pg_log_error("cannot reindex specific index(es) and system catalogs at the same time");
 			exit(1);
 		}
 
@@ -305,17 +307,17 @@ reindex_one_database(const char *name, const char *dbname, const char *type,
 	if (!executeMaintenanceCommand(conn, sql.data, echo))
 	{
 		if (strcmp(type, "TABLE") == 0)
-			fprintf(stderr, _("%s: reindexing of table \"%s\" in database \"%s\" failed: %s"),
-					progname, name, PQdb(conn), PQerrorMessage(conn));
+			pg_log_error("reindexing of table \"%s\" in database \"%s\" failed: %s",
+						 name, PQdb(conn), PQerrorMessage(conn));
 		if (strcmp(type, "INDEX") == 0)
-			fprintf(stderr, _("%s: reindexing of index \"%s\" in database \"%s\" failed: %s"),
-					progname, name, PQdb(conn), PQerrorMessage(conn));
+			pg_log_error("reindexing of index \"%s\" in database \"%s\" failed: %s",
+						 name, PQdb(conn), PQerrorMessage(conn));
 		if (strcmp(type, "SCHEMA") == 0)
-			fprintf(stderr, _("%s: reindexing of schema \"%s\" in database \"%s\" failed: %s"),
-					progname, name, PQdb(conn), PQerrorMessage(conn));
+			pg_log_error("reindexing of schema \"%s\" in database \"%s\" failed: %s",
+						 name, PQdb(conn), PQerrorMessage(conn));
 		else
-			fprintf(stderr, _("%s: reindexing of database \"%s\" failed: %s"),
-					progname, PQdb(conn), PQerrorMessage(conn));
+			pg_log_error("reindexing of database \"%s\" failed: %s",
+						 PQdb(conn), PQerrorMessage(conn));
 		PQfinish(conn);
 		exit(1);
 	}
@@ -386,8 +388,8 @@ reindex_system_catalogs(const char *dbname, const char *host, const char *port,
 
 	if (!executeMaintenanceCommand(conn, sql.data, echo))
 	{
-		fprintf(stderr, _("%s: reindexing of system catalogs failed: %s"),
-				progname, PQerrorMessage(conn));
+		pg_log_error("reindexing of system catalogs failed: %s",
+					 PQerrorMessage(conn));
 		PQfinish(conn);
 		exit(1);
 	}
diff --git a/src/bin/scripts/vacuumdb.c b/src/bin/scripts/vacuumdb.c
index 127b75e0b4..d449be59ad 100644
--- a/src/bin/scripts/vacuumdb.c
+++ b/src/bin/scripts/vacuumdb.c
@@ -19,6 +19,7 @@
 #include "catalog/pg_class_d.h"
 
 #include "common.h"
+#include "fe_utils/logging.h"
 #include "fe_utils/simple_list.h"
 #include "fe_utils/string_utils.h"
 
@@ -141,6 +142,7 @@ main(int argc, char *argv[])
 	progname = get_progname(argv[0]);
 
 	set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pgscripts"));
+	pg_logging_init(argv[0]);
 
 	handle_help_version_opts(argc, argv, "vacuumdb", help);
 
@@ -200,14 +202,13 @@ main(int argc, char *argv[])
 				concurrentCons = atoi(optarg);
 				if (concurrentCons <= 0)
 				{
-					fprintf(stderr, _("%s: number of parallel jobs must be at least 1\n"),
-							progname);
+					pg_log_error("number of parallel jobs must be at least 1");
 					exit(1);
 				}
 				if (concurrentCons > FD_SETSIZE - 1)
 				{
-					fprintf(stderr, _("%s: too many parallel jobs requested (maximum: %d)\n"),
-							progname, FD_SETSIZE - 1);
+					pg_log_error("too many parallel jobs requested (maximum: %d)",
+								 FD_SETSIZE - 1);
 					exit(1);
 				}
 				break;
@@ -241,8 +242,8 @@ main(int argc, char *argv[])
 
 	if (optind < argc)
 	{
-		fprintf(stderr, _("%s: too many command-line arguments (first is \"%s\")\n"),
-				progname, argv[optind]);
+		pg_log_error("too many command-line arguments (first is \"%s\")",
+					 argv[optind]);
 		fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
 		exit(1);
 	}
@@ -251,14 +252,14 @@ main(int argc, char *argv[])
 	{
 		if (vacopts.full)
 		{
-			fprintf(stderr, _("%s: cannot use the \"%s\" option when performing only analyze\n"),
-					progname, "full");
+			pg_log_error("cannot use the \"%s\" option when performing only analyze",
+						 "full");
 			exit(1);
 		}
 		if (vacopts.freeze)
 		{
-			fprintf(stderr, _("%s: cannot use the \"%s\" option when performing only analyze\n"),
-					progname, "freeze");
+			pg_log_error("cannot use the \"%s\" option when performing only analyze",
+						 "freeze");
 			exit(1);
 		}
 		if (vacopts.disable_page_skipping)
@@ -280,14 +281,12 @@ main(int argc, char *argv[])
 	{
 		if (dbname)
 		{
-			fprintf(stderr, _("%s: cannot vacuum all databases and a specific one at the same time\n"),
-					progname);
+			pg_log_error("cannot vacuum all databases and a specific one at the same time");
 			exit(1);
 		}
 		if (tables.head != NULL)
 		{
-			fprintf(stderr, _("%s: cannot vacuum specific table(s) in all databases\n"),
-					progname);
+			pg_log_error("cannot vacuum specific table(s) in all databases");
 			exit(1);
 		}
 
@@ -790,12 +789,11 @@ run_vacuum_command(PGconn *conn, const char *sql, bool echo,
 	if (!status)
 	{
 		if (table)
-			fprintf(stderr,
-					_("%s: vacuuming of table \"%s\" in database \"%s\" failed: %s"),
-					progname, table, PQdb(conn), PQerrorMessage(conn));
+			pg_log_error("vacuuming of table \"%s\" in database \"%s\" failed: %s",
+						 table, PQdb(conn), PQerrorMessage(conn));
 		else
-			fprintf(stderr, _("%s: vacuuming of database \"%s\" failed: %s"),
-					progname, PQdb(conn), PQerrorMessage(conn));
+			pg_log_error("vacuuming of database \"%s\" failed: %s",
+						 PQdb(conn), PQerrorMessage(conn));
 
 		if (!async)
 		{
@@ -929,8 +927,8 @@ ProcessQueryResult(PGconn *conn, PGresult *result, const char *progname)
 	{
 		char	   *sqlState = PQresultErrorField(result, PG_DIAG_SQLSTATE);
 
-		fprintf(stderr, _("%s: vacuuming of database \"%s\" failed: %s"),
-				progname, PQdb(conn), PQerrorMessage(conn));
+		pg_log_error("vacuuming of database \"%s\" failed: %s",
+					 PQdb(conn), PQerrorMessage(conn));
 
 		if (sqlState && strcmp(sqlState, ERRCODE_UNDEFINED_TABLE) != 0)
 		{
diff --git a/src/common/controldata_utils.c b/src/common/controldata_utils.c
index abfe7065f5..17998a9f39 100644
--- a/src/common/controldata_utils.c
+++ b/src/common/controldata_utils.c
@@ -26,10 +26,13 @@
 
 #include "catalog/pg_control.h"
 #include "common/controldata_utils.h"
+#ifdef FRONTEND
+#include "fe_utils/logging.h"
+#endif
 #include "port/pg_crc32c.h"
 
 /*
- * get_controlfile(char *DataDir, const char *progname, bool *crc_ok_p)
+ * get_controlfile(char *DataDir, bool *crc_ok_p)
  *
  * Get controlfile values.  The result is returned as a palloc'd copy of the
  * control file data.
@@ -38,7 +41,7 @@
  * file data is correct.
  */
 ControlFileData *
-get_controlfile(const char *DataDir, const char *progname, bool *crc_ok_p)
+get_controlfile(const char *DataDir, bool *crc_ok_p)
 {
 	ControlFileData *ControlFile;
 	int			fd;
@@ -59,8 +62,8 @@ get_controlfile(const char *DataDir, const char *progname, bool *crc_ok_p)
 						ControlFilePath)));
 #else
 	{
-		fprintf(stderr, _("%s: could not open file \"%s\" for reading: %s\n"),
-				progname, ControlFilePath, strerror(errno));
+		pg_log_fatal("could not open file \"%s\" for reading: %m",
+					 ControlFilePath);
 		exit(EXIT_FAILURE);
 	}
 #endif
@@ -75,8 +78,7 @@ get_controlfile(const char *DataDir, const char *progname, bool *crc_ok_p)
 					 errmsg("could not read file \"%s\": %m", ControlFilePath)));
 #else
 		{
-			fprintf(stderr, _("%s: could not read file \"%s\": %s\n"),
-					progname, ControlFilePath, strerror(errno));
+			pg_log_fatal("could not read file \"%s\": %m", ControlFilePath);
 			exit(EXIT_FAILURE);
 		}
 #endif
@@ -88,8 +90,8 @@ get_controlfile(const char *DataDir, const char *progname, bool *crc_ok_p)
 							ControlFilePath, r, sizeof(ControlFileData))));
 #else
 		{
-			fprintf(stderr, _("%s: could not read file \"%s\": read %d of %zu\n"),
-					progname, ControlFilePath, r, sizeof(ControlFileData));
+			pg_log_fatal("could not read file \"%s\": read %d of %zu",
+						 ControlFilePath, r, sizeof(ControlFileData));
 			exit(EXIT_FAILURE);
 		}
 #endif
@@ -112,10 +114,10 @@ get_controlfile(const char *DataDir, const char *progname, bool *crc_ok_p)
 #ifndef FRONTEND
 		elog(ERROR, _("byte ordering mismatch"));
 #else
-		printf(_("WARNING: possible byte ordering mismatch\n"
-				 "The byte ordering used to store the pg_control file might not match the one\n"
-				 "used by this program.  In that case the results below would be incorrect, and\n"
-				 "the PostgreSQL installation would be incompatible with this data directory.\n"));
+		pg_log_warning("possible byte ordering mismatch\n"
+					   "The byte ordering used to store the pg_control file might not match the one\n"
+					   "used by this program.  In that case the results below would be incorrect, and\n"
+					   "the PostgreSQL installation would be incompatible with this data directory.");
 #endif
 
 	return ControlFile;
diff --git a/src/common/file_utils.c b/src/common/file_utils.c
index 4bcb9c1e05..e45b0d8e0e 100644
--- a/src/common/file_utils.c
+++ b/src/common/file_utils.c
@@ -20,6 +20,7 @@
 #include <unistd.h>
 
 #include "common/file_utils.h"
+#include "fe_utils/logging.h"
 
 
 /* Define PG_FLUSH_DATA_WORKS if we have an implementation for pg_flush_data */
@@ -35,12 +36,11 @@
 #define MINIMUM_VERSION_FOR_PG_WAL	100000
 
 #ifdef PG_FLUSH_DATA_WORKS
-static int pre_sync_fname(const char *fname, bool isdir,
-			   const char *progname);
+static int pre_sync_fname(const char *fname, bool isdir);
 #endif
 static void walkdir(const char *path,
-		int (*action) (const char *fname, bool isdir, const char *progname),
-		bool process_symlinks, const char *progname);
+		int (*action) (const char *fname, bool isdir),
+		bool process_symlinks);
 
 /*
  * Issue fsync recursively on PGDATA and all its contents.
@@ -56,7 +56,6 @@ static void walkdir(const char *path,
  */
 void
 fsync_pgdata(const char *pg_data,
-			 const char *progname,
 			 int serverVersion)
 {
 	bool		xlog_is_symlink;
@@ -79,8 +78,7 @@ fsync_pgdata(const char *pg_data,
 		struct stat st;
 
 		if (lstat(pg_wal, &st) < 0)
-			fprintf(stderr, _("%s: could not stat file \"%s\": %s\n"),
-					progname, pg_wal, strerror(errno));
+			pg_log_error("could not stat file \"%s\": %m", pg_wal);
 		else if (S_ISLNK(st.st_mode))
 			xlog_is_symlink = true;
 	}
@@ -94,10 +92,10 @@ fsync_pgdata(const char *pg_data,
 	 * directory and its contents.
 	 */
 #ifdef PG_FLUSH_DATA_WORKS
-	walkdir(pg_data, pre_sync_fname, false, progname);
+	walkdir(pg_data, pre_sync_fname, false);
 	if (xlog_is_symlink)
-		walkdir(pg_wal, pre_sync_fname, false, progname);
-	walkdir(pg_tblspc, pre_sync_fname, true, progname);
+		walkdir(pg_wal, pre_sync_fname, false);
+	walkdir(pg_tblspc, pre_sync_fname, true);
 #endif
 
 	/*
@@ -109,10 +107,10 @@ fsync_pgdata(const char *pg_data,
 	 * in pg_tblspc, they'll get fsync'd twice.  That's not an expected case
 	 * so we don't worry about optimizing it.
 	 */
-	walkdir(pg_data, fsync_fname, false, progname);
+	walkdir(pg_data, fsync_fname, false);
 	if (xlog_is_symlink)
-		walkdir(pg_wal, fsync_fname, false, progname);
-	walkdir(pg_tblspc, fsync_fname, true, progname);
+		walkdir(pg_wal, fsync_fname, false);
+	walkdir(pg_tblspc, fsync_fname, true);
 }
 
 /*
@@ -121,17 +119,17 @@ fsync_pgdata(const char *pg_data,
  * This is a convenient wrapper on top of walkdir().
  */
 void
-fsync_dir_recurse(const char *dir, const char *progname)
+fsync_dir_recurse(const char *dir)
 {
 	/*
 	 * If possible, hint to the kernel that we're soon going to fsync the data
 	 * directory and its contents.
 	 */
 #ifdef PG_FLUSH_DATA_WORKS
-	walkdir(dir, pre_sync_fname, false, progname);
+	walkdir(dir, pre_sync_fname, false);
 #endif
 
-	walkdir(dir, fsync_fname, false, progname);
+	walkdir(dir, fsync_fname, false);
 }
 
 /*
@@ -150,8 +148,8 @@ fsync_dir_recurse(const char *dir, const char *progname)
  */
 static void
 walkdir(const char *path,
-		int (*action) (const char *fname, bool isdir, const char *progname),
-		bool process_symlinks, const char *progname)
+		int (*action) (const char *fname, bool isdir),
+		bool process_symlinks)
 {
 	DIR		   *dir;
 	struct dirent *de;
@@ -159,8 +157,7 @@ walkdir(const char *path,
 	dir = opendir(path);
 	if (dir == NULL)
 	{
-		fprintf(stderr, _("%s: could not open directory \"%s\": %s\n"),
-				progname, path, strerror(errno));
+		pg_log_error("could not open directory \"%s\": %m", path);
 		return;
 	}
 
@@ -183,20 +180,18 @@ walkdir(const char *path,
 
 		if (sret < 0)
 		{
-			fprintf(stderr, _("%s: could not stat file \"%s\": %s\n"),
-					progname, subpath, strerror(errno));
+			pg_log_error("could not stat file \"%s\": %m", subpath);
 			continue;
 		}
 
 		if (S_ISREG(fst.st_mode))
-			(*action) (subpath, false, progname);
+			(*action) (subpath, false);
 		else if (S_ISDIR(fst.st_mode))
-			walkdir(subpath, action, false, progname);
+			walkdir(subpath, action, false);
 	}
 
 	if (errno)
-		fprintf(stderr, _("%s: could not read directory \"%s\": %s\n"),
-				progname, path, strerror(errno));
+		pg_log_error("could not read directory \"%s\": %m", path);
 
 	(void) closedir(dir);
 
@@ -206,7 +201,7 @@ walkdir(const char *path,
 	 * synced.  Recent versions of ext4 have made the window much wider but
 	 * it's been an issue for ext3 and other filesystems in the past.
 	 */
-	(*action) (path, true, progname);
+	(*action) (path, true);
 }
 
 /*
@@ -218,7 +213,7 @@ walkdir(const char *path,
 #ifdef PG_FLUSH_DATA_WORKS
 
 static int
-pre_sync_fname(const char *fname, bool isdir, const char *progname)
+pre_sync_fname(const char *fname, bool isdir)
 {
 	int			fd;
 
@@ -228,8 +223,7 @@ pre_sync_fname(const char *fname, bool isdir, const char *progname)
 	{
 		if (errno == EACCES || (isdir && errno == EISDIR))
 			return 0;
-		fprintf(stderr, _("%s: could not open file \"%s\": %s\n"),
-				progname, fname, strerror(errno));
+		pg_log_error("could not open file \"%s\": %m", fname);
 		return -1;
 	}
 
@@ -260,7 +254,7 @@ pre_sync_fname(const char *fname, bool isdir, const char *progname)
  * other errors non-fatally.
  */
 int
-fsync_fname(const char *fname, bool isdir, const char *progname)
+fsync_fname(const char *fname, bool isdir)
 {
 	int			fd;
 	int			flags;
@@ -288,8 +282,7 @@ fsync_fname(const char *fname, bool isdir, const char *progname)
 	{
 		if (errno == EACCES || (isdir && errno == EISDIR))
 			return 0;
-		fprintf(stderr, _("%s: could not open file \"%s\": %s\n"),
-				progname, fname, strerror(errno));
+		pg_log_error("could not open file \"%s\": %m", fname);
 		return -1;
 	}
 
@@ -301,8 +294,7 @@ fsync_fname(const char *fname, bool isdir, const char *progname)
 	 */
 	if (returncode != 0 && !(isdir && errno == EBADF))
 	{
-		fprintf(stderr, _("%s: could not fsync file \"%s\": %s\n"),
-				progname, fname, strerror(errno));
+		pg_log_error("could not fsync file \"%s\": %m", fname);
 		(void) close(fd);
 		return -1;
 	}
@@ -318,7 +310,7 @@ fsync_fname(const char *fname, bool isdir, const char *progname)
  * an OS crash or power failure.
  */
 int
-fsync_parent_path(const char *fname, const char *progname)
+fsync_parent_path(const char *fname)
 {
 	char		parentpath[MAXPGPATH];
 
@@ -333,7 +325,7 @@ fsync_parent_path(const char *fname, const char *progname)
 	if (strlen(parentpath) == 0)
 		strlcpy(parentpath, ".", MAXPGPATH);
 
-	if (fsync_fname(parentpath, true, progname) != 0)
+	if (fsync_fname(parentpath, true) != 0)
 		return -1;
 
 	return 0;
@@ -345,7 +337,7 @@ fsync_parent_path(const char *fname, const char *progname)
  * Wrapper around rename, similar to the backend version.
  */
 int
-durable_rename(const char *oldfile, const char *newfile, const char *progname)
+durable_rename(const char *oldfile, const char *newfile)
 {
 	int			fd;
 
@@ -356,7 +348,7 @@ durable_rename(const char *oldfile, const char *newfile, const char *progname)
 	 * because it's then guaranteed that either source or target file exists
 	 * after a crash.
 	 */
-	if (fsync_fname(oldfile, false, progname) != 0)
+	if (fsync_fname(oldfile, false) != 0)
 		return -1;
 
 	fd = open(newfile, PG_BINARY | O_RDWR, 0);
@@ -364,8 +356,7 @@ durable_rename(const char *oldfile, const char *newfile, const char *progname)
 	{
 		if (errno != ENOENT)
 		{
-			fprintf(stderr, _("%s: could not open file \"%s\": %s\n"),
-					progname, newfile, strerror(errno));
+			pg_log_error("could not open file \"%s\": %m", newfile);
 			return -1;
 		}
 	}
@@ -373,8 +364,7 @@ durable_rename(const char *oldfile, const char *newfile, const char *progname)
 	{
 		if (fsync(fd) != 0)
 		{
-			fprintf(stderr, _("%s: could not fsync file \"%s\": %s\n"),
-					progname, newfile, strerror(errno));
+			pg_log_error("could not fsync file \"%s\": %m", newfile);
 			close(fd);
 			return -1;
 		}
@@ -384,8 +374,8 @@ durable_rename(const char *oldfile, const char *newfile, const char *progname)
 	/* Time to do the real deal... */
 	if (rename(oldfile, newfile) != 0)
 	{
-		fprintf(stderr, _("%s: could not rename file \"%s\" to \"%s\": %s\n"),
-				progname, oldfile, newfile, strerror(errno));
+		pg_log_error("could not rename file \"%s\" to \"%s\": %m",
+					 oldfile, newfile);
 		return -1;
 	}
 
@@ -393,10 +383,10 @@ durable_rename(const char *oldfile, const char *newfile, const char *progname)
 	 * To guarantee renaming the file is persistent, fsync the file with its
 	 * new name, and its containing directory.
 	 */
-	if (fsync_fname(newfile, false, progname) != 0)
+	if (fsync_fname(newfile, false) != 0)
 		return -1;
 
-	if (fsync_parent_path(newfile, progname) != 0)
+	if (fsync_parent_path(newfile) != 0)
 		return -1;
 
 	return 0;
diff --git a/src/common/pgfnames.c b/src/common/pgfnames.c
index f9e0a69be0..95b17e47d8 100644
--- a/src/common/pgfnames.c
+++ b/src/common/pgfnames.c
@@ -20,6 +20,12 @@
 
 #include <dirent.h>
 
+#ifndef FRONTEND
+#define pg_log_warning(...) elog(WARNING, __VA_ARGS__)
+#else
+#include "fe_utils/logging.h"
+#endif
+
 /*
  * pgfnames
  *
@@ -39,12 +45,7 @@ pgfnames(const char *path)
 	dir = opendir(path);
 	if (dir == NULL)
 	{
-#ifndef FRONTEND
-		elog(WARNING, "could not open directory \"%s\": %m", path);
-#else
-		fprintf(stderr, _("could not open directory \"%s\": %s\n"),
-				path, strerror(errno));
-#endif
+		pg_log_warning("could not open directory \"%s\": %m", path);
 		return NULL;
 	}
 
@@ -65,26 +66,12 @@ pgfnames(const char *path)
 	}
 
 	if (errno)
-	{
-#ifndef FRONTEND
-		elog(WARNING, "could not read directory \"%s\": %m", path);
-#else
-		fprintf(stderr, _("could not read directory \"%s\": %s\n"),
-				path, strerror(errno));
-#endif
-	}
+		pg_log_warning("could not read directory \"%s\": %m", path);
 
 	filenames[numnames] = NULL;
 
 	if (closedir(dir))
-	{
-#ifndef FRONTEND
-		elog(WARNING, "could not close directory \"%s\": %m", path);
-#else
-		fprintf(stderr, _("could not close directory \"%s\": %s\n"),
-				path, strerror(errno));
-#endif
-	}
+		pg_log_warning("could not close directory \"%s\": %m", path);
 
 	return filenames;
 }
diff --git a/src/common/restricted_token.c b/src/common/restricted_token.c
index c4ccc0e55c..3f57ff8b40 100644
--- a/src/common/restricted_token.c
+++ b/src/common/restricted_token.c
@@ -21,6 +21,7 @@
 #include "postgres_fe.h"
 
 #include "common/restricted_token.h"
+#include "fe_utils/logging.h"
 
 #ifdef WIN32
 
@@ -43,7 +44,7 @@ typedef BOOL (WINAPI * __CreateRestrictedToken) (HANDLE, DWORD, DWORD, PSID_AND_
  * NOT execute anything.
  */
 HANDLE
-CreateRestrictedProcess(char *cmd, PROCESS_INFORMATION *processInfo, const char *progname)
+CreateRestrictedProcess(char *cmd, PROCESS_INFORMATION *processInfo)
 {
 	BOOL		b;
 	STARTUPINFO si;
@@ -65,7 +66,7 @@ CreateRestrictedProcess(char *cmd, PROCESS_INFORMATION *processInfo, const char
 
 	if (_CreateRestrictedToken == NULL)
 	{
-		fprintf(stderr, _("%s: WARNING: cannot create restricted tokens on this platform\n"), progname);
+		pg_log_warning("cannot create restricted tokens on this platform");
 		if (Advapi32Handle != NULL)
 			FreeLibrary(Advapi32Handle);
 		return 0;
@@ -74,7 +75,7 @@ CreateRestrictedProcess(char *cmd, PROCESS_INFORMATION *processInfo, const char
 	/* Open the current token to use as a base for the restricted one */
 	if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &origToken))
 	{
-		fprintf(stderr, _("%s: could not open process token: error code %lu\n"), progname, GetLastError());
+		pg_log_error("could not open process token: error code %lu", GetLastError());
 		return 0;
 	}
 
@@ -87,8 +88,7 @@ CreateRestrictedProcess(char *cmd, PROCESS_INFORMATION *processInfo, const char
 								  SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_POWER_USERS, 0, 0, 0, 0, 0,
 								  0, &dropSids[1].Sid))
 	{
-		fprintf(stderr, _("%s: could not allocate SIDs: error code %lu\n"),
-				progname, GetLastError());
+		pg_log_error("could not allocate SIDs: error code %lu", GetLastError());
 		return 0;
 	}
 
@@ -107,8 +107,7 @@ CreateRestrictedProcess(char *cmd, PROCESS_INFORMATION *processInfo, const char
 
 	if (!b)
 	{
-		fprintf(stderr, _("%s: could not create restricted token: error code %lu\n"),
-				progname, GetLastError());
+		pg_log_error("could not create restricted token: error code %lu", GetLastError());
 		return 0;
 	}
 
@@ -129,7 +128,7 @@ CreateRestrictedProcess(char *cmd, PROCESS_INFORMATION *processInfo, const char
 							 processInfo))
 
 	{
-		fprintf(stderr, _("%s: could not start process for command \"%s\": error code %lu\n"), progname, cmd, GetLastError());
+		pg_log_error("could not start process for command \"%s\": error code %lu", cmd, GetLastError());
 		return 0;
 	}
 
@@ -143,7 +142,7 @@ CreateRestrictedProcess(char *cmd, PROCESS_INFORMATION *processInfo, const char
  * On other platforms do nothing.
  */
 void
-get_restricted_token(const char *progname)
+get_restricted_token(void)
 {
 #ifdef WIN32
 	HANDLE		restrictedToken;
@@ -165,9 +164,9 @@ get_restricted_token(const char *progname)
 
 		putenv("PG_RESTRICT_EXEC=1");
 
-		if ((restrictedToken = CreateRestrictedProcess(cmdline, &pi, progname)) == 0)
+		if ((restrictedToken = CreateRestrictedProcess(cmdline, &pi)) == 0)
 		{
-			fprintf(stderr, _("%s: could not re-execute with restricted token: error code %lu\n"), progname, GetLastError());
+			pg_log_error("could not re-execute with restricted token: error code %lu", GetLastError());
 		}
 		else
 		{
@@ -183,7 +182,7 @@ get_restricted_token(const char *progname)
 
 			if (!GetExitCodeProcess(pi.hProcess, &x))
 			{
-				fprintf(stderr, _("%s: could not get exit code from subprocess: error code %lu\n"), progname, GetLastError());
+				pg_log_error("could not get exit code from subprocess: error code %lu", GetLastError());
 				exit(1);
 			}
 			exit(x);
diff --git a/src/common/rmtree.c b/src/common/rmtree.c
index 57164d45d6..3052d013ee 100644
--- a/src/common/rmtree.c
+++ b/src/common/rmtree.c
@@ -20,6 +20,12 @@
 #include <unistd.h>
 #include <sys/stat.h>
 
+#ifndef FRONTEND
+#define pg_log_warning(...) elog(WARNING, __VA_ARGS__)
+#else
+#include "fe_utils/logging.h"
+#endif
+
 
 /*
  *	rmtree
@@ -70,13 +76,8 @@ rmtree(const char *path, bool rmtopdir)
 		{
 			if (errno != ENOENT)
 			{
-#ifndef FRONTEND
-				elog(WARNING, "could not stat file or directory \"%s\": %m",
+				pg_log_warning("could not stat file or directory \"%s\": %m",
 					 pathbuf);
-#else
-				fprintf(stderr, _("could not stat file or directory \"%s\": %s\n"),
-						pathbuf, strerror(errno));
-#endif
 				result = false;
 			}
 			continue;
@@ -97,13 +98,8 @@ rmtree(const char *path, bool rmtopdir)
 			{
 				if (errno != ENOENT)
 				{
-#ifndef FRONTEND
-					elog(WARNING, "could not remove file or directory \"%s\": %m",
+					pg_log_warning("could not remove file or directory \"%s\": %m",
 						 pathbuf);
-#else
-					fprintf(stderr, _("could not remove file or directory \"%s\": %s\n"),
-							pathbuf, strerror(errno));
-#endif
 					result = false;
 				}
 			}
@@ -114,13 +110,8 @@ rmtree(const char *path, bool rmtopdir)
 	{
 		if (rmdir(path) != 0)
 		{
-#ifndef FRONTEND
-			elog(WARNING, "could not remove file or directory \"%s\": %m",
+			pg_log_warning("could not remove file or directory \"%s\": %m",
 				 path);
-#else
-			fprintf(stderr, _("could not remove file or directory \"%s\": %s\n"),
-					path, strerror(errno));
-#endif
 			result = false;
 		}
 	}
diff --git a/src/fe_utils/Makefile b/src/fe_utils/Makefile
index 7d73800323..960ecf0b6a 100644
--- a/src/fe_utils/Makefile
+++ b/src/fe_utils/Makefile
@@ -19,7 +19,7 @@ include $(top_builddir)/src/Makefile.global
 
 override CPPFLAGS := -DFRONTEND -I$(libpq_srcdir) $(CPPFLAGS)
 
-OBJS = mbprint.o print.o psqlscan.o simple_list.o string_utils.o conditional.o
+OBJS = logging.o mbprint.o print.o psqlscan.o simple_list.o string_utils.o conditional.o
 
 all: libpgfeutils.a
 
diff --git a/src/fe_utils/logging.c b/src/fe_utils/logging.c
new file mode 100644
index 0000000000..8aa8da60f4
--- /dev/null
+++ b/src/fe_utils/logging.c
@@ -0,0 +1,165 @@
+/*-------------------------------------------------------------------------
+ * Logging framework for frontend programs
+ *
+ * Copyright (c) 2018, PostgreSQL Global Development Group
+ *
+ * src/fe_utils/logging.c
+ *
+ *-------------------------------------------------------------------------
+ */
+#include "postgres_fe.h"
+
+#include <unistd.h>
+
+#include "fe_utils/logging.h"
+
+static const char *progname;
+
+enum pg_log_level __pg_log_level;
+static int log_flags;
+void (*log_pre_callback)(void);
+void (*log_locus_callback)(const char **, uint64 *);
+static bool log_color;
+
+const char *sgr_error = "01;31";
+const char *sgr_warning = "01;35";
+const char *sgr_locus = "01";
+
+#define ANSI_ESCAPE_FMT "\x1b[%sm"
+#define ANSI_ESCAPE_RESET "\x1b[0m"
+
+void
+pg_logging_init(const char *argv0)
+{
+	const char *pg_color_env = getenv("PG_COLOR");
+
+	progname = get_progname(argv0);
+	__pg_log_level = PG_LOG_INFO;
+
+	if (pg_color_env)
+	{
+		if (strcmp(pg_color_env, "always") == 0 ||
+			(strcmp(pg_color_env, "auto") == 0 && isatty(fileno(stderr))))
+			log_color = true;
+	}
+}
+
+void
+pg_logging_config(int new_flags)
+{
+	log_flags = new_flags;
+}
+
+void
+pg_logging_set_level(enum pg_log_level new_level)
+{
+	__pg_log_level = new_level;
+}
+
+void
+pg_logging_set_pre_callback(void (*cb)(void))
+{
+	log_pre_callback = cb;
+}
+
+void
+pg_logging_set_locus_callback(void (*cb)(const char **filename, uint64 *lineno))
+{
+	log_locus_callback = cb;
+}
+
+void
+pg_log_generic(enum pg_log_level level, const char * pg_restrict fmt, ...)
+{
+	int			save_errno = errno;
+	const char *filename = NULL;
+	uint64		lineno = 0;
+	va_list		ap;
+	size_t		required_len;
+	char	   *buf;
+
+	Assert(progname);
+	Assert(level);
+	Assert(fmt);
+	Assert(fmt[strlen(fmt) - 1] != '\n');
+
+	fflush(stdout);
+	if (log_pre_callback)
+		log_pre_callback();
+
+	if (log_locus_callback)
+		log_locus_callback(&filename, &lineno);
+
+	fmt = _(fmt);
+
+	if (log_color)
+		fprintf(stderr, ANSI_ESCAPE_FMT, sgr_locus);
+	if (!(log_flags & PG_LOG_FLAG_TERSE))
+		fprintf(stderr, "%s:", progname);
+	if (filename)
+	{
+		fprintf(stderr, "%s:", filename);
+		if (lineno > 0)
+			fprintf(stderr, UINT64_FORMAT ":", lineno);
+	}
+	if (!(log_flags & PG_LOG_FLAG_TERSE) || filename)
+		fprintf(stderr, " ");
+	if (log_color)
+		fprintf(stderr, ANSI_ESCAPE_RESET);
+
+	if (!(log_flags & PG_LOG_FLAG_TERSE))
+	switch (level)
+	{
+		case PG_LOG_FATAL:
+			if (log_color)
+				fprintf(stderr, ANSI_ESCAPE_FMT, sgr_error);
+			fprintf(stderr, _("fatal: "));
+			if (log_color)
+				fprintf(stderr, ANSI_ESCAPE_RESET);
+			break;
+		case PG_LOG_ERROR:
+			if (log_color)
+				fprintf(stderr, ANSI_ESCAPE_FMT, sgr_error);
+			fprintf(stderr, _("error: "));
+			if (log_color)
+				fprintf(stderr, ANSI_ESCAPE_RESET);
+			break;
+		case PG_LOG_WARNING:
+			if (log_color)
+				fprintf(stderr, ANSI_ESCAPE_FMT, sgr_warning);
+			fprintf(stderr, _("warning: "));
+			if (log_color)
+				fprintf(stderr, ANSI_ESCAPE_RESET);
+			break;
+		default:
+			break;
+	}
+
+	errno = save_errno;
+
+	va_start(ap, fmt);
+	required_len = vsnprintf(NULL, 0, fmt, ap) + 1;
+	va_end(ap);
+
+	buf = pg_malloc_extended(required_len, MCXT_ALLOC_NO_OOM);
+
+	if (!buf)
+	{
+		/* memory trouble, just print what we can and get out of here */
+		va_start(ap, fmt);
+		vfprintf(stderr, fmt, ap);
+		va_end(ap);
+		return;
+	}
+
+	va_start(ap, fmt);
+	vsnprintf(buf, required_len, fmt, ap);
+	va_end(ap);
+
+	/* strip one newline, for PQerrorMessage() */
+	if (buf[required_len - 2] == '\n')
+		buf[required_len - 2] = '\0';
+
+	fprintf(stderr, "%s\n", buf);
+	free(buf);
+}
diff --git a/src/fe_utils/psqlscan.l b/src/fe_utils/psqlscan.l
index 321744cddb..ee32547897 100644
--- a/src/fe_utils/psqlscan.l
+++ b/src/fe_utils/psqlscan.l
@@ -34,6 +34,7 @@
  */
 #include "postgres_fe.h"
 
+#include "fe_utils/logging.h"
 #include "fe_utils/psqlscan.h"
 
 #include "libpq-fe.h"
@@ -732,7 +733,7 @@ other			.
 						if (psqlscan_var_is_current_source(cur_state, varname))
 						{
 							/* Recursive expansion --- don't go there */
-							cur_state->callbacks->write_error("skipping recursive expansion of variable \"%s\"\n",
+							pg_log_warning("skipping recursive expansion of variable \"%s\"",
 															  varname);
 							/* Instead copy the string as is */
 							ECHO;
diff --git a/src/include/common/controldata_utils.h b/src/include/common/controldata_utils.h
index 0ffa2000fc..d49c7b0b02 100644
--- a/src/include/common/controldata_utils.h
+++ b/src/include/common/controldata_utils.h
@@ -12,6 +12,6 @@
 
 #include "catalog/pg_control.h"
 
-extern ControlFileData *get_controlfile(const char *DataDir, const char *progname, bool *crc_ok_p);
+extern ControlFileData *get_controlfile(const char *DataDir, bool *crc_ok_p);
 
 #endif							/* COMMON_CONTROLDATA_UTILS_H */
diff --git a/src/include/common/file_utils.h b/src/include/common/file_utils.h
index b1f1a3a1c1..5cb1fd3a00 100644
--- a/src/include/common/file_utils.h
+++ b/src/include/common/file_utils.h
@@ -15,13 +15,10 @@
 #ifndef FILE_UTILS_H
 #define FILE_UTILS_H
 
-extern int fsync_fname(const char *fname, bool isdir,
-			const char *progname);
-extern void fsync_pgdata(const char *pg_data, const char *progname,
-			 int serverVersion);
-extern void fsync_dir_recurse(const char *dir, const char *progname);
-extern int durable_rename(const char *oldfile, const char *newfile,
-			   const char *progname);
-extern int	fsync_parent_path(const char *fname, const char *progname);
+extern int fsync_fname(const char *fname, bool isdir);
+extern void fsync_pgdata(const char *pg_data, int serverVersion);
+extern void fsync_dir_recurse(const char *dir);
+extern int durable_rename(const char *oldfile, const char *newfile);
+extern int	fsync_parent_path(const char *fname);
 
 #endif							/* FILE_UTILS_H */
diff --git a/src/include/common/restricted_token.h b/src/include/common/restricted_token.h
index d71499d07e..078385c6a3 100644
--- a/src/include/common/restricted_token.h
+++ b/src/include/common/restricted_token.h
@@ -14,11 +14,11 @@
  * On Windows make sure that we are running with a restricted token,
  * On other platforms do nothing.
  */
-void		get_restricted_token(const char *progname);
+void		get_restricted_token(void);
 
 #ifdef WIN32
 /* Create a restricted token and execute the specified process with it. */
-HANDLE		CreateRestrictedProcess(char *cmd, PROCESS_INFORMATION *processInfo, const char *progname);
+HANDLE		CreateRestrictedProcess(char *cmd, PROCESS_INFORMATION *processInfo);
 #endif
 
 #endif							/* COMMON_RESTRICTED_TOKEN_H */
diff --git a/src/include/fe_utils/logging.h b/src/include/fe_utils/logging.h
new file mode 100644
index 0000000000..9b578d4633
--- /dev/null
+++ b/src/include/fe_utils/logging.h
@@ -0,0 +1,94 @@
+/*-------------------------------------------------------------------------
+ * Logging framework for frontend programs
+ *
+ * Copyright (c) 2018, PostgreSQL Global Development Group
+ *
+ * src/include/fe_utils/logging.h
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef FE_UTILS_LOGGING_H
+#define FE_UTILS_LOGGING_H
+
+/*
+ * Log levels are informational only.  They do not affect program flow.
+ */
+enum pg_log_level
+{
+	/*
+	 * Not initialized yet
+	 */
+	PG_LOG_NOTSET = 0,
+
+	/*
+	 * Low level messages that are normally off by default.
+	 */
+	PG_LOG_DEBUG,
+
+	/*
+	 * Any program messages that go to stderr, shown by default.  (The
+	 * program's normal output should go to stdout and not use the logging
+	 * system.)
+	 */
+	PG_LOG_INFO,
+
+	/*
+	 * Warnings and "almost" errors, depends on the program
+	 */
+	PG_LOG_WARNING,
+
+	/*
+	 * Errors
+	 */
+	PG_LOG_ERROR,
+
+	/*
+	 * Severe errors that cause program termination.  (One-shot programs may
+	 * chose to label even fatal errors as merely "errors".  The distinction
+	 * is up to the program.)
+	 */
+	PG_LOG_FATAL,
+
+	/*
+	 * Turn all logging off.
+	 */
+	PG_LOG_OFF,
+};
+
+extern enum pg_log_level __pg_log_level;
+
+/*
+ * Kind of a hack to be able to produce the psql output exactly as required by
+ * the regression tests.
+ */
+#define PG_LOG_FLAG_TERSE	1
+
+void pg_logging_init(const char *argv0);
+void pg_logging_config(int new_flags);
+void pg_logging_set_level(enum pg_log_level new_level);
+void pg_logging_set_pre_callback(void (*cb)(void));
+void pg_logging_set_locus_callback(void (*cb)(const char **filename, uint64 *lineno));
+
+void pg_log_generic(enum pg_log_level level, const char * pg_restrict fmt, ...) pg_attribute_printf(2, 3);
+
+#define pg_log_fatal(...) do { \
+		if (likely(__pg_log_level <= PG_LOG_FATAL)) pg_log_generic(PG_LOG_FATAL, __VA_ARGS__); \
+	} while(0)
+
+#define pg_log_error(...) do { \
+		if (likely(__pg_log_level <= PG_LOG_ERROR)) pg_log_generic(PG_LOG_ERROR, __VA_ARGS__); \
+	} while(0)
+
+#define pg_log_warning(...) do { \
+		if (likely(__pg_log_level <= PG_LOG_WARNING)) pg_log_generic(PG_LOG_WARNING, __VA_ARGS__); \
+	} while(0)
+
+#define pg_log_info(...) do { \
+		if (likely(__pg_log_level <= PG_LOG_INFO)) pg_log_generic(PG_LOG_INFO, __VA_ARGS__); \
+	} while(0)
+
+#define pg_log_debug(...) do { \
+		if (unlikely(__pg_log_level <= PG_LOG_DEBUG)) pg_log_generic(PG_LOG_DEBUG, __VA_ARGS__); \
+	} while(0)
+
+#endif	/* FE_UTILS_LOGGING_H */
diff --git a/src/include/fe_utils/psqlscan.h b/src/include/fe_utils/psqlscan.h
index d6fef9ff77..395ac78c59 100644
--- a/src/include/fe_utils/psqlscan.h
+++ b/src/include/fe_utils/psqlscan.h
@@ -64,13 +64,6 @@ typedef struct PsqlScanCallbacks
 	/* This pointer can be NULL if no variable substitution is wanted */
 	char	   *(*get_variable) (const char *varname, PsqlScanQuoteType quote,
 								 void *passthrough);
-	/* Print an error message someplace appropriate */
-	/* (very old gcc versions don't support attributes on function pointers) */
-#if defined(__GNUC__) && __GNUC__ < 4
-	void		(*write_error) (const char *fmt,...);
-#else
-	void		(*write_error) (const char *fmt,...) pg_attribute_printf(1, 2);
-#endif
 } PsqlScanCallbacks;
 
 
diff --git a/src/interfaces/ecpg/test/Makefile b/src/interfaces/ecpg/test/Makefile
index be53b7b94d..e6d6f80eef 100644
--- a/src/interfaces/ecpg/test/Makefile
+++ b/src/interfaces/ecpg/test/Makefile
@@ -15,6 +15,8 @@ override CPPFLAGS := \
 	'-DDLSUFFIX="$(DLSUFFIX)"' \
 	$(CPPFLAGS)
 
+LDFLAGS_INTERNAL += -L$(top_builddir)/src/fe_utils -lpgfeutils
+
 # default encoding for regression tests
 ENCODING = SQL_ASCII
 
diff --git a/src/nls-global.mk b/src/nls-global.mk
index 4fc9937991..c502ac3fc9 100644
--- a/src/nls-global.mk
+++ b/src/nls-global.mk
@@ -67,6 +67,14 @@ BACKEND_COMMON_GETTEXT_FLAGS = \
     errhint:1:c-format \
     errcontext:1:c-format
 
+FRONTEND_COMMON_GETTEXT_FILES = $(top_srcdir)/src/fe_utils/logging.c
+
+FRONTEND_COMMON_GETTEXT_TRIGGERS = \
+    pg_log_fatal pg_log_error pg_log_warning pg_log_info
+
+FRONTEND_COMMON_GETTEXT_FLAGS = \
+    pg_log_fatal:1:c-format pg_log_error:1:c-format pg_log_warning:1:c-format pg_log_info:1:c-format
+
 
 all-po: $(MO_FILES)
 
diff --git a/src/test/isolation/Makefile b/src/test/isolation/Makefile
index c3c8280ea2..fbbbca05c5 100644
--- a/src/test/isolation/Makefile
+++ b/src/test/isolation/Makefile
@@ -10,6 +10,7 @@ top_builddir = ../../..
 include $(top_builddir)/src/Makefile.global
 
 override CPPFLAGS := -I$(srcdir) -I$(libpq_srcdir) -I$(srcdir)/../regress $(CPPFLAGS)
+LDFLAGS_INTERNAL += -L$(top_builddir)/src/fe_utils -lpgfeutils
 
 OBJS =  specparse.o isolationtester.o $(WIN32RES)
 
@@ -31,7 +32,7 @@ pg_regress.o: | submake-regress
 pg_isolation_regress$(X): isolation_main.o pg_regress.o $(WIN32RES)
 	$(CC) $(CFLAGS) $^ $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@
 
-isolationtester$(X): $(OBJS) | submake-libpq submake-libpgport
+isolationtester$(X): $(OBJS) | submake-libpq submake-libpgport submake-libpgfeutils
 	$(CC) $(CFLAGS) $^ $(libpq_pgport) $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@
 
 distprep: specparse.c specscanner.c
diff --git a/src/test/regress/GNUmakefile b/src/test/regress/GNUmakefile
index a24cfd4e01..38fd25e569 100644
--- a/src/test/regress/GNUmakefile
+++ b/src/test/regress/GNUmakefile
@@ -23,6 +23,8 @@ ifdef MAX_CONNECTIONS
 MAXCONNOPT += --max-connections=$(MAX_CONNECTIONS)
 endif
 
+LDFLAGS_INTERNAL += -L$(top_builddir)/src/fe_utils -lpgfeutils
+
 # stuff to pass into build of pg_regress
 EXTRADEFS = '-DHOST_TUPLE="$(host_tuple)"' \
 	'-DSHELLPROG="$(SHELL)"' \
@@ -36,7 +38,7 @@ EXTRADEFS = '-DHOST_TUPLE="$(host_tuple)"' \
 
 all: pg_regress$(X)
 
-pg_regress$(X): pg_regress.o pg_regress_main.o $(WIN32RES) | submake-libpgport
+pg_regress$(X): pg_regress.o pg_regress_main.o $(WIN32RES) | submake-libpgport submake-libpgfeutils
 	$(CC) $(CFLAGS) $^ $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@
 
 # dependencies ensure that path changes propagate
diff --git a/src/test/regress/pg_regress.c b/src/test/regress/pg_regress.c
index d4f04a8a2c..add253a1d6 100644
--- a/src/test/regress/pg_regress.c
+++ b/src/test/regress/pg_regress.c
@@ -33,6 +33,7 @@
 
 #include "common/restricted_token.h"
 #include "common/username.h"
+#include "fe_utils/logging.h"
 #include "getopt_long.h"
 #include "libpq/pqcomm.h"		/* needed for UNIXSOCK_PATH() */
 #include "pg_config_paths.h"
@@ -1173,7 +1174,7 @@ spawn_process(const char *cmdline)
 	cmdline2 = psprintf("cmd /c \"%s\"", cmdline);
 
 	if ((restrictedToken =
-		 CreateRestrictedProcess(cmdline2, &pi, progname)) == 0)
+		 CreateRestrictedProcess(cmdline2, &pi)) == 0)
 		exit(2);
 
 	CloseHandle(pi.hThread);
@@ -2075,8 +2076,9 @@ regression_main(int argc, char *argv[], init_function ifunc, test_function tfunc
 
 	progname = get_progname(argv[0]);
 	set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_regress"));
+	pg_logging_init(argv[0]);
 
-	get_restricted_token(progname);
+	get_restricted_token();
 
 	atexit(stop_postmaster);
 

base-commit: 8b89a88618dff78dec25f08ee0ca83824b69b34b
-- 
2.20.1