On Wed, Feb 5, 2025, at 3:51 PM, Álvaro Herrera wrote:
> On 2024-Dec-17, Euler Taveira wrote:
> 
> > Sometimes you need to inspect some debug messages from autovacuum worker but
> > you cannot apply the same setting for backends (that could rapidly fill the 
> > log
> > file). This proposal aims to change log_min_messages to have different log
> > levels depending on which backend type the message comes from.
> > 
> > The syntax was changed from enum to string and it accepts a list of 
> > elements.
> > 
> > Instead of enum, it now accepts a comma-separated list of elements (string).
> > Each element is LOGLEVEL:BACKENDTYPE.
> 
> This format seems unintuitive.  I would have thought you do it the other
> way around, "backendtype:loglevel" ... that seems more natural because
> it's like assigning the 'loglevel' value to the 'backendtype' element.
>   SET log_min_messages TO 'checkpointer:debug2, autovacuum:debug1';

Alvaro, thanks for your feedback. Your suggestion makes sense to me.

> I dislike the array of names in variable.c.  We already have an array in
> launch_backend.c (child_process_kinds), plus GetBackendTypeDesc in
> miscinit.c.  Maybe not for this patch to clean up though.

I thought about using child_process_kinds but two details made me give
up on the idea: (a) multiple names per backend type (for example, 
B_BACKEND, B_DEAD_END_BACKEND, B_STANDALONE_BACKEND) and (b) spaces into
names. Maybe we should have a group into child_process_kinds but as you
said it seems material for another patch.

> I think it should be acceptable to configure one global setting with
> exceptions for particular backend types:
> 
> log_min_messages = WARNING, autovacuum:DEBUG1
> 
> Right now I think the code only accepts the unadorned log level if there
> are no other items in the list.  I think the proposal downthread is to
> use the keyword ALL for this,
> 
>   log_min_messages = all:WARNING, autovacuum:DEBUG1   # I don't like this
> 
> but I think it's inferior, because then "all" is not really "all", and I
> think it would be different if I had said
> 
>   log_min_messages = autovacuum:DEBUG1, all:WARNING   # I don't like this
> 
> because it looks like the "all" entry should override the one I set for
> autovacuum before, which frankly would not make sense to me.

Good point. After reflection, I agree that "all" is not a good keyword.
This patch turns backend type as optional so WARNING means apply this
log level as a final step to the backend types that are not specified in
the list.

> So I think these two lines,
> 
> log_min_messages = WARNING, autovacuum:DEBUG1
> log_min_messages = autovacuum:DEBUG1, WARNING
> 
> should behave identically and mean "set the level for autovacuum to
> DEBUG1, and to any other backend type to WARNING.

Done.

> Also, I think it'd be better to reject duplicates in the list.  Right
> now it looks like the last entry for one backend type overrides prior
> ones.  I mean
> 
> log_min_messages = autovacuum:DEBUG1, autovacuum:ERROR
> 
> would set autovacuum to error, but that might be mistake prone if your
> string is long.  So implementation-wise I suggest to initialize the
> whole newlogminmsgs array to -1, then scan the list of entries (saving
> an entry without backend type as the one to use later and) setting every
> backend type to the number specified; if we see trying to set a value
> that's already different from -1, throw error.  After scanning the whole
> log_min_messages array, we scan the newlogminmsgs and set any entries
> that are still -1 to the value that we saved before.
> 
> 
> The new code in variable.c should be before the /* DATESTYLE */ comment
> rather than at the end of the file.

It was added into the MISCELLANEOUS section.

> 
> You still have many XXX comments.  Also, postgresql.conf should list the
> valid values for backendtype, as well as show an example of a valid
> setting.  Please don't use ALLCAPS backend types in the docs, this looks
> ugly:
> 
> > +        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>LOGGER</literal>,
> > +        <literal>SLOTSYNCWORKER</literal>, <literal>WALRECEIVER</literal>,
> > +        <literal>WALSENDER</literal>, <literal>WALSUMMARIZER</literal>, and
> > +        <literal>WALWRITER</literal>.

Done.

Just to recap what was changed:

- patch was rebased
- backend type is optional and means all unspecified backend types
- generic log level (without backend type) is mandatory and the order it 
  ppears is not important (it is applied for the remaining backend types)
- fix Windows build
- new tests to cover the changes


--
Euler Taveira
EDB   https://www.enterprisedb.com/
From 0640ddb6e5510f1b600982331490188d20bfa7e9 Mon Sep 17 00:00:00 2001
From: Euler Taveira <eu...@eulerto.com>
Date: Mon, 11 Dec 2023 17:24:50 -0300
Subject: [PATCH v2] 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, logger, slotsyncworker, walreceiver, walsender,
walsummarizer and walwriter. It should be part of this list a single log
level 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                      |  30 ++-
 src/backend/commands/extension.c              |   2 +-
 src/backend/commands/variable.c               | 187 ++++++++++++++++++
 src/backend/utils/error/elog.c                |   2 +-
 src/backend/utils/misc/guc_tables.c           |  81 ++++++--
 src/backend/utils/misc/postgresql.conf.sample |   1 +
 src/include/miscadmin.h                       |   2 +
 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             |  48 +++++
 src/test/regress/sql/guc.sql                  |  16 ++
 12 files changed, 352 insertions(+), 25 deletions(-)

diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
index d2fa5f7d1a9..3e8df85556d 100644
--- a/doc/src/sgml/config.sgml
+++ b/doc/src/sgml/config.sgml
@@ -6861,7 +6861,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>
@@ -6870,14 +6870,26 @@ 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>logger</literal>,
+        <literal>slotsyncworker</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. The single <literal>LEVEL</literal> is mandatory 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 d9bb4ce5f1e..93923c26a7e 100644
--- a/src/backend/commands/extension.c
+++ b/src/backend/commands/extension.c
@@ -1059,7 +1059,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 4ad6e236d69..0f646298bf1 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"
@@ -1271,3 +1272,189 @@ 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)
+				{
+					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/utils/error/elog.c b/src/backend/utils/error/elog.c
index 860bbd40d42..fc5aedab0c8 100644
--- a/src/backend/utils/error/elog.c
+++ b/src/backend/utils/error/elog.c
@@ -234,7 +234,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/misc/guc_tables.c b/src/backend/utils/misc/guc_tables.c
index ad25cbb39c5..9d38474fc79 100644
--- a/src/backend/utils/misc/guc_tables.c
+++ b/src/backend/utils/misc/guc_tables.c
@@ -139,7 +139,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},
@@ -521,7 +521,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;
@@ -579,6 +578,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
@@ -623,6 +623,60 @@ char	   *role_string;
 /* should be static, but guc.c needs to get at this */
 bool		in_hot_standby_guc;
 
+/*
+ * This must match enum BackendType! It should be static, but
+ * commands/variable.c needs to get at this.
+ */
+int			log_min_messages[] = {
+	[B_INVALID] = WARNING,
+	[B_BACKEND] = WARNING,
+	[B_DEAD_END_BACKEND] = WARNING,
+	[B_AUTOVAC_LAUNCHER] = WARNING,
+	[B_AUTOVAC_WORKER] = WARNING,
+	[B_BG_WORKER] = WARNING,
+	[B_WAL_SENDER] = WARNING,
+	[B_SLOTSYNC_WORKER] = WARNING,
+	[B_STANDALONE_BACKEND] = WARNING,
+	[B_ARCHIVER] = WARNING,
+	[B_BG_WRITER] = WARNING,
+	[B_CHECKPOINTER] = WARNING,
+	[B_STARTUP] = WARNING,
+	[B_WAL_RECEIVER] = WARNING,
+	[B_WAL_SUMMARIZER] = WARNING,
+	[B_WAL_WRITER] = WARNING,
+	[B_LOGGER] = WARNING,
+};
+
+StaticAssertDecl(lengthof(log_min_messages) == BACKEND_NUM_TYPES,
+				 "array length mismatch");
+
+/*
+ * This must match enum BackendType! It might be in commands/variable.c but for
+ * convenience it is near log_min_messages.
+ */
+const char *const log_min_messages_backend_types[] = {
+	[B_INVALID] = "backend",	/* XXX same as backend? */
+	[B_BACKEND] = "backend",
+	[B_DEAD_END_BACKEND] = "backend",	/* XXX same as backend? */
+	[B_AUTOVAC_LAUNCHER] = "autovacuum",
+	[B_AUTOVAC_WORKER] = "autovacuum",
+	[B_BG_WORKER] = "bgworker",
+	[B_WAL_SENDER] = "walsender",
+	[B_SLOTSYNC_WORKER] = "slotsyncworker",
+	[B_STANDALONE_BACKEND] = "backend", /* XXX same as backend? */
+	[B_ARCHIVER] = "archiver",
+	[B_BG_WRITER] = "bgwriter",
+	[B_CHECKPOINTER] = "checkpointer",
+	[B_STARTUP] = "backend",	/* XXX same as backend? */
+	[B_WAL_RECEIVER] = "walreceiver",
+	[B_WAL_SUMMARIZER] = "walsummarizer",
+	[B_WAL_WRITER] = "walwriter",
+	[B_LOGGER] = "logger",
+};
+
+StaticAssertDecl(lengthof(log_min_messages_backend_types) == BACKEND_NUM_TYPES,
+				 "array length mismatch");
+
 
 /*
  * Displayable names for context types (enum GucContext)
@@ -4223,6 +4277,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."),
@@ -5011,17 +5077,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 2d1de9c37bd..c99e1fb90ae 100644
--- a/src/backend/utils/misc/postgresql.conf.sample
+++ b/src/backend/utils/misc/postgresql.conf.sample
@@ -526,6 +526,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/miscadmin.h b/src/include/miscadmin.h
index a2b63495eec..36b0b82cf3e 100644
--- a/src/include/miscadmin.h
+++ b/src/include/miscadmin.h
@@ -332,6 +332,8 @@ extern void SwitchBackToLocalLatch(void);
  *
  * If you add entries, please also update the child_process_kinds array in
  * launch_backend.c.
+ * XXX If you add a new backend type or change the order, update
+ * log_min_messages because it relies on this order to work correctly.
  */
 typedef enum BackendType
 {
diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h
index 1233e07d7da..bb23ca65449 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 951451a9765..cf27960e239 100644
--- a/src/include/utils/guc_hooks.h
+++ b/src/include/utils/guc_hooks.h
@@ -176,5 +176,7 @@ extern bool check_synchronized_standby_slots(char **newval, void **extra,
 extern void assign_synchronized_standby_slots(const char *newval, void *extra);
 extern bool check_idle_replication_slot_timeout(int *newval, void **extra,
 												GucSource source);
+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 ab47145ec36..8a60ec5997a 100644
--- a/src/include/utils/guc_tables.h
+++ b/src/include/utils/guc_tables.h
@@ -297,6 +297,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..7572e0addbc 100644
--- a/src/test/regress/expected/guc.out
+++ b/src/test/regress/expected/guc.out
@@ -913,3 +913,51 @@ 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, 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..e9dddb4e72d 100644
--- a/src/test/regress/sql/guc.sql
+++ b/src/test/regress/sql/guc.sql
@@ -368,3 +368,19 @@ 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, 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