Subject: Re: log_min_messages per backend type

From: "Euler Taveira" <[email-masked]>
Date: Wed, 21 Jan 2026 23:12:19 -0300

On Sat, Jan 17, 2026, at 7:02 PM, Alvaro Herrera wrote:
>
> I'm not opposed to this idea, but I think it should be implemented not
> by sorting and then moving the first element to the top of the list, but
> instead by modifying the cmp function so that the desired order is
> achieved directly.  So the cmp() should return -1 if element a has no
> colon, or 1 if element b has no colon, otherwise return per strcmp.
> That way you can remove the foreach() block above, which is icky.
>

Good idea. The v9 contains this implementation. I also use the StringInfo as
you suggested in the other email. The 0003 removed the wrong B_BACKEND
assignment pointed in a previous email. This new patchset contains some changes
suggested by Japin Li [1] (I didn't change the error message because it adds an
extra message to translate). There was a minor issue with a null-terminated
string that I fixed too.

PS> I didn't change the background worker case that I mentioned in [2].

[1] https://postgr.es/m/[email-masked]
[2] https://postgr.es/m/[email-masked]

-- 
Euler Taveira
EDB   https://www.enterprisedb.com/

From ea299f1a8b6a38e40826d7baf0dd7a6733197fb4 Mon Sep 17 00:00:00 2001
From: Euler Taveira <[email-masked]>
Date: Tue, 4 Nov 2025 17:18:20 -0300
Subject: [PATCH v9 1/3] log_min_messages per process type

Change log_min_messages from a single element to a comma-separated list
of elements. Each element is type:level. The types are archiver,
autovacuum (includes launcher and workers), backend, bgworker, bgwriter,
checkpointer, ioworker, postmaster, syslogger, slotsyncworker, startup,
walreceiver, walsender, walsummarizer and walwriter. A single log level
should be part of this list and it is applied as a final step to the
process types that were 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 all process types. The default log level is the same (WARNING) for
all process types.
---
 doc/src/sgml/config.sgml                      |  42 +++-
 src/backend/commands/extension.c              |   2 +-
 src/backend/commands/variable.c               | 206 ++++++++++++++++++
 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_parameters.dat     |  10 +-
 src/backend/utils/misc/guc_tables.c           |  21 +-
 src/backend/utils/misc/postgresql.conf.sample |   2 +
 src/include/postmaster/proctypelist.h         |  42 ++--
 src/include/utils/guc.h                       |   5 +-
 src/include/utils/guc_hooks.h                 |   2 +
 src/test/regress/expected/guc.out             |  54 +++++
 src/test/regress/sql/guc.sql                  |  18 ++
 14 files changed, 369 insertions(+), 41 deletions(-)

diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
index 5560b95ee60..cbc748a3636 100644
--- a/doc/src/sgml/config.sgml
+++ b/doc/src/sgml/config.sgml
@@ -7083,7 +7083,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>
@@ -7092,14 +7092,38 @@ 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>type:level</literal>
+        and a single <literal>level</literal>. The list allows it to use
+        different levels per process type. Only the single <literal>level</literal>
+        is mandatory (order does not matter) and it is assigned to the process
+        types that are not specified in the list.
+        Valid process types are listed in the table below, each corresponding to
+        either postmaster, an auxiliary process type or a backend.
+        <simplelist type="vert" columns="4">
+         <member><literal>archiver</literal></member>
+         <member><literal>autovacuum</literal></member>
+         <member><literal>backend</literal></member>
+         <member><literal>bgworker</literal></member>
+         <member><literal>bgwriter</literal></member>
+         <member><literal>checkpointer</literal></member>
+         <member><literal>ioworker</literal></member>
+         <member><literal>postmaster</literal></member>
+         <member><literal>syslogger</literal></member>
+         <member><literal>slotsyncworker</literal></member>
+         <member><literal>startup</literal></member>
+         <member><literal>walreceiver</literal></member>
+         <member><literal>walsender</literal></member>
+         <member><literal>walsummarizer</literal></member>
+         <member><literal>walwriter</literal></member>
+        </simplelist>
+        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.  The default is <literal>WARNING</literal> for all process 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 596105ee078..688f1874f31 100644
--- a/src/backend/commands/extension.c
+++ b/src/backend/commands/extension.c
@@ -1191,7 +1191,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 4440aff4925..99f40186533 100644
--- a/src/backend/commands/variable.c
+++ b/src/backend/commands/variable.c
@@ -34,6 +34,7 @@
 #include "utils/backend_status.h"
 #include "utils/datetime.h"
 #include "utils/fmgrprotos.h"
+#include "utils/guc.h"
 #include "utils/guc_hooks.h"
 #include "utils/snapmgr.h"
 #include "utils/syscache.h"
@@ -1272,3 +1273,208 @@ check_standard_conforming_strings(bool *newval, void **extra, GucSource source)
 
 	return true;
 }
+
+/*
+ * GUC check_hook for log_min_messages
+ *
+ * The parsing consists of a comma-separated list of TYPE:LEVEL elements. TYPE
+ * is log_min_messages_process_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 process types that are not specified. For backward
+ * compatibility, the old syntax is still accepted and it means to apply the
+ * LEVEL for all process types.
+ */
+bool
+check_log_min_messages(char **newval, void **extra, GucSource source)
+{
+	char	   *rawstring;
+	List	   *elemlist;
+	int			newlevel[BACKEND_NUM_TYPES];
+	bool		assigned[BACKEND_NUM_TYPES];
+	int			genericlevel = -1;	/* -1 means not assigned */
+
+	/* Initialize the array. */
+	for (int i = 0; i < BACKEND_NUM_TYPES; i++)
+	{
+		newlevel[i] = WARNING;
+		assigned[i] = false;
+	}
+
+	/* Need a modifiable copy of string. */
+	rawstring = guc_strdup(LOG, *newval);
+
+	/* Parse string into list of identifiers. */
+	if (!SplitGUCList(rawstring, ',', &elemlist))
+	{
+		/* syntax error in list */
+		GUC_check_errdetail("List syntax is invalid.");
+		list_free(elemlist);
+		guc_free(rawstring);
+		return false;
+	}
+
+	/* Validate and assign log level and process type. */
+	foreach_ptr(char, tok, elemlist)
+	{
+		char	   *sep;
+		const struct config_enum_entry *entry;
+
+		/*
+		 * Check whether there is a process type following the log level. If
+		 * there is no separator, it means this is the generic log level. The
+		 * generic log level will be assigned to the process types that were
+		 * not informed.
+		 */
+		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.");
+				guc_free(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);
+				guc_free(rawstring);
+				list_free(elemlist);
+				return false;
+			}
+		}
+		else
+		{
+			char	   *loglevel;
+			char	   *ptype;
+			bool		found = false;
+
+			ptype = guc_malloc(LOG, (sep - tok) + 1);
+			if (!ptype)
+			{
+				guc_free(rawstring);
+				list_free(elemlist);
+				return false;
+			}
+			memcpy(ptype, tok, sep - tok);
+			ptype[sep - tok] = '\0';
+			loglevel = 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);
+				guc_free(ptype);
+				guc_free(rawstring);
+				list_free(elemlist);
+				return false;
+			}
+
+			/*
+			 * Is the process type name valid? There might be multiple entries
+			 * per process type, don't bail out because it can assign the
+			 * value for multiple entries.
+			 */
+			found = false;
+			for (int i = 0; i < BACKEND_NUM_TYPES; i++)
+			{
+				if (pg_strcasecmp(log_min_messages_process_types[i], ptype) == 0)
+				{
+					/* Reject duplicates for a process type. */
+					if (assigned[i])
+					{
+						GUC_check_errdetail("Process type \"%s\" was already assigned.", ptype);
+						guc_free(ptype);
+						guc_free(rawstring);
+						list_free(elemlist);
+						return false;
+					}
+
+					newlevel[i] = entry->val;
+					assigned[i] = true;
+					found = true;
+				}
+			}
+
+			if (!found)
+			{
+				GUC_check_errdetail("Unrecognized process type: \"%s\".", ptype);
+				guc_free(ptype);
+				guc_free(rawstring);
+				list_free(elemlist);
+				return false;
+			}
+
+			guc_free(ptype);
+		}
+	}
+
+	/*
+	 * The generic log level must be specified. It is the fallback value.
+	 */
+	if (genericlevel == -1)
+	{
+		GUC_check_errdetail("Generic log level was not defined.");
+		guc_free(rawstring);
+		list_free(elemlist);
+		return false;
+	}
+
+	/*
+	 * Apply the generic log level after all of the specific process types
+	 * 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])
+			newlevel[i] = genericlevel;
+	}
+
+	guc_free(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, newlevel, 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 cea229ad6a4..756a0237deb 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -179,7 +179,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 aa530d3685e..59975309a4e 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 563f20374ff..efba20fa8b9 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 = description; break;
 #include "postmaster/proctypelist.h"
 #undef PG_PROCTYPE
diff --git a/src/backend/utils/misc/guc_parameters.dat b/src/backend/utils/misc/guc_parameters.dat
index f0260e6e412..3297c4bc30c 100644
--- a/src/backend/utils/misc/guc_parameters.dat
+++ b/src/backend/utils/misc/guc_parameters.dat
@@ -1686,12 +1686,14 @@
   options => 'server_message_level_options',
 },
 
-{ name => 'log_min_messages', type => 'enum', context => 'PGC_SUSET', group => 'LOGGING_WHEN',
+{ name => 'log_min_messages', type => 'string', context => 'PGC_SUSET', group => 'LOGGING_WHEN',
   short_desc => 'Sets the message levels that are logged.',
   long_desc => 'Each level includes all the levels that follow it. The later the level, the fewer messages are sent.',
-  variable => 'log_min_messages',
-  boot_val => 'WARNING',
-  options => 'server_message_level_options',
+  flags => 'GUC_LIST_INPUT',
+  variable => 'log_min_messages_string',
+  boot_val => '"WARNING"',
+  check_hook => 'check_log_min_messages',
+  assign_hook => 'assign_log_min_messages',
 },
 
 { name => 'log_parameter_max_length', type => 'int', context => 'PGC_SUSET', group => 'LOGGING_WHAT',
diff --git a/src/backend/utils/misc/guc_tables.c b/src/backend/utils/misc/guc_tables.c
index 13c569d8790..0aebb9c8e24 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},
@@ -537,7 +537,6 @@ static bool standard_conforming_strings = true;
 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;
@@ -595,6 +594,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
@@ -647,6 +647,23 @@ char	   *role_string;
 /* should be static, but guc.c needs to get at this */
 bool		in_hot_standby_guc;
 
+/*
+ * log_min_messages
+ */
+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
+};
+
+const char *const log_min_messages_process_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)
diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample
index c4f92fcdac8..ad0804ccb9f 100644
--- a/src/backend/utils/misc/postgresql.conf.sample
+++ b/src/backend/utils/misc/postgresql.conf.sample
@@ -541,6 +541,8 @@
                                         #   log
                                         #   fatal
                                         #   panic
+                                        #   and an optional comma-separated list
+                                        #   of 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 0b99eaabfd0..0ddd805f0e7 100644
--- a/src/include/postmaster/proctypelist.h
+++ b/src/include/postmaster/proctypelist.h
@@ -25,27 +25,27 @@
  */
 
 /*
- * List of process types (symbol, description, Main function, shmem_attach)
- * entries.
+ * List of process types (symbol, category, description, Main function,
+ * shmem_attach, message level) entries.
  */

-/* bktype, description, main_func, shmem_attach */
-PG_PROCTYPE(B_ARCHIVER, gettext_noop("archiver"), PgArchiverMain, true)
-PG_PROCTYPE(B_AUTOVAC_LAUNCHER, gettext_noop("autovacuum launcher"), AutoVacLauncherMain, true)
-PG_PROCTYPE(B_AUTOVAC_WORKER, gettext_noop("autovacuum worker"), AutoVacWorkerMain, true)
-PG_PROCTYPE(B_BACKEND, gettext_noop("client backend"), BackendMain, true)
-PG_PROCTYPE(B_BG_WORKER, gettext_noop("background worker"), BackgroundWorkerMain, true)
-PG_PROCTYPE(B_BG_WRITER, gettext_noop("background writer"), BackgroundWriterMain, true)
-PG_PROCTYPE(B_CHECKPOINTER, gettext_noop("checkpointer"), CheckpointerMain, true)
-PG_PROCTYPE(B_DEAD_END_BACKEND, gettext_noop("dead-end client backend"), BackendMain, true)
-PG_PROCTYPE(B_INVALID, gettext_noop("unrecognized"), NULL, false)
-PG_PROCTYPE(B_IO_WORKER, gettext_noop("io worker"), IoWorkerMain, true)
-PG_PROCTYPE(B_LOGGER, gettext_noop("syslogger"), SysLoggerMain, false)
-PG_PROCTYPE(B_SLOTSYNC_WORKER, gettext_noop("slotsync worker"), ReplSlotSyncWorkerMain, true)
-PG_PROCTYPE(B_STANDALONE_BACKEND, gettext_noop("standalone backend"), NULL, false)
-PG_PROCTYPE(B_STARTUP, gettext_noop("startup"), StartupProcessMain, true)
-PG_PROCTYPE(B_WAL_RECEIVER, gettext_noop("walreceiver"), WalReceiverMain, true)
-PG_PROCTYPE(B_WAL_SENDER, gettext_noop("walsender"), NULL, true)
-PG_PROCTYPE(B_WAL_SUMMARIZER, gettext_noop("walsummarizer"), WalSummarizerMain, true)
-PG_PROCTYPE(B_WAL_WRITER, gettext_noop("walwriter"), WalWriterMain, true)
+/* bktype, bkcategory, description, main_func, shmem_attach, log_min_messages */
+PG_PROCTYPE(B_ARCHIVER, "archiver", gettext_noop("archiver"), PgArchiverMain, true, WARNING)
+PG_PROCTYPE(B_AUTOVAC_LAUNCHER, "autovacuum", gettext_noop("autovacuum launcher"), AutoVacLauncherMain, true, WARNING)
+PG_PROCTYPE(B_AUTOVAC_WORKER, "autovacuum", gettext_noop("autovacuum worker"), AutoVacWorkerMain, true, WARNING)
+PG_PROCTYPE(B_BACKEND, "backend", gettext_noop("client backend"), BackendMain, true, WARNING)
+PG_PROCTYPE(B_BG_WORKER, "bgworker", gettext_noop("background worker"), BackgroundWorkerMain, true, WARNING)
+PG_PROCTYPE(B_BG_WRITER, "bgwriter", gettext_noop("background writer"), BackgroundWriterMain, true, WARNING)
+PG_PROCTYPE(B_CHECKPOINTER, "checkpointer", gettext_noop("checkpointer"), CheckpointerMain, true, WARNING)
+PG_PROCTYPE(B_DEAD_END_BACKEND, "backend", gettext_noop("dead-end client backend"), BackendMain, true, WARNING)
+PG_PROCTYPE(B_INVALID, "postmaster", gettext_noop("unrecognized"), NULL, false, WARNING)
+PG_PROCTYPE(B_IO_WORKER, "ioworker", gettext_noop("io worker"), IoWorkerMain, true, WARNING)
+PG_PROCTYPE(B_LOGGER, "syslogger", gettext_noop("syslogger"), SysLoggerMain, false, WARNING)
+PG_PROCTYPE(B_SLOTSYNC_WORKER, "slotsyncworker", gettext_noop("slotsync worker"), ReplSlotSyncWorkerMain, true, WARNING)
+PG_PROCTYPE(B_STANDALONE_BACKEND, "backend", gettext_noop("standalone backend"), NULL, false, WARNING)
+PG_PROCTYPE(B_STARTUP, "startup", gettext_noop("startup"), StartupProcessMain, true, WARNING)
+PG_PROCTYPE(B_WAL_RECEIVER, "walreceiver", gettext_noop("walreceiver"), WalReceiverMain, true, WARNING)
+PG_PROCTYPE(B_WAL_SENDER, "walsender", gettext_noop("walsender"), NULL, true, WARNING)
+PG_PROCTYPE(B_WAL_SUMMARIZER, "walsummarizer", gettext_noop("walsummarizer"), WalSummarizerMain, true, WARNING)
+PG_PROCTYPE(B_WAL_WRITER, "walwriter", gettext_noop("walwriter"), WalWriterMain, true, WARNING)
diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h
index bf39878c43e..8acbdba7ff5 100644
--- a/src/include/utils/guc.h
+++ b/src/include/utils/guc.h
@@ -295,7 +295,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;
@@ -329,6 +329,8 @@ extern PGDLLIMPORT bool trace_sort;
 extern PGDLLIMPORT bool optimize_bounded_sort;
 #endif
 
+extern PGDLLIMPORT const char *const log_min_messages_process_types[];
+
 /*
  * Declarations for options for enum values
  *
@@ -344,6 +346,7 @@ extern PGDLLIMPORT const struct config_enum_entry archive_mode_options[];
 extern PGDLLIMPORT const struct config_enum_entry dynamic_shared_memory_options[];
 extern PGDLLIMPORT const struct config_enum_entry io_method_options[];
 extern PGDLLIMPORT const struct config_enum_entry recovery_target_action_options[];
+extern PGDLLIMPORT const struct config_enum_entry server_message_level_options[];
 extern PGDLLIMPORT const struct config_enum_entry wal_level_options[];
 extern PGDLLIMPORT const struct config_enum_entry wal_sync_method_options[];
 
diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h
index b6ecb0e769f..9c90670d9b8 100644
--- a/src/include/utils/guc_hooks.h
+++ b/src/include/utils/guc_hooks.h
@@ -177,5 +177,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/test/regress/expected/guc.out b/src/test/regress/expected/guc.out
index d6fb879f500..3b8f44566b2 100644
--- a/src/test/regress/expected/guc.out
+++ b/src/test/regress/expected/guc.out
@@ -935,3 +935,57 @@ SELECT name FROM tab_settings_flags
 (0 rows)
 
 DROP TABLE tab_settings_flags;
+-- Test log_min_messages
+SET log_min_messages TO foo;  -- fail
+ERROR:  invalid value for parameter "log_min_messages": "foo"
+DETAIL:  Unrecognized log level: "foo".
+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:  Process 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 process 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 bafaf067e82..f7dfc909b42 100644
--- a/src/test/regress/sql/guc.sql
+++ b/src/test/regress/sql/guc.sql
@@ -377,3 +377,21 @@ 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 foo;  -- fail
+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

From b1e7dc57578cd07fb96678ace2911676f43b6339 Mon Sep 17 00:00:00 2001
From: Euler Taveira <[email-masked]>
Date: Wed, 14 Jan 2026 17:29:09 -0300
Subject: [PATCH v9 2/3] sort log_min_messages elements per process type

The generic log level is always the first element.
---
 src/backend/commands/variable.c   | 50 +++++++++++++++++++++++++++++++
 src/test/regress/expected/guc.out |  4 +--
 2 files changed, 52 insertions(+), 2 deletions(-)

diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c
index 99f40186533..a450254d1fa 100644
--- a/src/backend/commands/variable.c
+++ b/src/backend/commands/variable.c
@@ -42,6 +42,8 @@
 #include "utils/tzparser.h"
 #include "utils/varlena.h"
 
+static int	log_min_messages_cmp(const ListCell *a, const ListCell *b);
+
 /*
  * DATESTYLE
  */
@@ -1289,6 +1291,9 @@ check_log_min_messages(char **newval, void **extra, GucSource source)
 {
 	char	   *rawstring;
 	List	   *elemlist;
+	StringInfoData buf;
+	char	   *result;
+	bool		first = true;
 	int			newlevel[BACKEND_NUM_TYPES];
 	bool		assigned[BACKEND_NUM_TYPES];
 	int			genericlevel = -1;	/* -1 means not assigned */
@@ -1455,8 +1460,39 @@ check_log_min_messages(char **newval, void **extra, GucSource source)
 			newlevel[i] = genericlevel;
 	}
 
+	/*
+	 * Use a stable representation of log_min_messages. The generic level is
+	 * always the first element and the other elements (type:level) are sorted
+	 * by process type. See log_min_messages_cmp for details.
+	 */
+	list_sort(elemlist, log_min_messages_cmp);
+
+	initStringInfo(&buf);
+	foreach_ptr(char, tok, elemlist)
+	{
+		if (first)
+		{
+			appendStringInfoString(&buf, tok);
+			first = false;
+		}
+		else
+		{
+			appendStringInfo(&buf, ", %s", tok);
+		}
+	}
+
+	result = (char *) guc_malloc(LOG, buf.len + 1);
+	if (!result)
+		return false;
+	memcpy(result, buf.data, buf.len);
+	result[buf.len] = '\0';
+
+	guc_free(*newval);
+	*newval = result;
+
 	guc_free(rawstring);
 	list_free(elemlist);
+	pfree(buf.data);
 
 	/*
 	 * Pass back data for assign_log_min_messages to use.
@@ -1469,6 +1505,20 @@ check_log_min_messages(char **newval, void **extra, GucSource source)
 	return true;
 }
 
+static int
+log_min_messages_cmp(const ListCell *a, const ListCell *b)
+{
+	const char *s = lfirst(a);
+	const char *t = lfirst(b);
+
+	if (strchr(s, ':') == NULL)
+		return -1;
+	else if (strchr(t, ':') == NULL)
+		return 1;
+	else
+		return strcmp(s, t);
+}
+
 /*
  * GUC assign_hook for log_min_messages
  */
diff --git a/src/test/regress/expected/guc.out b/src/test/regress/expected/guc.out
index 3b8f44566b2..9a6fd503009 100644
--- a/src/test/regress/expected/guc.out
+++ b/src/test/regress/expected/guc.out
@@ -972,7 +972,7 @@ SET log_min_messages TO 'backend:error, checkpointer:debug3, fatal, archiver:deb
 SHOW log_min_messages;
                                         log_min_messages                                         
 -------------------------------------------------------------------------------------------------
- backend:error, checkpointer:debug3, fatal, archiver:debug2, autovacuum:debug1, walsender:debug3
+ fatal, archiver:debug2, autovacuum:debug1, backend:error, checkpointer:debug3, walsender:debug3
 (1 row)
 
 SET log_min_messages TO 'warning, autovacuum:debug1';
@@ -986,6 +986,6 @@ SET log_min_messages TO 'autovacuum:debug1, warning';
 SHOW log_min_messages;
       log_min_messages      
 ----------------------------
- autovacuum:debug1, warning
+ warning, autovacuum:debug1
 (1 row)
 
-- 
2.39.5

From 55d685515d9459d07863b8e9845ed9620c6eff21 Mon Sep 17 00:00:00 2001
From: Euler Taveira <[email-masked]>
Date: Wed, 21 Jan 2026 10:42:02 -0300
Subject: [PATCH v9 3/3] Assign backend type earlier
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Instead of assigning the backend type into the Main function of each
postmaster child, do it earlier (after fork()). The backend type is
already known by postmaster_child_launch() before it calls fork(). This
reduces the time frame that MyBackendType is correct. (This is important
for log_min_messages per backend type that relies on a known
MyBackendType to decide if it writes a log message or not.)

Author: Euler Taveira <[email-masked]>
Author: Álvaro Herrera <[email-masked]>
Discussion: https://www.postgresql.org/message-id/flat/[email-masked]
---
 src/backend/postmaster/autovacuum.c        | 2 --
 src/backend/postmaster/bgworker.c          | 1 -
 src/backend/postmaster/bgwriter.c          | 1 -
 src/backend/postmaster/checkpointer.c      | 1 -
 src/backend/postmaster/launch_backend.c    | 3 +++
 src/backend/postmaster/pgarch.c            | 1 -
 src/backend/postmaster/startup.c           | 1 -
 src/backend/postmaster/syslogger.c         | 1 -
 src/backend/postmaster/walsummarizer.c     | 1 -
 src/backend/postmaster/walwriter.c         | 1 -
 src/backend/replication/logical/slotsync.c | 2 --
 src/backend/replication/walreceiver.c      | 1 -
 src/backend/storage/aio/method_worker.c    | 1 -
 src/backend/utils/error/elog.c             | 7 ++++++-
 14 files changed, 9 insertions(+), 15 deletions(-)

diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 22379de1e31..6fde740465f 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -385,7 +385,6 @@ AutoVacLauncherMain(const void *startup_data, size_t startup_data_len)
 		PostmasterContext = NULL;
 	}
 
-	MyBackendType = B_AUTOVAC_LAUNCHER;
 	init_ps_display(NULL);
 
 	ereport(DEBUG1,
@@ -1398,7 +1397,6 @@ AutoVacWorkerMain(const void *startup_data, size_t startup_data_len)
 		PostmasterContext = NULL;
 	}
 
-	MyBackendType = B_AUTOVAC_WORKER;
 	init_ps_display(NULL);
 
 	Assert(GetProcessingMode() == InitProcessing);
diff --git a/src/backend/postmaster/bgworker.c b/src/backend/postmaster/bgworker.c
index 65deabe91a7..5144d70095c 100644
--- a/src/backend/postmaster/bgworker.c
+++ b/src/backend/postmaster/bgworker.c
@@ -753,7 +753,6 @@ BackgroundWorkerMain(const void *startup_data, size_t startup_data_len)
 	}
 
 	MyBgworkerEntry = worker;
-	MyBackendType = B_BG_WORKER;
 	init_ps_display(worker->bgw_name);
 
 	Assert(GetProcessingMode() == InitProcessing);
diff --git a/src/backend/postmaster/bgwriter.c b/src/backend/postmaster/bgwriter.c
index 80e3088fc7e..0956bd39a85 100644
--- a/src/backend/postmaster/bgwriter.c
+++ b/src/backend/postmaster/bgwriter.c
@@ -94,7 +94,6 @@ BackgroundWriterMain(const void *startup_data, size_t startup_data_len)
 
 	Assert(startup_data_len == 0);
 
-	MyBackendType = B_BG_WRITER;
 	AuxiliaryProcessMainCommon();
 
 	/*
diff --git a/src/backend/postmaster/checkpointer.c b/src/backend/postmaster/checkpointer.c
index 6482c21b8f9..e03c19123bc 100644
--- a/src/backend/postmaster/checkpointer.c
+++ b/src/backend/postmaster/checkpointer.c
@@ -199,7 +199,6 @@ CheckpointerMain(const void *startup_data, size_t startup_data_len)
 
 	Assert(startup_data_len == 0);
 
-	MyBackendType = B_CHECKPOINTER;
 	AuxiliaryProcessMainCommon();
 
 	CheckpointerShmem->checkpointer_pid = MyProcPid;
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 756a0237deb..66b548d0e4d 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -224,6 +224,8 @@ postmaster_child_launch(BackendType child_type, int child_slot,
 	pid = fork_process();
 	if (pid == 0)				/* child */
 	{
+		MyBackendType = child_type;
+
 		/* Capture and transfer timings that may be needed for logging */
 		if (IsExternalConnectionBackend(child_type))
 		{
@@ -608,6 +610,7 @@ SubPostmasterMain(int argc, char *argv[])
 	child_type = (BackendType) atoi(child_kind);
 	if (child_type <= B_INVALID || child_type > BACKEND_NUM_TYPES - 1)
 		elog(ERROR, "unknown child kind %s", child_kind);
+	MyBackendType = child_type;
 
 	/* Read in the variables file */
 	read_backend_variables(argv[2], &startup_data, &startup_data_len);
diff --git a/src/backend/postmaster/pgarch.c b/src/backend/postmaster/pgarch.c
index 1a20387c4bd..82731e452fc 100644
--- a/src/backend/postmaster/pgarch.c
+++ b/src/backend/postmaster/pgarch.c
@@ -222,7 +222,6 @@ PgArchiverMain(const void *startup_data, size_t startup_data_len)
 {
 	Assert(startup_data_len == 0);
 
-	MyBackendType = B_ARCHIVER;
 	AuxiliaryProcessMainCommon();
 
 	/*
diff --git a/src/backend/postmaster/startup.c b/src/backend/postmaster/startup.c
index a1a4f65f9a9..cdbe53dd262 100644
--- a/src/backend/postmaster/startup.c
+++ b/src/backend/postmaster/startup.c
@@ -217,7 +217,6 @@ StartupProcessMain(const void *startup_data, size_t startup_data_len)
 {
 	Assert(startup_data_len == 0);
 
-	MyBackendType = B_STARTUP;
 	AuxiliaryProcessMainCommon();
 
 	/* Arrange to clean up at startup process exit */
diff --git a/src/backend/postmaster/syslogger.c b/src/backend/postmaster/syslogger.c
index 1c443b3d126..86c5e376b40 100644
--- a/src/backend/postmaster/syslogger.c
+++ b/src/backend/postmaster/syslogger.c
@@ -206,7 +206,6 @@ SysLoggerMain(const void *startup_data, size_t startup_data_len)
 
 	now = MyStartTime;
 
-	MyBackendType = B_LOGGER;
 	init_ps_display(NULL);
 
 	/*
diff --git a/src/backend/postmaster/walsummarizer.c b/src/backend/postmaster/walsummarizer.c
index c3d56c866d3..2d8f57099fd 100644
--- a/src/backend/postmaster/walsummarizer.c
+++ b/src/backend/postmaster/walsummarizer.c
@@ -234,7 +234,6 @@ WalSummarizerMain(const void *startup_data, size_t startup_data_len)
 
 	Assert(startup_data_len == 0);
 
-	MyBackendType = B_WAL_SUMMARIZER;
 	AuxiliaryProcessMainCommon();
 
 	ereport(DEBUG1,
diff --git a/src/backend/postmaster/walwriter.c b/src/backend/postmaster/walwriter.c
index 38ec8a4c8c7..23e79a32345 100644
--- a/src/backend/postmaster/walwriter.c
+++ b/src/backend/postmaster/walwriter.c
@@ -94,7 +94,6 @@ WalWriterMain(const void *startup_data, size_t startup_data_len)
 
 	Assert(startup_data_len == 0);
 
-	MyBackendType = B_WAL_WRITER;
 	AuxiliaryProcessMainCommon();
 
 	/*
diff --git a/src/backend/replication/logical/slotsync.c b/src/backend/replication/logical/slotsync.c
index 73fc51ea53e..b53f888b804 100644
--- a/src/backend/replication/logical/slotsync.c
+++ b/src/backend/replication/logical/slotsync.c
@@ -1540,8 +1540,6 @@ ReplSlotSyncWorkerMain(const void *startup_data, size_t startup_data_len)
 
 	Assert(startup_data_len == 0);
 
-	MyBackendType = B_SLOTSYNC_WORKER;
-
 	init_ps_display(NULL);
 
 	Assert(GetProcessingMode() == InitProcessing);
diff --git a/src/backend/replication/walreceiver.c b/src/backend/replication/walreceiver.c
index a41453530a1..8dbd8cb2009 100644
--- a/src/backend/replication/walreceiver.c
+++ b/src/backend/replication/walreceiver.c
@@ -169,7 +169,6 @@ WalReceiverMain(const void *startup_data, size_t startup_data_len)
 
 	Assert(startup_data_len == 0);
 
-	MyBackendType = B_WAL_RECEIVER;
 	AuxiliaryProcessMainCommon();
 
 	/*
diff --git a/src/backend/storage/aio/method_worker.c b/src/backend/storage/aio/method_worker.c
index d7c144cd8f7..d9617c20e76 100644
--- a/src/backend/storage/aio/method_worker.c
+++ b/src/backend/storage/aio/method_worker.c
@@ -390,7 +390,6 @@ IoWorkerMain(const void *startup_data, size_t startup_data_len)
 	volatile int error_errno = 0;
 	char		cmd[128];
 
-	MyBackendType = B_IO_WORKER;
 	AuxiliaryProcessMainCommon();
 
 	pqsignal(SIGHUP, SignalHandlerForConfigReload);
diff --git a/src/backend/utils/error/elog.c b/src/backend/utils/error/elog.c
index 59975309a4e..f35ec0429b2 100644
--- a/src/backend/utils/error/elog.c
+++ b/src/backend/utils/error/elog.c
@@ -2779,7 +2779,12 @@ get_backend_type_for_log(void)
 	if (MyProcPid == PostmasterPid)
 		backend_type_str = "postmaster";
 	else if (MyBackendType == B_BG_WORKER)
-		backend_type_str = MyBgworkerEntry->bgw_type;
+	{
+		if (MyBgworkerEntry && MyBgworkerEntry->bgw_type[0] != '\0')
+			backend_type_str = MyBgworkerEntry->bgw_type;
+		else
+			backend_type_str = "early bgworker";
+	}
 	else
 		backend_type_str = GetBackendTypeDesc(MyBackendType);
 
-- 
2.39.5

---

From: Alvaro Herrera <[email-masked]>
Date: Fri, 6 Feb 2026 12:05:27 +0100

Here are some fixups for the main patch.  I include yours so that CI
will test this one.

* I found some errdetail messages unclear, so I reworded them.
Specifically you had
 ERROR:  invalid value for parameter "log_min_messages": "backend:error, debug1, backend:warning"
 DETAIL:  Process type "backend" was already assigned.
which is not completely incorrect but looks weird from the user
perspective.  I changed it to
 DETAIL:  Redundant log level specification for process type "backend".

Also,
 ERROR:  invalid value for parameter "log_min_messages": "debug1, backend:error, fatal"
 DETAIL:  Generic log level was already assigned.
I changed to
 DETAIL:  Redundant specification of default log level.

and added process type in this one:
 ERROR:  invalid value for parameter "log_min_messages": "backend:error, checkpointer:bar, archiver:debug1"
 DETAIL:  Unrecognized log level: "bar".
changed to
 DETAIL:  Unrecognized log level for process type "checkpointer": "bar".
(This one can show an invalid process type if the level is also bogus.
I don't think that's a terrible problem.)

* I'm not fond of the term "generic", so I changed it to "default",
which IMO makes more sense from the user point of view.

* There seemed to be too much guc_mallocking[*] going on; for instance for
ptype.  I simplified that by just overwriting the : to a '\0', then we
can use the original string for pg_strcasecmp().  At the bottom of the
loop we restore the ':', so that the code below can reuse the original
values.  This is okay because we have already mallocked a copy for
SplitGUCList.

* There's no reason to add a WARNING to every process type in the
proctypelist.h table.  We can just set the values to WARNING in the
log_min_messages initializer in guc_tables.c.

* There's no reason AFAICS to have log_min_messages_process_types in
guc_tables.c; nobody else uses it.  I made it a local array of char*
inside the check_log_min_messages function.

* There's no need to initialize the newlevel[] array, since we're going
to assign values to every individual element at one point or another.
And for the assigned[] array, we don't need to set the value of each to
'false' in a loop; we can just initialize to '{0}' and the compiler will
do the needful.  With this we can remove the loop entirely.

* "guc_free()+list_free()+return false" the whole time in the various
failure places across the loop was tiresome.  I put them all in a single
place and jump there with a goto.

* in foreach() loops, tracking of a 'bool first' is unnecessary.  You
can just compare foreach_current_index() with 0.

* Rewrote docs and comments

-- 
Álvaro Herrera         PostgreSQL Developer  —  https://www.EnterpriseDB.com/
>From a05d1e59324b7c88aeb52c009b4e03aaeafd2ffc Mon Sep 17 00:00:00 2001
From: Euler Taveira <[email-masked]>
Date: Tue, 4 Nov 2025 17:18:20 -0300
Subject: [PATCH v10 1/2] log_min_messages per process type

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 all process types. The default log level is the same (WARNING) for
all process types.
---
 doc/src/sgml/config.sgml                      |  42 ++-
 src/backend/commands/extension.c              |   2 +-
 src/backend/commands/variable.c               | 256 ++++++++++++++++++
 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_parameters.dat     |  10 +-
 src/backend/utils/misc/guc_tables.c           |  21 +-
 src/backend/utils/misc/postgresql.conf.sample |   2 +
 src/include/postmaster/proctypelist.h         |  42 +--
 src/include/utils/guc.h                       |   5 +-
 src/include/utils/guc_hooks.h                 |   2 +
 src/test/regress/expected/guc.out             |  54 ++++
 src/test/regress/sql/guc.sql                  |  18 ++
 14 files changed, 419 insertions(+), 41 deletions(-)

index 4440aff4925..a450254d1fa 100644
@@ -41,6 +42,8 @@
 
+static int	log_min_messages_cmp(const ListCell *a, const ListCell *b);
+
 /*
  * DATESTYLE
  */
@@ -1272,3 +1275,256 @@ check_standard_conforming_strings(bool *newval, void **extra, GucSource source)
 
 	return true;
 }
+
+/*
index 926fd6f2700..08553c0f024 100644
@@ -178,7 +178,7 @@ typedef struct
 } child_process_kind;
 
index e6a4ef99059..4e9143b6e6f 100644
 
 /*
 
 	switch (backendType)
 	{

 

 #ifdef HAVE_SYSLOG
 
+/*
+ * log_min_messages
+ */
 
 /*

 /*

 
 
 #endif							/* GUC_HOOKS_H */
index d6fb879f500..9a6fd503009 100644
 
2.47.3

>From 668c6e24e58f1fd9a75bb6040990d26f89a52513 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=C3=81lvaro=20Herrera?= <[email-masked]>
Date: Fri, 6 Feb 2026 10:24:29 +0100
Subject: [PATCH v10 2/2] review

---
 doc/src/sgml/config.sgml                |  18 ++--
 src/backend/commands/variable.c         | 127 +++++++++++-------------
 src/backend/postmaster/launch_backend.c |   2 +-
 src/backend/utils/init/miscinit.c       |   2 +-
 src/backend/utils/misc/guc_tables.c     |  14 +--
 src/include/postmaster/proctypelist.h   |  38 +++----
 src/test/regress/expected/guc.out       |   8 +-
 7 files changed, 93 insertions(+), 116 deletions(-)

diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
index cbc748a3636..984194ca758 100644
--- a/doc/src/sgml/config.sgml
+++ b/doc/src/sgml/config.sgml
@@ -7090,15 +7090,15 @@ local0.*    /var/log/postgresql
       </term>
       <listitem>
        <para>
-        Controls which <link linkend="runtime-config-severity-levels">message
-        levels</link> are written to the server log.
-        Valid values are a comma-separated list of <literal>type:level</literal>
-        and a single <literal>level</literal>. The list allows it to use
-        different levels per process type. Only the single <literal>level</literal>
-        is mandatory (order does not matter) and it is assigned to the process
-        types that are not specified in the list.
-        Valid process types are listed in the table below, each corresponding to
-        either postmaster, an auxiliary process type or a backend.
+        Controls which
+        <link linkend="runtime-config-severity-levels">message levels</link>
+        are written to the server log.  Valid values are a comma-separated
+        list of zero or more
+        <literal><replaceable>process type</replaceable>:<replaceable>level</replaceable></literal>
+        entries and exactly one mandatory
+        <literal><replaceable>level</replaceable></literal> entry,
+        which is the default for process types not listed.
+        Valid process types are listed in the table below.
         <simplelist type="vert" columns="4">
          <member><literal>archiver</literal></member>
          <member><literal>autovacuum</literal></member>
diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c
index a450254d1fa..97b9a6b5964 100644
--- a/src/backend/commands/variable.c
+++ b/src/backend/commands/variable.c
@@ -1279,12 +1279,12 @@ check_standard_conforming_strings(bool *newval, void **extra, GucSource source)
 /*
  * GUC check_hook for log_min_messages
  *
- * The parsing consists of a comma-separated list of TYPE:LEVEL elements. TYPE
- * is log_min_messages_process_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 process types that are not specified. For backward
- * compatibility, the old syntax is still accepted and it means to apply the
- * LEVEL for all process types.
+ * This value is parsed as a comma-separated list of zero or more TYPE:LEVEL
+ * elements.  For each element, TYPE corresponds to a bk_category value (see
+ * postmaster/proctypelist.h), and LEVEL is one of log_min_message_lvls.
+ *
+ * In addition, there must be a single LEVEL element (with no TYPE part)
+ * which sets the default level for process types that aren't specified.
  */
 bool
 check_log_min_messages(char **newval, void **extra, GucSource source)
@@ -1293,22 +1293,21 @@ check_log_min_messages(char **newval, void **extra, GucSource source)
 	List	   *elemlist;
 	StringInfoData buf;
 	char	   *result;
-	bool		first = true;
 	int			newlevel[BACKEND_NUM_TYPES];
-	bool		assigned[BACKEND_NUM_TYPES];
+	bool		assigned[BACKEND_NUM_TYPES] = {0};
 	int			genericlevel = -1;	/* -1 means not assigned */
 
-	/* Initialize the array. */
-	for (int i = 0; i < BACKEND_NUM_TYPES; i++)
-	{
-		newlevel[i] = WARNING;
-		assigned[i] = false;
-	}
+	const char *const process_types[] = {
+#define PG_PROCTYPE(bktype, bkcategory, description, main_func, shmem_attach) \
+		[bktype] = bkcategory,
+#include "postmaster/proctypelist.h"
+#undef PG_PROCTYPE
+	};
 
 	/* Need a modifiable copy of string. */
 	rawstring = guc_strdup(LOG, *newval);
 
-	/* Parse string into list of identifiers. */
+	/* Parse the string into a list. */
 	if (!SplitGUCList(rawstring, ',', &elemlist))
 	{
 		/* syntax error in list */
@@ -1321,27 +1320,22 @@ check_log_min_messages(char **newval, void **extra, GucSource source)
 	/* Validate and assign log level and process type. */
 	foreach_ptr(char, tok, elemlist)
 	{
-		char	   *sep;
-		const struct config_enum_entry *entry;
+		char	   *sep = strchr(tok, ':');
 
 		/*
-		 * Check whether there is a process type following the log level. If
-		 * there is no separator, it means this is the generic log level. The
-		 * generic log level will be assigned to the process types that were
-		 * not informed.
+		 * If there's no ':' separator in the entry, this is the default
+		 * value.  Otherwise it's a process type-specific entry.
 		 */
-		sep = strchr(tok, ':');
 		if (sep == NULL)
 		{
+			const struct config_enum_entry *entry;
 			bool		found = false;
 
 			/* Reject duplicates for generic log level. */
 			if (genericlevel != -1)
 			{
-				GUC_check_errdetail("Generic log level was already assigned.");
-				guc_free(rawstring);
-				list_free(elemlist);
-				return false;
+				GUC_check_errdetail("Redundant specification of default log level.");
+				goto lmm_fail;
 			}
 
 			/* Is the log level valid? */
@@ -1358,9 +1352,7 @@ check_log_min_messages(char **newval, void **extra, GucSource source)
 			if (!found)
 			{
 				GUC_check_errdetail("Unrecognized log level: \"%s\".", tok);
-				guc_free(rawstring);
-				list_free(elemlist);
-				return false;
+				goto lmm_fail;
 			}
 		}
 		else
@@ -1368,23 +1360,19 @@ check_log_min_messages(char **newval, void **extra, GucSource source)
 			char	   *loglevel;
 			char	   *ptype;
 			bool		found = false;
+			int			level;
+			const struct config_enum_entry *entry;
 
-			ptype = guc_malloc(LOG, (sep - tok) + 1);
-			if (!ptype)
-			{
-				guc_free(rawstring);
-				list_free(elemlist);
-				return false;
-			}
-			memcpy(ptype, tok, sep - tok);
-			ptype[sep - tok] = '\0';
+			ptype = tok;
 			loglevel = sep + 1;
+			*sep = '\0';
 
 			/* Is the log level valid? */
 			for (entry = server_message_level_options; entry && entry->name; entry++)
 			{
 				if (pg_strcasecmp(entry->name, loglevel) == 0)
 				{
+					level = entry->val;
 					found = true;
 					break;
 				}
@@ -1392,50 +1380,49 @@ check_log_min_messages(char **newval, void **extra, GucSource source)
 
 			if (!found)
 			{
-				GUC_check_errdetail("Unrecognized log level: \"%s\".", loglevel);
-				guc_free(ptype);
-				guc_free(rawstring);
-				list_free(elemlist);
-				return false;
+				GUC_check_errdetail("Unrecognized log level for process type \"%s\": \"%s\".",
+									ptype, loglevel);
+				goto lmm_fail;
 			}
 
-			/*
-			 * Is the process type name valid? There might be multiple entries
-			 * per process type, don't bail out because it can assign the
-			 * value for multiple entries.
-			 */
+			/* Is the process type name valid and unique? */
 			found = false;
 			for (int i = 0; i < BACKEND_NUM_TYPES; i++)
 			{
-				if (pg_strcasecmp(log_min_messages_process_types[i], ptype) == 0)
+				if (pg_strcasecmp(process_types[i], ptype) == 0)
 				{
 					/* Reject duplicates for a process type. */
 					if (assigned[i])
 					{
-						GUC_check_errdetail("Process type \"%s\" was already assigned.", ptype);
-						guc_free(ptype);
-						guc_free(rawstring);
-						list_free(elemlist);
-						return false;
+						GUC_check_errdetail("Redundant log level specification for process type \"%s\".",
+											ptype);
+						goto lmm_fail;
 					}
 
-					newlevel[i] = entry->val;
+					newlevel[i] = level;
 					assigned[i] = true;
 					found = true;
+					break;
 				}
 			}
 
 			if (!found)
 			{
 				GUC_check_errdetail("Unrecognized process type: \"%s\".", ptype);
-				guc_free(ptype);
-				guc_free(rawstring);
-				list_free(elemlist);
-				return false;
+				goto lmm_fail;
 			}
 
-			guc_free(ptype);
+			/* Put the separator back in place */
+			*sep = ':';
 		}
+
+		/* all good */
+		continue;
+
+lmm_fail:
+		guc_free(rawstring);
+		list_free(elemlist);
+		return false;
 	}
 
 	/*
@@ -1443,7 +1430,7 @@ check_log_min_messages(char **newval, void **extra, GucSource source)
 	 */
 	if (genericlevel == -1)
 	{
-		GUC_check_errdetail("Generic log level was not defined.");
+		GUC_check_errdetail("Default log level was not defined.");
 		guc_free(rawstring);
 		list_free(elemlist);
 		return false;
@@ -1461,24 +1448,18 @@ check_log_min_messages(char **newval, void **extra, GucSource source)
 	}
 
 	/*
-	 * Use a stable representation of log_min_messages. The generic level is
-	 * always the first element and the other elements (type:level) are sorted
-	 * by process type. See log_min_messages_cmp for details.
+	 * To present a nice view to users, sort the output list by process type,
+	 * with the default value first.
 	 */
 	list_sort(elemlist, log_min_messages_cmp);
 
-	initStringInfo(&buf);
+	initStringInfoExt(&buf, strlen(rawstring) + 1);
 	foreach_ptr(char, tok, elemlist)
 	{
-		if (first)
-		{
+		if (foreach_current_index(tok) == 0)
 			appendStringInfoString(&buf, tok);
-			first = false;
-		}
 		else
-		{
 			appendStringInfo(&buf, ", %s", tok);
-		}
 	}
 
 	result = (char *) guc_malloc(LOG, buf.len + 1);
@@ -1505,6 +1486,10 @@ check_log_min_messages(char **newval, void **extra, GucSource source)
 	return true;
 }
 
+/*
+ * list_sort() callback for check_log_min_messages.  The default element
+ * goes first; the rest are ordered by strcmp() of the process type.
+ */
 static int
 log_min_messages_cmp(const ListCell *a, const ListCell *b)
 {
diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c
index 08553c0f024..05b1feef3cf 100644
--- a/src/backend/postmaster/launch_backend.c
+++ b/src/backend/postmaster/launch_backend.c
@@ -178,7 +178,7 @@ typedef struct
 } child_process_kind;
 
 static child_process_kind child_process_kinds[] = {
-#define PG_PROCTYPE(bktype, bkcategory, description, main_func, shmem_attach, log_min_messages) \
+#define PG_PROCTYPE(bktype, bkcategory, description, main_func, shmem_attach) \
 	[bktype] = {description, main_func, shmem_attach},
 #include "postmaster/proctypelist.h"
 #undef PG_PROCTYPE
diff --git a/src/backend/utils/init/miscinit.c b/src/backend/utils/init/miscinit.c
index efba20fa8b9..03f6c8479f2 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, bkcategory, description, main_func, shmem_attach, log_min_messages)	\
+#define PG_PROCTYPE(bktype, bkcategory, description, main_func, shmem_attach)	\
 		case bktype: backendDesc = 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 0aebb9c8e24..53933f53b25 100644
--- a/src/backend/utils/misc/guc_tables.c
+++ b/src/backend/utils/misc/guc_tables.c
@@ -648,23 +648,15 @@ char	   *role_string;
 bool		in_hot_standby_guc;
 
 /*
- * log_min_messages
+ * set default log_min_messages to WARNING for all process types
  */
 int			log_min_messages[] = {
-#define PG_PROCTYPE(bktype, bkcategory, description, main_func, shmem_attach, log_min_messages) \
-	[bktype] = log_min_messages,
+#define PG_PROCTYPE(bktype, bkcategory, description, main_func, shmem_attach) \
+	[bktype] = WARNING,
 #include "postmaster/proctypelist.h"
 #undef PG_PROCTYPE
 };
 
-const char *const log_min_messages_process_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)
  *
diff --git a/src/include/postmaster/proctypelist.h b/src/include/postmaster/proctypelist.h
index 0ddd805f0e7..4e259e84c2d 100644
--- a/src/include/postmaster/proctypelist.h
+++ b/src/include/postmaster/proctypelist.h
@@ -30,22 +30,22 @@
  */

-/* bktype, bkcategory, description, main_func, shmem_attach, log_min_messages */
-PG_PROCTYPE(B_ARCHIVER, "archiver", gettext_noop("archiver"), PgArchiverMain, true, WARNING)
-PG_PROCTYPE(B_AUTOVAC_LAUNCHER, "autovacuum", gettext_noop("autovacuum launcher"), AutoVacLauncherMain, true, WARNING)
-PG_PROCTYPE(B_AUTOVAC_WORKER, "autovacuum", gettext_noop("autovacuum worker"), AutoVacWorkerMain, true, WARNING)
-PG_PROCTYPE(B_BACKEND, "backend", gettext_noop("client backend"), BackendMain, true, WARNING)
-PG_PROCTYPE(B_BG_WORKER, "bgworker", gettext_noop("background worker"), BackgroundWorkerMain, true, WARNING)
-PG_PROCTYPE(B_BG_WRITER, "bgwriter", gettext_noop("background writer"), BackgroundWriterMain, true, WARNING)
-PG_PROCTYPE(B_CHECKPOINTER, "checkpointer", gettext_noop("checkpointer"), CheckpointerMain, true, WARNING)
-PG_PROCTYPE(B_DEAD_END_BACKEND, "backend", gettext_noop("dead-end client backend"), BackendMain, true, WARNING)
-PG_PROCTYPE(B_INVALID, "postmaster", gettext_noop("unrecognized"), NULL, false, WARNING)
-PG_PROCTYPE(B_IO_WORKER, "ioworker", gettext_noop("io worker"), IoWorkerMain, true, WARNING)
-PG_PROCTYPE(B_LOGGER, "syslogger", gettext_noop("syslogger"), SysLoggerMain, false, WARNING)
-PG_PROCTYPE(B_SLOTSYNC_WORKER, "slotsyncworker", gettext_noop("slotsync worker"), ReplSlotSyncWorkerMain, true, WARNING)
-PG_PROCTYPE(B_STANDALONE_BACKEND, "backend", gettext_noop("standalone backend"), NULL, false, WARNING)
-PG_PROCTYPE(B_STARTUP, "startup", gettext_noop("startup"), StartupProcessMain, true, WARNING)
-PG_PROCTYPE(B_WAL_RECEIVER, "walreceiver", gettext_noop("walreceiver"), WalReceiverMain, true, WARNING)
-PG_PROCTYPE(B_WAL_SENDER, "walsender", gettext_noop("walsender"), NULL, true, WARNING)
-PG_PROCTYPE(B_WAL_SUMMARIZER, "walsummarizer", gettext_noop("walsummarizer"), WalSummarizerMain, true, WARNING)
-PG_PROCTYPE(B_WAL_WRITER, "walwriter", gettext_noop("walwriter"), WalWriterMain, true, WARNING)
+/* bktype, bkcategory, description, main_func, shmem_attach */
+PG_PROCTYPE(B_ARCHIVER, "archiver", gettext_noop("archiver"), PgArchiverMain, true)
+PG_PROCTYPE(B_AUTOVAC_LAUNCHER, "autovacuum", gettext_noop("autovacuum launcher"), AutoVacLauncherMain, true)
+PG_PROCTYPE(B_AUTOVAC_WORKER, "autovacuum", gettext_noop("autovacuum worker"), AutoVacWorkerMain, true)
+PG_PROCTYPE(B_BACKEND, "backend", gettext_noop("client backend"), BackendMain, true)
+PG_PROCTYPE(B_BG_WORKER, "bgworker", gettext_noop("background worker"), BackgroundWorkerMain, true)
+PG_PROCTYPE(B_BG_WRITER, "bgwriter", gettext_noop("background writer"), BackgroundWriterMain, true)
+PG_PROCTYPE(B_CHECKPOINTER, "checkpointer", gettext_noop("checkpointer"), CheckpointerMain, true)
+PG_PROCTYPE(B_DEAD_END_BACKEND, "backend", gettext_noop("dead-end client backend"), BackendMain, true)
+PG_PROCTYPE(B_INVALID, "postmaster", gettext_noop("unrecognized"), NULL, false)
+PG_PROCTYPE(B_IO_WORKER, "ioworker", gettext_noop("io worker"), IoWorkerMain, true)
+PG_PROCTYPE(B_LOGGER, "syslogger", gettext_noop("syslogger"), SysLoggerMain, false)
+PG_PROCTYPE(B_SLOTSYNC_WORKER, "slotsyncworker", gettext_noop("slotsync worker"), ReplSlotSyncWorkerMain, true)
+PG_PROCTYPE(B_STANDALONE_BACKEND, "backend", gettext_noop("standalone backend"), NULL, false)
+PG_PROCTYPE(B_STARTUP, "startup", gettext_noop("startup"), StartupProcessMain, true)
+PG_PROCTYPE(B_WAL_RECEIVER, "walreceiver", gettext_noop("walreceiver"), WalReceiverMain, true)
+PG_PROCTYPE(B_WAL_SENDER, "walsender", gettext_noop("walsender"), NULL, true)
+PG_PROCTYPE(B_WAL_SUMMARIZER, "walsummarizer", gettext_noop("walsummarizer"), WalSummarizerMain, true)
+PG_PROCTYPE(B_WAL_WRITER, "walwriter", gettext_noop("walwriter"), WalWriterMain, true)
diff --git a/src/test/regress/expected/guc.out b/src/test/regress/expected/guc.out
index 9a6fd503009..616b10f80d6 100644
--- a/src/test/regress/expected/guc.out
+++ b/src/test/regress/expected/guc.out
@@ -955,19 +955,19 @@ SHOW log_min_messages;
 
 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.
+DETAIL:  Default 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.
+DETAIL:  Redundant specification of default log level.
 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:  Process type "backend" was already assigned.
+DETAIL:  Redundant log level specification for process type "backend".
 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 process 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".
+DETAIL:  Unrecognized log level for process type "checkpointer": "bar".
 SET log_min_messages TO 'backend:error, checkpointer:debug3, fatal, archiver:debug2, autovacuum:debug1, walsender:debug3';
 SHOW log_min_messages;
                                         log_min_messages                                         
-- 
2.47.3

---

From: "Euler Taveira" <[email-masked]>
Date: Fri, 06 Feb 2026 12:45:20 -0300

> Here are some fixups for the main patch.  I include yours so that CI

All suggestions seem good to me.

> which IMO makes more sense from the user point of view.

I'm fine with "default" instead of "generic". However, you forgot to replace
"generic" in a few places. The attached patch fixes them all.

> values.  This is okay because we have already mallocked a copy for

Nice trick.

> log_min_messages initializer in guc_tables.c.

Ok.

> inside the check_log_min_messages function.

That's true.

> do the needful.  With this we can remove the loop entirely.

Ok.

> place and jump there with a goto.

I tend to avoid goto. However, in this case, it seems it improves readability.

> can just compare foreach_current_index() with 0.

Didn't know about foreach_current_index.

> * Rewrote docs and comments

Ok.

I attached the same patches that you shared plus the s/generic/default/ that I
said earlier for the sake of CI.

From 8c1fb5c97cd3fd342120f8c44d34f7bdc18e8b74 Mon Sep 17 00:00:00 2001
From: Euler Taveira <[email-masked]>
Date: Tue, 4 Nov 2025 17:18:20 -0300
Subject: [PATCH v11 1/3] log_min_messages per process type

diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
index f1af1505cf3..287816fb504 100644
--- a/doc/src/sgml/config.sgml
+++ b/doc/src/sgml/config.sgml
@@ -7120,7 +7120,7 @@ local0.*    /var/log/postgresql
      <variablelist>
 
@@ -7129,14 +7129,38 @@ local0.*    /var/log/postgresql

 	return true;
 }
+
+/*

 /*
 
 	switch (backendType)
 	{
index c1f1603cd39..762b8efe6b0 100644
@@ -1693,12 +1693,14 @@

 { name => 'log_parameter_max_length', type => 'int', context => 'PGC_SUSET', group => 'LOGGING_WHAT',
diff --git a/src/backend/utils/misc/guc_tables.c b/src/backend/utils/misc/guc_tables.c
index 5df3a36bf64..46a5cf13e4a 100644
--- a/src/backend/utils/misc/guc_tables.c
+++ b/src/backend/utils/misc/guc_tables.c
@@ -147,7 +147,7 @@ static const struct config_enum_entry client_message_level_options[] = {
 	{NULL, 0, false}
 };
 
@@ -546,7 +546,6 @@ static bool standard_conforming_strings = true;
 
@@ -604,6 +603,7 @@ static char *server_version_string;
 
 #ifdef HAVE_SYSLOG
 #define	DEFAULT_SYSLOG_FACILITY LOG_LOCAL0
@@ -656,6 +656,23 @@ char	   *role_string;
 /* should be static, but guc.c needs to get at this */
 bool		in_hot_standby_guc;
 
+/*
+ * log_min_messages
+ */
 
 /*
index 1ae594af843..a9798cc628d 100644
@@ -545,6 +545,8 @@

 /*

 
 
 #endif							/* GUC_HOOKS_H */

From d8a6a1824a0f93d5418dceb06fc692bb66b62446 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=C3=81lvaro=20Herrera?= <[email-masked]>
Date: Fri, 6 Feb 2026 10:24:29 +0100
Subject: [PATCH v11 2/3] review

---

index 287816fb504..aeed21b1548 100644
@@ -7127,15 +7127,15 @@ local0.*    /var/log/postgresql

 
 
 		/*

 

 			if (!found)
 			{
 
-			/*

 			if (!found)
 			{
 
-			guc_free(ptype);
 
 	/*
 
 	/*
 
-	initStringInfo(&buf);

+/*

 	switch (backendType)
 	{
-#define PG_PROCTYPE(bktype, bkcategory, description, main_func, shmem_attach, log_min_messages)	\
+#define PG_PROCTYPE(bktype, bkcategory, description, main_func, shmem_attach)	\
 		case bktype: backendDesc = 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 46a5cf13e4a..741fce8dede 100644
--- a/src/backend/utils/misc/guc_tables.c
+++ b/src/backend/utils/misc/guc_tables.c
@@ -657,23 +657,15 @@ char	   *role_string;
 bool		in_hot_standby_guc;
 
 /*
- * log_min_messages

 

From ff64f521873c5f75ae5813c4441d55404c1854f8 Mon Sep 17 00:00:00 2001
From: Euler Taveira <[email-masked]>
Date: Fri, 6 Feb 2026 12:42:21 -0300
Subject: [PATCH v11 3/3] fixup! review

---
 src/backend/commands/variable.c | 18 +++++++++---------
 1 file changed, 9 insertions(+), 9 deletions(-)

diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c
index 97b9a6b5964..8ea6f6f57e6 100644
--- a/src/backend/commands/variable.c
+++ b/src/backend/commands/variable.c
@@ -1295,7 +1295,7 @@ check_log_min_messages(char **newval, void **extra, GucSource source)
 	char	   *result;
 	int			newlevel[BACKEND_NUM_TYPES];
 	bool		assigned[BACKEND_NUM_TYPES] = {0};
-	int			genericlevel = -1;	/* -1 means not assigned */
+	int			defaultlevel = -1;	/* -1 means not assigned */
 
 	const char *const process_types[] = {
 #define PG_PROCTYPE(bktype, bkcategory, description, main_func, shmem_attach) \
@@ -1331,8 +1331,8 @@ check_log_min_messages(char **newval, void **extra, GucSource source)
 			const struct config_enum_entry *entry;
 			bool		found = false;
 
-			/* Reject duplicates for generic log level. */
-			if (genericlevel != -1)
+			/* Reject duplicates for default log level. */
+			if (defaultlevel != -1)
 			{
 				GUC_check_errdetail("Redundant specification of default log level.");
 				goto lmm_fail;
@@ -1343,7 +1343,7 @@ check_log_min_messages(char **newval, void **extra, GucSource source)
 			{
 				if (pg_strcasecmp(entry->name, tok) == 0)
 				{
-					genericlevel = entry->val;
+					defaultlevel = entry->val;
 					found = true;
 					break;
 				}
@@ -1426,9 +1426,9 @@ lmm_fail:
 	}
 
 	/*
-	 * The generic log level must be specified. It is the fallback value.
+	 * The default log level must be specified. It is the fallback value.
 	 */
-	if (genericlevel == -1)
+	if (defaultlevel == -1)
 	{
 		GUC_check_errdetail("Default log level was not defined.");
 		guc_free(rawstring);
@@ -1437,14 +1437,14 @@ lmm_fail:
 	}
 
 	/*
-	 * Apply the generic log level after all of the specific process types
+	 * Apply the default log level after all of the specific process types
 	 * have been assigned. Hence, it doesn't matter the order you specify the
-	 * generic log level, the final result will be the same.
+	 * default log level, the final result will be the same.
 	 */
 	for (int i = 0; i < BACKEND_NUM_TYPES; i++)
 	{
 		if (!assigned[i])
-			newlevel[i] = genericlevel;
+			newlevel[i] = defaultlevel;
 	}
 
 	/*
-- 
2.39.5