On Thu, Mar 6, 2025, at 10:33 AM, Andres Freund wrote:
> Huh, the startup process is among the most crucial things to monitor?
>

Good point. Fixed.

After collecting some suggestions, I'm attaching a new patch contains the
following changes:

- patch was rebased
- include Alvaro's patch (v2-0001) [1] as a basis for this patch
- add ioworker as new backend type
- add startup as new backend type per Andres suggestion
- small changes into documentation

> I don't know what I think about the whole patch, but I do want to voice
> *strong* opposition to duplicating a list of all backend types into multiple
> places. It's already painfull enough to add a new backend type, without having
> to pointlessly go around and manually add a new backend type to mulltiple
> arrays that have completely predictable content.
>

I'm including Alvaro's patch as is just to make the CF bot happy and to
illustrate how it would be if we adopt his solution to centralize the list of
backend types. I think Alvaro's proposal overcomes the objection [2], right?


[1] 
https://www.postgresql.org/message-id/202507282113.vdp4axehoppi@alvherre.pgsql
[2] 
https://www.postgresql.org/message-id/y5tgui75jrcj6mm5nmoq4yqwage2432akx4kp2ogtcnim3wskx@2ipmtfi4qvpi


-- 
Euler Taveira
EDB   https://www.enterprisedb.com/
From ec409dada269cf54b9bce16cae473a46b2400598 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=C3=81lvaro=20Herrera?= <alvhe...@kurilemu.de>
Date: Tue, 15 Jul 2025 18:19:27 +0200
Subject: [PATCH v3 1/2] Create a separate file listing backend types

Use our established coding pattern to reduce maintenance pain when
adding other per-process-type characteristics.

Like PG_KEYWORD, PG_CMDTAG, PG_RMGR.
---
 src/backend/postmaster/launch_backend.c | 32 ++------------
 src/backend/utils/init/miscinit.c       | 59 ++-----------------------
 src/include/postmaster/proctypelist.h   | 50 +++++++++++++++++++++
 3 files changed, 58 insertions(+), 83 deletions(-)
 create mode 100644 src/include/postmaster/proctypelist.h

diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index bf6b55ee830..8b2f1a0cf41 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -177,34 +177,10 @@ typedef struct
 } child_process_kind;
 
 static child_process_kind child_process_kinds[] = {
-	[B_INVALID] = {"invalid", NULL, false},
-
-	[B_BACKEND] = {"backend", BackendMain, true},
-	[B_DEAD_END_BACKEND] = {"dead-end backend", BackendMain, true},
-	[B_AUTOVAC_LAUNCHER] = {"autovacuum launcher", AutoVacLauncherMain, true},
-	[B_AUTOVAC_WORKER] = {"autovacuum worker", AutoVacWorkerMain, true},
-	[B_BG_WORKER] = {"bgworker", BackgroundWorkerMain, true},
-
-	/*
-	 * WAL senders start their life as regular backend processes, and change
-	 * their type after authenticating the client for replication.  We list it
-	 * here for PostmasterChildName() but cannot launch them directly.
-	 */
-	[B_WAL_SENDER] = {"wal sender", NULL, true},
-	[B_SLOTSYNC_WORKER] = {"slot sync worker", ReplSlotSyncWorkerMain, true},
-
-	[B_STANDALONE_BACKEND] = {"standalone backend", NULL, false},
-
-	[B_ARCHIVER] = {"archiver", PgArchiverMain, true},
-	[B_BG_WRITER] = {"bgwriter", BackgroundWriterMain, true},
-	[B_CHECKPOINTER] = {"checkpointer", CheckpointerMain, true},
-	[B_IO_WORKER] = {"io_worker", IoWorkerMain, true},
-	[B_STARTUP] = {"startup", StartupProcessMain, true},
-	[B_WAL_RECEIVER] = {"wal_receiver", WalReceiverMain, true},
-	[B_WAL_SUMMARIZER] = {"wal_summarizer", WalSummarizerMain, true},
-	[B_WAL_WRITER] = {"wal_writer", WalWriterMain, true},
-
-	[B_LOGGER] = {"syslogger", SysLoggerMain, false},
+#define PG_PROCTYPE(bktype, description, main_func, shmem_attach) \
+	[bktype] = {description, main_func, shmem_attach},
+#include "postmaster/proctypelist.h"
+#undef PG_PROCTYPE
 };
 
 const char *
diff --git a/src/backend/utils/init/miscinit.c b/src/backend/utils/init/miscinit.c
index 43b4dbccc3d..dec220a61f5 100644
--- a/src/backend/utils/init/miscinit.c
+++ b/src/backend/utils/init/miscinit.c
@@ -266,62 +266,11 @@ GetBackendTypeDesc(BackendType backendType)
 
 	switch (backendType)
 	{
-		case B_INVALID:
-			backendDesc = gettext_noop("not initialized");
-			break;
-		case B_ARCHIVER:
-			backendDesc = gettext_noop("archiver");
-			break;
-		case B_AUTOVAC_LAUNCHER:
-			backendDesc = gettext_noop("autovacuum launcher");
-			break;
-		case B_AUTOVAC_WORKER:
-			backendDesc = gettext_noop("autovacuum worker");
-			break;
-		case B_BACKEND:
-			backendDesc = gettext_noop("client backend");
-			break;
-		case B_DEAD_END_BACKEND:
-			backendDesc = gettext_noop("dead-end client backend");
-			break;
-		case B_BG_WORKER:
-			backendDesc = gettext_noop("background worker");
-			break;
-		case B_BG_WRITER:
-			backendDesc = gettext_noop("background writer");
-			break;
-		case B_CHECKPOINTER:
-			backendDesc = gettext_noop("checkpointer");
-			break;
-		case B_IO_WORKER:
-			backendDesc = gettext_noop("io worker");
-			break;
-		case B_LOGGER:
-			backendDesc = gettext_noop("logger");
-			break;
-		case B_SLOTSYNC_WORKER:
-			backendDesc = gettext_noop("slotsync worker");
-			break;
-		case B_STANDALONE_BACKEND:
-			backendDesc = gettext_noop("standalone backend");
-			break;
-		case B_STARTUP:
-			backendDesc = gettext_noop("startup");
-			break;
-		case B_WAL_RECEIVER:
-			backendDesc = gettext_noop("walreceiver");
-			break;
-		case B_WAL_SENDER:
-			backendDesc = gettext_noop("walsender");
-			break;
-		case B_WAL_SUMMARIZER:
-			backendDesc = gettext_noop("walsummarizer");
-			break;
-		case B_WAL_WRITER:
-			backendDesc = gettext_noop("walwriter");
-			break;
+#define PG_PROCTYPE(bktype, description, main_func, shmem_attach) \
+		case bktype: backendDesc = gettext_noop(description); break;
+#include "postmaster/proctypelist.h"
+#undef PG_PROCTYPE
 	}
-
 	return backendDesc;
 }
 
diff --git a/src/include/postmaster/proctypelist.h b/src/include/postmaster/proctypelist.h
new file mode 100644
index 00000000000..919f00bb3a7
--- /dev/null
+++ b/src/include/postmaster/proctypelist.h
@@ -0,0 +1,50 @@
+/*-------------------------------------------------------------------------
+ *
+ * proctypelist.h
+ *
+ * The list of process types is kept on its own source file for use by
+ * automatic tools.  The exact representation of a process type is
+ * determined by the PG_PROCTYPE macro, which is not defined in this
+ * file; it can be defined by the caller for special purposes.
+ *
+ * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * IDENTIFICATION
+ *	  src/include/postmaster/proctypelist.h
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/* there is deliberately not an #ifndef PROCTYPELIST_H here */
+
+/*
+ * WAL senders start their life as regular backend processes, and change their
+ * type after authenticating the client for replication.  We list it here for
+ * PostmasterChildName() but cannot launch them directly.
+ */
+
+/*
+ * List of process types (symbol, description, Main function, shmem_attach)
+ * entries.
+ */
+
+/* bktype, description, main_func, shmem_attach */
+PG_PROCTYPE(B_ARCHIVER, "archiver", PgArchiverMain, true)
+PG_PROCTYPE(B_AUTOVAC_LAUNCHER, "autovacuum launcher", AutoVacLauncherMain, true)
+PG_PROCTYPE(B_AUTOVAC_WORKER, "autovacuum worker", AutoVacWorkerMain, true)
+PG_PROCTYPE(B_BACKEND, "client backend", BackendMain, true)
+PG_PROCTYPE(B_BG_WORKER, "background worker", BackgroundWorkerMain, true)
+PG_PROCTYPE(B_BG_WRITER, "background writer", BackgroundWriterMain, true)
+PG_PROCTYPE(B_CHECKPOINTER, "checkpointer", CheckpointerMain, true)
+PG_PROCTYPE(B_DEAD_END_BACKEND, "dead-end client backend", BackendMain, true)
+PG_PROCTYPE(B_INVALID, "unrecognized", NULL, false)
+PG_PROCTYPE(B_IO_WORKER, "io worker", IoWorkerMain, true)
+PG_PROCTYPE(B_LOGGER, "syslogger", SysLoggerMain, false)
+PG_PROCTYPE(B_SLOTSYNC_WORKER, "slotsync worker", ReplSlotSyncWorkerMain, true)
+PG_PROCTYPE(B_STANDALONE_BACKEND, "standalone backend", NULL, false)
+PG_PROCTYPE(B_STARTUP, "startup", StartupProcessMain, true)
+PG_PROCTYPE(B_WAL_RECEIVER, "walreceiver", WalReceiverMain, true)
+PG_PROCTYPE(B_WAL_SENDER, "walsender", NULL, true)
+PG_PROCTYPE(B_WAL_SUMMARIZER, "walsummarizer", WalSummarizerMain, true)
+PG_PROCTYPE(B_WAL_WRITER, "walwriter", WalWriterMain, true)
-- 
2.39.5

From a36fb59413fc6cca46a87accebebd08e515429a8 Mon Sep 17 00:00:00 2001
From: Euler Taveira <eu...@eulerto.com>
Date: Mon, 11 Dec 2023 17:24:50 -0300
Subject: [PATCH v3 2/2] log_min_messages per backend type

Change log_min_messages from a single element to a comma-separated list
of elements. Each element is backendtype:loglevel. The backendtype are
archiver, autovacuum (includes launcher and workers), backend, bgworker,
bgwriter, checkpointer, ioworker, logger, slotsyncworker, walreceiver,
walsender, walsummarizer and walwriter. A single log level should be
part of this list that is applied as a final step to the backend types
that are not informed.

The old syntax (a single log level) is still accepted for backward
compatibility. In this case, it means the informed log level is applied
for the backend types that are not informed. The default log level is
the same (WARNING) for all backend types.
---
 doc/src/sgml/config.sgml                      |  32 ++-
 src/backend/commands/extension.c              |   2 +-
 src/backend/commands/variable.c               | 196 ++++++++++++++++++
 src/backend/postmaster/launch_backend.c       |   2 +-
 src/backend/utils/error/elog.c                |   2 +-
 src/backend/utils/init/miscinit.c             |   2 +-
 src/backend/utils/misc/guc_tables.c           |  48 +++--
 src/backend/utils/misc/postgresql.conf.sample |   1 +
 src/include/postmaster/proctypelist.h         |  38 ++--
 src/include/utils/guc.h                       |   2 +-
 src/include/utils/guc_hooks.h                 |   2 +
 src/include/utils/guc_tables.h                |   4 +
 src/test/regress/expected/guc.out             |  51 +++++
 src/test/regress/sql/guc.sql                  |  17 ++
 14 files changed, 353 insertions(+), 46 deletions(-)

diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
index 20ccb2d6b54..7c4002f2266 100644
--- a/doc/src/sgml/config.sgml
+++ b/doc/src/sgml/config.sgml
@@ -7021,7 +7021,7 @@ local0.*    /var/log/postgresql
      <variablelist>
 
      <varlistentry id="guc-log-min-messages" xreflabel="log_min_messages">
-      <term><varname>log_min_messages</varname> (<type>enum</type>)
+      <term><varname>log_min_messages</varname> (<type>string</type>)
       <indexterm>
        <primary><varname>log_min_messages</varname> configuration parameter</primary>
       </indexterm>
@@ -7030,14 +7030,28 @@ local0.*    /var/log/postgresql
        <para>
         Controls which <link linkend="runtime-config-severity-levels">message
         levels</link> are written to the server log.
-        Valid values are <literal>DEBUG5</literal>, <literal>DEBUG4</literal>,
-        <literal>DEBUG3</literal>, <literal>DEBUG2</literal>, <literal>DEBUG1</literal>,
-        <literal>INFO</literal>, <literal>NOTICE</literal>, <literal>WARNING</literal>,
-        <literal>ERROR</literal>, <literal>LOG</literal>, <literal>FATAL</literal>, and
-        <literal>PANIC</literal>.  Each level includes all the levels that
-        follow it.  The later the level, the fewer messages are sent
-        to the log.  The default is <literal>WARNING</literal>.  Note that
-        <literal>LOG</literal> has a different rank here than in
+        Valid values are a comma-separated list of <literal>backendtype:level</literal>
+        and a single <literal>level</literal>. The list allows it to use
+        different levels per backend type.
+        Valid <literal>backendtype</literal> values are <literal>archiver</literal>,
+        <literal>autovacuum</literal>, <literal>backend</literal>,
+        <literal>bgworker</literal>, <literal>bgwriter</literal>,
+        <literal>checkpointer</literal>, <literal>ioworker</literal>,
+        <literal>logger</literal>, <literal>slotsyncworker</literal>,
+        <literal>startup</literal>, <literal>walreceiver</literal>,
+        <literal>walsender</literal>, <literal>walsummarizer</literal>, and
+        <literal>walwriter</literal>.
+        Valid <literal>LEVEL</literal> values are <literal>DEBUG5</literal>,
+        <literal>DEBUG4</literal>, <literal>DEBUG3</literal>, <literal>DEBUG2</literal>,
+        <literal>DEBUG1</literal>, <literal>INFO</literal>, <literal>NOTICE</literal>,
+        <literal>WARNING</literal>, <literal>ERROR</literal>, <literal>LOG</literal>,
+        <literal>FATAL</literal>, and <literal>PANIC</literal>.  Each level includes
+        all the levels that follow it.  The later the level, the fewer messages are sent
+        to the log. A single <literal>LEVEL</literal> is mandatory (order does
+        not matter) and it is assigned to the backend types that are not
+        specified in the list.  The default is <literal>WARNING</literal> for
+        all backend types.
+        Note that <literal>LOG</literal> has a different rank here than in
         <xref linkend="guc-client-min-messages"/>.
         Only superusers and users with the appropriate <literal>SET</literal>
         privilege can change this setting.
diff --git a/src/backend/commands/extension.c b/src/backend/commands/extension.c
index e6f9ab6dfd6..b6055431d8f 100644
--- a/src/backend/commands/extension.c
+++ b/src/backend/commands/extension.c
@@ -1143,7 +1143,7 @@ execute_extension_script(Oid extensionOid, ExtensionControlFile *control,
 		(void) set_config_option("client_min_messages", "warning",
 								 PGC_USERSET, PGC_S_SESSION,
 								 GUC_ACTION_SAVE, true, 0, false);
-	if (log_min_messages < WARNING)
+	if (log_min_messages[MyBackendType] < WARNING)
 		(void) set_config_option_ext("log_min_messages", "warning",
 									 PGC_SUSET, PGC_S_SESSION,
 									 BOOTSTRAP_SUPERUSERID,
diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c
index 608f10d9412..5c769dd7bcc 100644
--- a/src/backend/commands/variable.c
+++ b/src/backend/commands/variable.c
@@ -35,6 +35,7 @@
 #include "utils/datetime.h"
 #include "utils/fmgrprotos.h"
 #include "utils/guc_hooks.h"
+#include "utils/guc_tables.h"
 #include "utils/snapmgr.h"
 #include "utils/syscache.h"
 #include "utils/timestamp.h"
@@ -1257,3 +1258,198 @@ check_ssl(bool *newval, void **extra, GucSource source)
 #endif
 	return true;
 }
+
+/*
+ * GUC check_hook for log_min_messages
+ *
+ * The parsing consists of a comma-separated list of BACKENDTYPENAME:LEVEL
+ * elements. BACKENDTYPENAME is log_min_messages_backend_types.  LEVEL is
+ * server_message_level_options. A single LEVEL element should be part of this
+ * list and it is applied as a final step to the backend types that are not
+ * specified. For backward compatibility, the old syntax is still accepted and
+ * it means to apply this level for all backend types.
+ */
+bool
+check_log_min_messages(char **newval, void **extra, GucSource source)
+{
+	char	   *rawstring;
+	List	   *elemlist;
+	ListCell   *l;
+	int			newlevels[BACKEND_NUM_TYPES];
+	bool		assigned[BACKEND_NUM_TYPES];
+	int			genericlevel = -1;	/* -1 means not assigned */
+
+	/* Initialize the array. */
+	memset(newlevels, WARNING, BACKEND_NUM_TYPES * sizeof(int));
+	memset(assigned, false, BACKEND_NUM_TYPES * sizeof(bool));
+
+	/* Need a modifiable copy of string. */
+	rawstring = pstrdup(*newval);
+
+	/* Parse string into list of identifiers. */
+	if (!SplitGUCList(rawstring, ',', &elemlist))
+	{
+		/* syntax error in list */
+		GUC_check_errdetail("List syntax is invalid.");
+		pfree(rawstring);
+		list_free(elemlist);
+		return false;
+	}
+
+	/* Validate and assign log level and backend type. */
+	foreach(l, elemlist)
+	{
+		char	   *tok = (char *) lfirst(l);
+		char	   *sep;
+		const struct config_enum_entry *entry;
+
+		/*
+		 * Check whether there is a backend type following the log level. If
+		 * there is no separator, it means this log level should be applied
+		 * for all backend types (backward compatibility).
+		 */
+		sep = strchr(tok, ':');
+		if (sep == NULL)
+		{
+			bool		found = false;
+
+			/* Reject duplicates for generic log level. */
+			if (genericlevel != -1)
+			{
+				GUC_check_errdetail("Generic log level was already assigned.");
+				pfree(rawstring);
+				list_free(elemlist);
+				return false;
+			}
+
+			/* Is the log level valid? */
+			for (entry = server_message_level_options; entry && entry->name; entry++)
+			{
+				if (pg_strcasecmp(entry->name, tok) == 0)
+				{
+					genericlevel = entry->val;
+					found = true;
+					break;
+				}
+			}
+
+			if (!found)
+			{
+				GUC_check_errdetail("Unrecognized log level: \"%s\".", tok);
+				pfree(rawstring);
+				list_free(elemlist);
+				return false;
+			}
+		}
+		else
+		{
+			char	   *loglevel;
+			char	   *btype;
+			bool		found = false;
+
+			btype = palloc((sep - tok) + 1);
+			memcpy(btype, tok, sep - tok);
+			btype[sep - tok] = '\0';
+			loglevel = pstrdup(sep + 1);
+
+			/* Is the log level valid? */
+			for (entry = server_message_level_options; entry && entry->name; entry++)
+			{
+				if (pg_strcasecmp(entry->name, loglevel) == 0)
+				{
+					found = true;
+					break;
+				}
+			}
+
+			if (!found)
+			{
+				GUC_check_errdetail("Unrecognized log level: \"%s\".", loglevel);
+				pfree(rawstring);
+				list_free(elemlist);
+				return false;
+			}
+
+			/*
+			 * Is the backend type name valid? There might be multiple entries
+			 * per backend type, don't bail out when find first occurrence.
+			 */
+			found = false;
+			for (int i = 0; i < BACKEND_NUM_TYPES; i++)
+			{
+				if (pg_strcasecmp(log_min_messages_backend_types[i], btype) == 0)
+				{
+					/* Reject duplicates for a backend type. */
+					if (assigned[i])
+					{
+						GUC_check_errdetail("Backend type \"%s\" was already assigned.", btype);
+						pfree(rawstring);
+						list_free(elemlist);
+						return false;
+					}
+
+					newlevels[i] = entry->val;
+					assigned[i] = true;
+					found = true;
+				}
+			}
+
+			if (!found)
+			{
+				GUC_check_errdetail("Unrecognized backend type: \"%s\".", btype);
+				pfree(rawstring);
+				list_free(elemlist);
+				return false;
+			}
+		}
+	}
+
+	/*
+	 * Generic log level must be specified. It is a good idea to specify a
+	 * generic log level to make it clear that it is the fallback value.
+	 * Although, we can document it, it might confuse users that used to
+	 * specify a single log level in prior releases.
+	 */
+	if (genericlevel == -1)
+	{
+		GUC_check_errdetail("Generic log level was not defined.");
+		pfree(rawstring);
+		list_free(elemlist);
+		return false;
+	}
+
+	/*
+	 * Apply the generic log level (the one without a backend type) after all
+	 * of the specific backend type have been assigned. Hence, it doesn't
+	 * matter the order you specify the generic log level, the final result
+	 * will be the same.
+	 */
+	for (int i = 0; i < BACKEND_NUM_TYPES; i++)
+	{
+		if (!assigned[i])
+			newlevels[i] = genericlevel;
+	}
+
+	pfree(rawstring);
+	list_free(elemlist);
+
+	/*
+	 * Pass back data for assign_log_min_messages to use.
+	 */
+	*extra = guc_malloc(LOG, BACKEND_NUM_TYPES * sizeof(int));
+	if (!*extra)
+		return false;
+	memcpy(*extra, newlevels, BACKEND_NUM_TYPES * sizeof(int));
+
+	return true;
+}
+
+/*
+ * GUC assign_hook for log_min_messages
+ */
+void
+assign_log_min_messages(const char *newval, void *extra)
+{
+	for (int i = 0; i < BACKEND_NUM_TYPES; i++)
+		log_min_messages[i] = ((int *) extra)[i];
+}
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 8b2f1a0cf41..08395dafe04 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -177,7 +177,7 @@ typedef struct
 } child_process_kind;
 
 static child_process_kind child_process_kinds[] = {
-#define PG_PROCTYPE(bktype, description, main_func, shmem_attach) \
+#define PG_PROCTYPE(bktype, bkcategory, description, main_func, shmem_attach, log_min_messages) \
 	[bktype] = {description, main_func, shmem_attach},
 #include "postmaster/proctypelist.h"
 #undef PG_PROCTYPE
diff --git a/src/backend/utils/error/elog.c b/src/backend/utils/error/elog.c
index 47af743990f..77cafe6e7b5 100644
--- a/src/backend/utils/error/elog.c
+++ b/src/backend/utils/error/elog.c
@@ -235,7 +235,7 @@ is_log_level_output(int elevel, int log_min_level)
 static inline bool
 should_output_to_server(int elevel)
 {
-	return is_log_level_output(elevel, log_min_messages);
+	return is_log_level_output(elevel, log_min_messages[MyBackendType]);
 }
 
 /*
diff --git a/src/backend/utils/init/miscinit.c b/src/backend/utils/init/miscinit.c
index dec220a61f5..8a919148fd7 100644
--- a/src/backend/utils/init/miscinit.c
+++ b/src/backend/utils/init/miscinit.c
@@ -266,7 +266,7 @@ GetBackendTypeDesc(BackendType backendType)
 
 	switch (backendType)
 	{
-#define PG_PROCTYPE(bktype, description, main_func, shmem_attach) \
+#define PG_PROCTYPE(bktype, bkcategory, description, main_func, shmem_attach, log_min_messages) \
 		case bktype: backendDesc = gettext_noop(description); break;
 #include "postmaster/proctypelist.h"
 #undef PG_PROCTYPE
diff --git a/src/backend/utils/misc/guc_tables.c b/src/backend/utils/misc/guc_tables.c
index d14b1678e7f..300e172aa82 100644
--- a/src/backend/utils/misc/guc_tables.c
+++ b/src/backend/utils/misc/guc_tables.c
@@ -146,7 +146,7 @@ static const struct config_enum_entry client_message_level_options[] = {
 	{NULL, 0, false}
 };
 
-static const struct config_enum_entry server_message_level_options[] = {
+const struct config_enum_entry server_message_level_options[] = {
 	{"debug5", DEBUG5, false},
 	{"debug4", DEBUG4, false},
 	{"debug3", DEBUG3, false},
@@ -536,7 +536,6 @@ static bool default_with_oids = false;
 bool		current_role_is_superuser;
 
 int			log_min_error_statement = ERROR;
-int			log_min_messages = WARNING;
 int			client_min_messages = NOTICE;
 int			log_min_duration_sample = -1;
 int			log_min_duration_statement = -1;
@@ -594,6 +593,7 @@ static char *server_version_string;
 static int	server_version_num;
 static char *debug_io_direct_string;
 static char *restrict_nonsystem_relation_kind_string;
+static char *log_min_messages_string;
 
 #ifdef HAVE_SYSLOG
 #define	DEFAULT_SYSLOG_FACILITY LOG_LOCAL0
@@ -638,6 +638,27 @@ char	   *role_string;
 /* should be static, but guc.c needs to get at this */
 bool		in_hot_standby_guc;
 
+/*
+ * It should be static, but commands/variable.c needs to get at this.
+ */
+int			log_min_messages[] = {
+#define PG_PROCTYPE(bktype, bkcategory, description, main_func, shmem_attach, log_min_messages) \
+	[bktype] = log_min_messages,
+#include "postmaster/proctypelist.h"
+#undef PG_PROCTYPE
+};
+
+/*
+ * It might be in commands/variable.c but for convenience it is near
+ * log_min_messages.
+ */
+const char *const log_min_messages_backend_types[] = {
+#define PG_PROCTYPE(bktype, bkcategory, description, main_func, shmem_attach, log_min_messages) \
+	[bktype] = bkcategory,
+#include "postmaster/proctypelist.h"
+#undef PG_PROCTYPE
+};
+
 
 /*
  * Displayable names for context types (enum GucContext)
@@ -4298,6 +4319,18 @@ struct config_string ConfigureNamesString[] =
 		check_client_encoding, assign_client_encoding, NULL
 	},
 
+	{
+		{"log_min_messages", PGC_SUSET, LOGGING_WHEN,
+			gettext_noop("Sets the message levels that are logged."),
+			gettext_noop("Each level includes all the levels that follow it. The later"
+						 " the level, the fewer messages are sent."),
+			GUC_LIST_INPUT
+		},
+		&log_min_messages_string,
+		"WARNING",
+		check_log_min_messages, assign_log_min_messages, NULL
+	},
+
 	{
 		{"log_line_prefix", PGC_SIGHUP, LOGGING_WHAT,
 			gettext_noop("Controls information prefixed to each log line."),
@@ -5110,17 +5143,6 @@ struct config_enum ConfigureNamesEnum[] =
 		NULL, NULL, NULL
 	},
 
-	{
-		{"log_min_messages", PGC_SUSET, LOGGING_WHEN,
-			gettext_noop("Sets the message levels that are logged."),
-			gettext_noop("Each level includes all the levels that follow it. The later"
-						 " the level, the fewer messages are sent.")
-		},
-		&log_min_messages,
-		WARNING, server_message_level_options,
-		NULL, NULL, NULL
-	},
-
 	{
 		{"log_min_error_statement", PGC_SUSET, LOGGING_WHEN,
 			gettext_noop("Causes all statements generating error at or above this level to be logged."),
diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample
index a9d8293474a..c266effc597 100644
--- a/src/backend/utils/misc/postgresql.conf.sample
+++ b/src/backend/utils/misc/postgresql.conf.sample
@@ -539,6 +539,7 @@
 					#   log
 					#   fatal
 					#   panic
+					#   or a comma-separated list of backend_type:level
 
 #log_min_error_statement = error	# values in order of decreasing detail:
 					#   debug5
diff --git a/src/include/postmaster/proctypelist.h b/src/include/postmaster/proctypelist.h
index 919f00bb3a7..356cd45815a 100644
--- a/src/include/postmaster/proctypelist.h
+++ b/src/include/postmaster/proctypelist.h
@@ -29,22 +29,22 @@
  * entries.
  */
 
-/* bktype, description, main_func, shmem_attach */
-PG_PROCTYPE(B_ARCHIVER, "archiver", PgArchiverMain, true)
-PG_PROCTYPE(B_AUTOVAC_LAUNCHER, "autovacuum launcher", AutoVacLauncherMain, true)
-PG_PROCTYPE(B_AUTOVAC_WORKER, "autovacuum worker", AutoVacWorkerMain, true)
-PG_PROCTYPE(B_BACKEND, "client backend", BackendMain, true)
-PG_PROCTYPE(B_BG_WORKER, "background worker", BackgroundWorkerMain, true)
-PG_PROCTYPE(B_BG_WRITER, "background writer", BackgroundWriterMain, true)
-PG_PROCTYPE(B_CHECKPOINTER, "checkpointer", CheckpointerMain, true)
-PG_PROCTYPE(B_DEAD_END_BACKEND, "dead-end client backend", BackendMain, true)
-PG_PROCTYPE(B_INVALID, "unrecognized", NULL, false)
-PG_PROCTYPE(B_IO_WORKER, "io worker", IoWorkerMain, true)
-PG_PROCTYPE(B_LOGGER, "syslogger", SysLoggerMain, false)
-PG_PROCTYPE(B_SLOTSYNC_WORKER, "slotsync worker", ReplSlotSyncWorkerMain, true)
-PG_PROCTYPE(B_STANDALONE_BACKEND, "standalone backend", NULL, false)
-PG_PROCTYPE(B_STARTUP, "startup", StartupProcessMain, true)
-PG_PROCTYPE(B_WAL_RECEIVER, "walreceiver", WalReceiverMain, true)
-PG_PROCTYPE(B_WAL_SENDER, "walsender", NULL, true)
-PG_PROCTYPE(B_WAL_SUMMARIZER, "walsummarizer", WalSummarizerMain, true)
-PG_PROCTYPE(B_WAL_WRITER, "walwriter", WalWriterMain, true)
+/* bktype, bkcategory, description, main_func, shmem_attach, log_min_messages */
+PG_PROCTYPE(B_ARCHIVER, "archiver", "archiver", PgArchiverMain, true, WARNING)
+PG_PROCTYPE(B_AUTOVAC_LAUNCHER, "autovacuum", "autovacuum launcher", AutoVacLauncherMain, true, WARNING)
+PG_PROCTYPE(B_AUTOVAC_WORKER, "autovacuum", "autovacuum worker", AutoVacWorkerMain, true, WARNING)
+PG_PROCTYPE(B_BACKEND, "backend", "client backend", BackendMain, true, WARNING)
+PG_PROCTYPE(B_BG_WORKER, "bgworker", "background worker", BackgroundWorkerMain, true, WARNING)
+PG_PROCTYPE(B_BG_WRITER, "bgwriter", "background writer", BackgroundWriterMain, true, WARNING)
+PG_PROCTYPE(B_CHECKPOINTER, "checkpointer", "checkpointer", CheckpointerMain, true, WARNING)
+PG_PROCTYPE(B_DEAD_END_BACKEND, "backend", "dead-end client backend", BackendMain, true, WARNING)
+PG_PROCTYPE(B_INVALID, "backend", "invalid", NULL, false, WARNING)
+PG_PROCTYPE(B_IO_WORKER, "ioworker", "io worker", IoWorkerMain, true, WARNING)
+PG_PROCTYPE(B_LOGGER, "logger", "syslogger", SysLoggerMain, false, WARNING)
+PG_PROCTYPE(B_SLOTSYNC_WORKER, "slotsyncworker", "slotsync worker", ReplSlotSyncWorkerMain, true, WARNING)
+PG_PROCTYPE(B_STANDALONE_BACKEND, "backend", "standalone backend", NULL, false, WARNING)
+PG_PROCTYPE(B_STARTUP, "startup", "startup", StartupProcessMain, true, WARNING)
+PG_PROCTYPE(B_WAL_RECEIVER, "walreceiver", "walreceiver", WalReceiverMain, true, WARNING)
+PG_PROCTYPE(B_WAL_SENDER, "walsender", "walsender", NULL, true, WARNING)
+PG_PROCTYPE(B_WAL_SUMMARIZER, "walsummarizer", "walsummarizer", WalSummarizerMain, true, WARNING)
+PG_PROCTYPE(B_WAL_WRITER, "walwriter", "walwriter", WalWriterMain, true, WARNING)
diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h
index f619100467d..e10e24940a7 100644
--- a/src/include/utils/guc.h
+++ b/src/include/utils/guc.h
@@ -271,7 +271,7 @@ extern PGDLLIMPORT bool log_duration;
 extern PGDLLIMPORT int log_parameter_max_length;
 extern PGDLLIMPORT int log_parameter_max_length_on_error;
 extern PGDLLIMPORT int log_min_error_statement;
-extern PGDLLIMPORT int log_min_messages;
+extern PGDLLIMPORT int log_min_messages[];
 extern PGDLLIMPORT int client_min_messages;
 extern PGDLLIMPORT int log_min_duration_sample;
 extern PGDLLIMPORT int log_min_duration_statement;
diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h
index 82ac8646a8d..e6ffc96468f 100644
--- a/src/include/utils/guc_hooks.h
+++ b/src/include/utils/guc_hooks.h
@@ -174,5 +174,7 @@ extern void assign_wal_sync_method(int new_wal_sync_method, void *extra);
 extern bool check_synchronized_standby_slots(char **newval, void **extra,
 											 GucSource source);
 extern void assign_synchronized_standby_slots(const char *newval, void *extra);
+extern bool check_log_min_messages(char **newval, void **extra, GucSource source);
+extern void assign_log_min_messages(const char *newval, void *extra);
 
 #endif							/* GUC_HOOKS_H */
diff --git a/src/include/utils/guc_tables.h b/src/include/utils/guc_tables.h
index f72ce944d7f..2aefc653f20 100644
--- a/src/include/utils/guc_tables.h
+++ b/src/include/utils/guc_tables.h
@@ -298,6 +298,10 @@ struct config_enum
 	void	   *reset_extra;
 };
 
+/* log_min_messages */
+extern PGDLLIMPORT const char *const log_min_messages_backend_types[];
+extern PGDLLIMPORT const struct config_enum_entry server_message_level_options[];
+
 /* constant tables corresponding to enums above and in guc.h */
 extern PGDLLIMPORT const char *const config_group_names[];
 extern PGDLLIMPORT const char *const config_type_names[];
diff --git a/src/test/regress/expected/guc.out b/src/test/regress/expected/guc.out
index 7f9e29c765c..741ad6bf062 100644
--- a/src/test/regress/expected/guc.out
+++ b/src/test/regress/expected/guc.out
@@ -913,3 +913,54 @@ SELECT name FROM tab_settings_flags
 (0 rows)
 
 DROP TABLE tab_settings_flags;
+-- Test log_min_messages
+SET log_min_messages TO fatal;
+SHOW log_min_messages;
+ log_min_messages 
+------------------
+ fatal
+(1 row)
+
+SET log_min_messages TO 'fatal';
+SHOW log_min_messages;
+ log_min_messages 
+------------------
+ fatal
+(1 row)
+
+SET log_min_messages TO 'checkpointer:debug2, autovacuum:debug1';  --fail
+ERROR:  invalid value for parameter "log_min_messages": "checkpointer:debug2, autovacuum:debug1"
+DETAIL:  Generic log level was not defined.
+SET log_min_messages TO 'debug1, backend:error, fatal';  -- fail
+ERROR:  invalid value for parameter "log_min_messages": "debug1, backend:error, fatal"
+DETAIL:  Generic log level was already assigned.
+SET log_min_messages TO 'backend:error, debug1, backend:warning';  -- fail
+ERROR:  invalid value for parameter "log_min_messages": "backend:error, debug1, backend:warning"
+DETAIL:  Backend type "backend" was already assigned.
+SET log_min_messages TO 'backend:error, foo:fatal, archiver:debug1';  -- fail
+ERROR:  invalid value for parameter "log_min_messages": "backend:error, foo:fatal, archiver:debug1"
+DETAIL:  Unrecognized backend type: "foo".
+SET log_min_messages TO 'backend:error, checkpointer:bar, archiver:debug1';  -- fail
+ERROR:  invalid value for parameter "log_min_messages": "backend:error, checkpointer:bar, archiver:debug1"
+DETAIL:  Unrecognized log level: "bar".
+SET log_min_messages TO 'backend:error, checkpointer:debug3, fatal, archiver:debug2, autovacuum:debug1, walsender:debug3';
+SHOW log_min_messages;
+                                        log_min_messages                                         
+-------------------------------------------------------------------------------------------------
+ backend:error, checkpointer:debug3, fatal, archiver:debug2, autovacuum:debug1, walsender:debug3
+(1 row)
+
+SET log_min_messages TO 'warning, autovacuum:debug1';
+SHOW log_min_messages;
+      log_min_messages      
+----------------------------
+ warning, autovacuum:debug1
+(1 row)
+
+SET log_min_messages TO 'autovacuum:debug1, warning';
+SHOW log_min_messages;
+      log_min_messages      
+----------------------------
+ autovacuum:debug1, warning
+(1 row)
+
diff --git a/src/test/regress/sql/guc.sql b/src/test/regress/sql/guc.sql
index f65f84a2632..12fa1812f35 100644
--- a/src/test/regress/sql/guc.sql
+++ b/src/test/regress/sql/guc.sql
@@ -368,3 +368,20 @@ SELECT name FROM tab_settings_flags
   WHERE no_reset AND NOT no_reset_all
   ORDER BY 1;
 DROP TABLE tab_settings_flags;
+
+-- Test log_min_messages
+SET log_min_messages TO fatal;
+SHOW log_min_messages;
+SET log_min_messages TO 'fatal';
+SHOW log_min_messages;
+SET log_min_messages TO 'checkpointer:debug2, autovacuum:debug1';  --fail
+SET log_min_messages TO 'debug1, backend:error, fatal';  -- fail
+SET log_min_messages TO 'backend:error, debug1, backend:warning';  -- fail
+SET log_min_messages TO 'backend:error, foo:fatal, archiver:debug1';  -- fail
+SET log_min_messages TO 'backend:error, checkpointer:bar, archiver:debug1';  -- fail
+SET log_min_messages TO 'backend:error, checkpointer:debug3, fatal, archiver:debug2, autovacuum:debug1, walsender:debug3';
+SHOW log_min_messages;
+SET log_min_messages TO 'warning, autovacuum:debug1';
+SHOW log_min_messages;
+SET log_min_messages TO 'autovacuum:debug1, warning';
+SHOW log_min_messages;
-- 
2.39.5

Reply via email to