Hello I noticed failures under Windows, and realized that the EXEC_BACKEND case was busted. That's easy to fix -- just assign MyBackendType in SubPostmasterMain() as well. With that fix I was still getting some crashes in three test modules, and after some debugging it turned out that if you have shared_preload_library with a background worker and use %b in the log_line_prefix, you get a crash trying to expand a name that hasn't been set up yet. I figured we can use a constant string in that case. Better ideas for that string welcome.
So here's your v6 again with those fixes as 0003 -- let's see what CI thinks of this. I haven't looked at your doc changes yet. BTW with %b in log_line_prefix, the log file looks ... interesting. -- Álvaro Herrera Breisgau, Deutschland — https://www.EnterpriseDB.com/ "Before you were born your parents weren't as boring as they are now. They got that way paying your bills, cleaning up your room and listening to you tell them how idealistic you are." -- Charles J. Sykes' advice to teenagers
>From d6e56c7259088529ae7a114f57f4dc875697dd97 Mon Sep 17 00:00:00 2001 From: Euler Taveira <[email protected]> Date: Tue, 4 Nov 2025 17:18:20 -0300 Subject: [PATCH v7 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 | 208 ++++++++++++++++++ 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 | 6 +- src/include/utils/guc_hooks.h | 2 + src/test/regress/expected/guc.out | 54 +++++ src/test/regress/sql/guc.sql | 18 ++ 14 files changed, 372 insertions(+), 41 deletions(-) diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml index 405c9689bd0..62d6c0d36a2 100644 --- a/doc/src/sgml/config.sgml +++ b/doc/src/sgml/config.sgml @@ -7069,7 +7069,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> @@ -7078,14 +7078,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 ebc204c4462..d123b7ebb77 100644 --- a/src/backend/commands/extension.c +++ b/src/backend/commands/extension.c @@ -1143,7 +1143,7 @@ execute_extension_script(Oid extensionOid, ExtensionControlFile *control, (void) set_config_option("client_min_messages", "warning", PGC_USERSET, PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); - if (log_min_messages < WARNING) + if (log_min_messages[MyBackendType] < WARNING) (void) set_config_option_ext("log_min_messages", "warning", PGC_SUSET, PGC_S_SESSION, BOOTSTRAP_SUPERUSERID, diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 608f10d9412..2b309791ee7 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" @@ -1257,3 +1258,210 @@ 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 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; + ListCell *l; + 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(l, elemlist) + { + char *tok = (char *) lfirst(l); + 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 976638a58ac..c2a044321d1 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 29643c51439..15d771a16c9 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 fec79992c8d..2c3926cbadf 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 3b9d8349078..450180bee31 100644 --- a/src/backend/utils/misc/guc_parameters.dat +++ b/src/backend/utils/misc/guc_parameters.dat @@ -1683,12 +1683,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 f87b558c2c6..a9ef447d1d4 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 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; @@ -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 @@ -646,6 +646,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 dc9e2255f8a..24b5d983590 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 242862451d8..5fbb8e7ab7c 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 f21ec37da89..98b0ba08c0c 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,9 @@ extern PGDLLIMPORT bool trace_sort; extern PGDLLIMPORT bool optimize_bounded_sort; #endif +/* log_min_messages */ +extern PGDLLIMPORT const char *const log_min_messages_process_types[]; + /* * Declarations for options for enum values * @@ -344,6 +347,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 82ac8646a8d..e6ffc96468f 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -174,5 +174,7 @@ extern void assign_wal_sync_method(int new_wal_sync_method, void *extra); extern bool check_synchronized_standby_slots(char **newval, void **extra, GucSource source); extern void assign_synchronized_standby_slots(const char *newval, void *extra); +extern bool check_log_min_messages(char **newval, void **extra, GucSource source); +extern void assign_log_min_messages(const char *newval, void *extra); #endif /* GUC_HOOKS_H */ diff --git a/src/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.47.3
>From c92d8b66de44b965ce1460e61ed047d1ae9d6b44 Mon Sep 17 00:00:00 2001 From: Euler Taveira <[email protected]> Date: Tue, 25 Nov 2025 21:09:11 -0300 Subject: [PATCH v7 2/3] Assign backend type earlier 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.) --- 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 | 2 ++ 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 - 13 files changed, 2 insertions(+), 14 deletions(-) diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c index 1c38488f2cb..36c1911a3a8 100644 --- a/src/backend/postmaster/autovacuum.c +++ b/src/backend/postmaster/autovacuum.c @@ -388,7 +388,6 @@ AutoVacLauncherMain(const void *startup_data, size_t startup_data_len) PostmasterContext = NULL; } - MyBackendType = B_AUTOVAC_LAUNCHER; init_ps_display(NULL); ereport(DEBUG1, @@ -1401,7 +1400,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 142a02eb5e9..260f051711e 100644 --- a/src/backend/postmaster/bgworker.c +++ b/src/backend/postmaster/bgworker.c @@ -741,7 +741,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 72f5acceec7..4119758a72c 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 afb3d6d8630..427f50752d4 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 c2a044321d1..35420b8c9fb 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)) { diff --git a/src/backend/postmaster/pgarch.c b/src/backend/postmaster/pgarch.c index ce6b5299324..b760d1aed40 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 27e86cf393f..13e86a2921e 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 50c2edec1f6..a378b15a6de 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 c4a888a081c..ce497d8ec42 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 fd92c8b7a33..c1b4ddda555 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 7e3b4c4413e..364df1ad519 100644 --- a/src/backend/replication/logical/slotsync.c +++ b/src/backend/replication/logical/slotsync.c @@ -1436,8 +1436,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 3a94c9683a7..154fe9e0cb5 100644 --- a/src/backend/replication/walreceiver.c +++ b/src/backend/replication/walreceiver.c @@ -168,7 +168,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 866a35abbd1..64caaa7b766 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); -- 2.47.3
>From 8aa3f579cd0e070e7449883ecad64bbf182e21e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Herrera?= <[email protected]> Date: Tue, 9 Dec 2025 09:53:01 +0100 Subject: [PATCH v7 3/3] Fixup: assign backend type earlier --- src/backend/postmaster/launch_backend.c | 3 +++ src/backend/utils/error/elog.c | 7 ++++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/backend/postmaster/launch_backend.c b/src/backend/postmaster/launch_backend.c index 35420b8c9fb..96624e08b5a 100644 --- a/src/backend/postmaster/launch_backend.c +++ b/src/backend/postmaster/launch_backend.c @@ -588,6 +588,8 @@ SubPostmasterMain(int argc, char *argv[]) IsPostmasterEnvironment = true; whereToSendOutput = DestNone; + MyBackendType = B_BACKEND; + /* * Capture the end of process creation for logging. We don't include the * time spent copying data from shared memory and setting up the backend. @@ -611,6 +613,7 @@ SubPostmasterMain(int argc, char *argv[]) if (strcmp(child_process_kinds[idx].name, child_kind) == 0) { child_type = (BackendType) idx; + MyBackendType = child_type; found = true; break; } diff --git a/src/backend/utils/error/elog.c b/src/backend/utils/error/elog.c index 15d771a16c9..d7f4a44c5a7 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.47.3
