Support a wildcard in backtrace_functions
I would like to be able to add backtraces to all ERROR logs. This is
useful to me, because during postgres or extension development any
error that I hit is usually unexpected. This avoids me from having to
change backtrace_functions every time I get an error based on the
function name listed in the LOCATION output (added by "\set VERBOSITY
verbose").
Attached is a trivial patch that starts supporting
backtrace_functions='*'. By setting that in postgresql.conf for my dev
environment it starts logging backtraces always.
The main problem it currently has is that it adds backtraces to all
LOG level logs too. So probably we want to make backtrace_functions
only log backtraces for ERROR and up (or maybe WARNING/NOTICE and up),
or add a backtrace_functions_level GUC too control this behaviour. The
docs of backtrace_functions currently heavily suggest that it should
only be logging backtraces for errors, so either we actually start
doing that or we should clarify the docs (emphasis mine):
Show quoted text
This parameter contains a comma-separated list of C function
names. If an **error** is raised and the name of the internal C function
where the **error** happens matches a value in the list, then a
backtrace is written to the server log together with the error
message. This can be used to debug specific areas of the
source code.
Attachments:
v1-0001-Add-wildcard-support-to-backtrace_functions-GUC.patchapplication/x-patch; name=v1-0001-Add-wildcard-support-to-backtrace_functions-GUC.patchDownload
From dacb18f62e7794d8165de80b811c994d384dc060 Mon Sep 17 00:00:00 2001
From: Jelte Fennema-Nio <jelte.fennema@microsoft.com>
Date: Wed, 20 Dec 2023 11:41:18 +0100
Subject: [PATCH v1] Add wildcard support to backtrace_functions GUC
With this change setting backtrace_functions to '*' will start logging
backtraces for all errors (or more precisely all logs).
---
doc/src/sgml/config.sgml | 5 +++++
src/backend/utils/error/elog.c | 8 +++++---
2 files changed, 10 insertions(+), 3 deletions(-)
diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
index 44cada2b403..9b352109a3e 100644
--- a/doc/src/sgml/config.sgml
+++ b/doc/src/sgml/config.sgml
@@ -11015,6 +11015,11 @@ dynamic_library_path = 'C:\tools\postgresql;H:\my_project\lib;$libdir'
be used to debug specific areas of the source code.
</para>
+ <para>
+ A single <literal>*</literal> character is interpreted as a wildcard and
+ will cause all errors in the log to contain backtraces.
+ </para>
+
<para>
Backtrace support is not available on all platforms, and the quality
of the backtraces depends on compilation options.
diff --git a/src/backend/utils/error/elog.c b/src/backend/utils/error/elog.c
index 6ea575a53b1..840fbe42ac5 100644
--- a/src/backend/utils/error/elog.c
+++ b/src/backend/utils/error/elog.c
@@ -840,6 +840,8 @@ matches_backtrace_functions(const char *funcname)
if (*p == '\0') /* end of backtrace_symbol_list */
break;
+ if (strcmp("*", p) == 0)
+ return true;
if (strcmp(funcname, p) == 0)
return true;
p += strlen(p) + 1;
@@ -2128,14 +2130,14 @@ check_backtrace_functions(char **newval, void **extra, GucSource source)
int j;
/*
- * Allow characters that can be C identifiers and commas as separators, as
- * well as some whitespace for readability.
+ * Allow characters that can be C identifiers, commas as separators, the
+ * wildcard symbol, as well as some whitespace for readability.
*/
validlen = strspn(*newval,
"0123456789_"
"abcdefghijklmnopqrstuvwxyz"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
- ", \n\t");
+ ",* \n\t");
if (validlen != newvallen)
{
GUC_check_errdetail("invalid character");
base-commit: 00498b718564cee3530b76d860b328718aed672b
--
2.34.1
On 20 Dec 2023, at 12:23, Jelte Fennema-Nio <me@jeltef.nl> wrote:
Attached is a trivial patch that starts supporting
backtrace_functions='*'. By setting that in postgresql.conf for my dev
environment it starts logging backtraces always.
I happened to implement pretty much the same diff today during a debugging
session, and then stumbled across this when searching the archives, so count me
in for +1 on the concept.
The main problem it currently has is that it adds backtraces to all
LOG level logs too. So probably we want to make backtrace_functions
only log backtraces for ERROR and up (or maybe WARNING/NOTICE and up),
or add a backtrace_functions_level GUC too control this behaviour.
A wildcard should IMO only apply for ERROR (and higher) so I've hacked that up
in the attached v2. I was thinking about WARNING as well but opted against it.
The docs of backtrace_functions currently heavily suggest that it should
only be logging backtraces for errors, so either we actually start
doing that or we should clarify the docs
I think we should keep the current functionality and instead adjust the docs.
This has already been shipped like this, and restricting it now without a clear
usecase for doing so seems invasive (and someone might very well be using
this). 0001 in the attached adjusts this.
--
Daniel Gustafsson
Attachments:
v2-0002-Support-wildcard-in-backtrace_functions-to-handle.patchapplication/octet-stream; name=v2-0002-Support-wildcard-in-backtrace_functions-to-handle.patch; x-unix-mode=0644Download
From 7f9208ccb95df113873e7c23257e1215b1be6919 Mon Sep 17 00:00:00 2001
From: Daniel Gustafsson <dgustafsson@postgresql.org>
Date: Mon, 12 Feb 2024 14:02:40 +0100
Subject: [PATCH v2 2/2] Support wildcard in backtrace_functions to handle all
errors
Sometimes during debugging it can be useful to get backtraces for all
errors, regardless of where they were fired. This is possible already
by specifying a list of functions, but it can quickly become unwieldy
when the exact callsite isn't known in advance. This adds support for
specifying a '*' wildcard which will emit backtraces for *all* errors
regardless (but only elevel >= ERROR).
Author: Jelte Fennema-Nio <me@jeltef.nl>
Discussion: https://postgr.es/m/CAGECzQTpdujCEt2SH4DBwRLoDq4HJArGDaxJSsWX0G=tNnzaVA@mail.gmail.com
---
doc/src/sgml/config.sgml | 5 +++++
src/backend/utils/error/elog.c | 14 ++++++++------
2 files changed, 13 insertions(+), 6 deletions(-)
diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
index f865d0b87e..21cc96c327 100644
--- a/doc/src/sgml/config.sgml
+++ b/doc/src/sgml/config.sgml
@@ -11075,6 +11075,11 @@ dynamic_library_path = 'C:\tools\postgresql;H:\my_project\lib;$libdir'
be used to debug specific areas of the source code.
</para>
+ <para>
+ A single <literal>*</literal> character is interpreted as a wildcard and
+ will cause all errors in the log to contain backtraces.
+ </para>
+
<para>
Backtrace support is not available on all platforms, and the quality
of the backtraces depends on compilation options.
diff --git a/src/backend/utils/error/elog.c b/src/backend/utils/error/elog.c
index 700fbde6db..6776972309 100644
--- a/src/backend/utils/error/elog.c
+++ b/src/backend/utils/error/elog.c
@@ -182,7 +182,7 @@ static void set_stack_entry_domain(ErrorData *edata, const char *domain);
static void set_stack_entry_location(ErrorData *edata,
const char *filename, int lineno,
const char *funcname);
-static bool matches_backtrace_functions(const char *funcname);
+static bool matches_backtrace_functions(const char *funcname, int elevel);
static pg_noinline void set_backtrace(ErrorData *edata, int num_skip);
static void set_errdata_field(MemoryContextData *cxt, char **ptr, const char *str);
static void FreeErrorDataContents(ErrorData *edata);
@@ -500,7 +500,7 @@ errfinish(const char *filename, int lineno, const char *funcname)
if (!edata->backtrace &&
((edata->funcname &&
backtrace_functions &&
- matches_backtrace_functions(edata->funcname)) ||
+ matches_backtrace_functions(edata->funcname, edata->elevel)) ||
(edata->sqlerrcode == ERRCODE_INTERNAL_ERROR &&
backtrace_on_internal_error)))
set_backtrace(edata, 2);
@@ -829,7 +829,7 @@ set_stack_entry_location(ErrorData *edata,
* See check_backtrace_functions.
*/
static bool
-matches_backtrace_functions(const char *funcname)
+matches_backtrace_functions(const char *funcname, int elevel)
{
const char *p;
@@ -842,6 +842,8 @@ matches_backtrace_functions(const char *funcname)
if (*p == '\0') /* end of backtrace_function_list */
break;
+ if (strcmp("*", p) == 0 && elevel >= ERROR)
+ return true;
if (strcmp(funcname, p) == 0)
return true;
p += strlen(p) + 1;
@@ -2134,14 +2136,14 @@ check_backtrace_functions(char **newval, void **extra, GucSource source)
int j;
/*
- * Allow characters that can be C identifiers and commas as separators, as
- * well as some whitespace for readability.
+ * Allow characters that can be C identifiers, commas as separators, the
+ * wildcard symbol, as well as some whitespace for readability.
*/
validlen = strspn(*newval,
"0123456789_"
"abcdefghijklmnopqrstuvwxyz"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
- ", \n\t");
+ ",* \n\t");
if (validlen != newvallen)
{
GUC_check_errdetail("Invalid character");
--
2.32.1 (Apple Git-133)
v2-0001-doc-Clarify-when-backtrace_functions-is-invoked.patchapplication/octet-stream; name=v2-0001-doc-Clarify-when-backtrace_functions-is-invoked.patch; x-unix-mode=0644Download
From 913cb1ccfaf1600d6f25eb5bc9a3f587806a77bb Mon Sep 17 00:00:00 2001
From: Daniel Gustafsson <dgustafsson@postgresql.org>
Date: Mon, 12 Feb 2024 13:58:13 +0100
Subject: [PATCH v2 1/2] doc: Clarify when backtrace_functions is invoked
The documentation for backtrace_functions only mentioned error logs,
but backtraces will be printed for LOG as well so soften the wording
a bit to make clear that not just errors can be debugged like this.
---
doc/src/sgml/config.sgml | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
index 61038472c5..f865d0b87e 100644
--- a/doc/src/sgml/config.sgml
+++ b/doc/src/sgml/config.sgml
@@ -11069,9 +11069,9 @@ dynamic_library_path = 'C:\tools\postgresql;H:\my_project\lib;$libdir'
<listitem>
<para>
This parameter contains a comma-separated list of C function names.
- If an error is raised and the name of the internal C function where
- the error happens matches a value in the list, then a backtrace is
- written to the server log together with the error message. This can
+ If an log entry is raised and the name of the internal C function where
+ the logging happens matches a value in the list, then a backtrace is
+ written to the server log together with the log message. This can
be used to debug specific areas of the source code.
</para>
--
2.32.1 (Apple Git-133)
On Mon, 12 Feb 2024 at 14:14, Daniel Gustafsson <daniel@yesql.se> wrote:
The main problem it currently has is that it adds backtraces to all
LOG level logs too. So probably we want to make backtrace_functions
only log backtraces for ERROR and up (or maybe WARNING/NOTICE and up),
or add a backtrace_functions_level GUC too control this behaviour.A wildcard should IMO only apply for ERROR (and higher) so I've hacked that up
in the attached v2. I was thinking about WARNING as well but opted against it.
Fine by me patch looks good. Although I think I'd slightly prefer
having a backtrace_functions_level GUC, so that we can get this same
benefit for non wildcard backtrace_functions and so we keep the
behaviour between the two consistent.
I think we should keep the current functionality and instead adjust the docs.
This has already been shipped like this, and restricting it now without a clear
usecase for doing so seems invasive (and someone might very well be using
this). 0001 in the attached adjusts this.
Would a backtrace_functions_level GUC that would default to ERROR be
acceptable in this case? It's slight behaviour break, but you would be
able to get the previous behaviour very easily. And honestly wanting
to get backtraces for non-ERROR log entries seems quite niche to me,
which to me makes it a weird default.
+ If an log entry is raised and the name of the internal C function where
s/an log entry/a log entry
On 12.02.24 14:27, Jelte Fennema-Nio wrote:
And honestly wanting
to get backtraces for non-ERROR log entries seems quite niche to me,
which to me makes it a weird default.
I think one reason for this is that non-ERRORs are fairly unique in
their wording, so you don't have to isolate them by function name.
On Mon, 12 Feb 2024 at 14:27, Jelte Fennema-Nio <me@jeltef.nl> wrote:
Would a backtrace_functions_level GUC that would default to ERROR be
acceptable in this case?
I implemented it this way in the attached patchset.
Attachments:
v3-0002-Add-wildcard-support-to-backtrace_functions-GUC.patchtext/x-patch; charset=US-ASCII; name=v3-0002-Add-wildcard-support-to-backtrace_functions-GUC.patchDownload
From 71e2c1f1fa903ecfce4a79ff5981d0d754d134a2 Mon Sep 17 00:00:00 2001
From: Jelte Fennema-Nio <jelte.fennema@microsoft.com>
Date: Wed, 20 Dec 2023 11:41:18 +0100
Subject: [PATCH v3 2/2] Add wildcard support to backtrace_functions GUC
With this change setting backtrace_functions to '*' will start logging
backtraces for all errors (or more precisely all logs).
---
doc/src/sgml/config.sgml | 5 +++++
src/backend/utils/error/elog.c | 8 +++++---
2 files changed, 10 insertions(+), 3 deletions(-)
diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
index ba5dbf9f096..a59d8e1b263 100644
--- a/doc/src/sgml/config.sgml
+++ b/doc/src/sgml/config.sgml
@@ -11136,6 +11136,11 @@ dynamic_library_path = 'C:\tools\postgresql;H:\my_project\lib;$libdir'
code.
</para>
+ <para>
+ A single <literal>*</literal> character is interpreted as a wildcard and
+ will cause all errors in the log to contain backtraces.
+ </para>
+
<para>
Backtrace support is not available on all platforms, and the quality
of the backtraces depends on compilation options.
diff --git a/src/backend/utils/error/elog.c b/src/backend/utils/error/elog.c
index 8364125f44a..923e00e766e 100644
--- a/src/backend/utils/error/elog.c
+++ b/src/backend/utils/error/elog.c
@@ -843,6 +843,8 @@ matches_backtrace_functions(const char *funcname)
if (*p == '\0') /* end of backtrace_function_list */
break;
+ if (strcmp("*", p) == 0)
+ return true;
if (strcmp(funcname, p) == 0)
return true;
p += strlen(p) + 1;
@@ -2135,14 +2137,14 @@ check_backtrace_functions(char **newval, void **extra, GucSource source)
int j;
/*
- * Allow characters that can be C identifiers and commas as separators, as
- * well as some whitespace for readability.
+ * Allow characters that can be C identifiers, commas as separators, the
+ * wildcard symbol, as well as some whitespace for readability.
*/
validlen = strspn(*newval,
"0123456789_"
"abcdefghijklmnopqrstuvwxyz"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
- ", \n\t");
+ ",* \n\t");
if (validlen != newvallen)
{
GUC_check_errdetail("Invalid character");
--
2.34.1
v3-0001-Add-backtrace_functions_min_level.patchtext/x-patch; charset=US-ASCII; name=v3-0001-Add-backtrace_functions_min_level.patchDownload
From 4ffbc6b51a711bd266f15c02611d894b080a3e11 Mon Sep 17 00:00:00 2001
From: Jelte Fennema-Nio <jelte.fennema@microsoft.com>
Date: Tue, 27 Feb 2024 17:31:24 +0100
Subject: [PATCH v3 1/2] Add backtrace_functions_min_level
Before this change a stacktrace would be attached to all logs messages
in a function that matched backtrace_functions. But in most cases people
only care about the stacktraces for messages with an ERROR level. This
changes that default to only log stacktraces for ERROR messages but
keeps the option open of logging stacktraces for different log levels
too by having users configure the new backtrace_functions_min_level GUC.
---
doc/src/sgml/config.sgml | 37 +++++++++++++++++++++++++----
src/backend/utils/error/elog.c | 1 +
src/backend/utils/misc/guc_tables.c | 12 ++++++++++
src/include/utils/guc.h | 1 +
4 files changed, 47 insertions(+), 4 deletions(-)
diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
index 36a2a5ce431..ba5dbf9f096 100644
--- a/doc/src/sgml/config.sgml
+++ b/doc/src/sgml/config.sgml
@@ -11128,10 +11128,12 @@ dynamic_library_path = 'C:\tools\postgresql;H:\my_project\lib;$libdir'
<listitem>
<para>
This parameter contains a comma-separated list of C function names.
- If an error is raised and the name of the internal C function where
- the error happens matches a value in the list, then a backtrace is
- written to the server log together with the error message. This can
- be used to debug specific areas of the source code.
+ If a log entry is raised with a level higher than
+ <xref linkend="guc-backtrace-functions-min-level"/> and the name of the
+ internal C function where the error happens matches a value in the
+ list, then a backtrace is written to the server log together with the
+ error message. This can be used to debug specific areas of the source
+ code.
</para>
<para>
@@ -11146,6 +11148,33 @@ dynamic_library_path = 'C:\tools\postgresql;H:\my_project\lib;$libdir'
</listitem>
</varlistentry>
+ <varlistentry id="guc-backtrace-functions-min-level" xreflabel="backtrace_functions_min_level">
+ <term><varname>backtrace_functions_min_level</varname> (<type>string</type>)
+ <indexterm>
+ <primary><varname>backtrace_functions_min_level</varname> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Controls which <link linkend="runtime-config-severity-levels">message
+ levels</link> cause stack traces to be written to the log, for log
+ entries in C functions that match the configured
+ <xref linkend="guc-backtrace-functions"/>.
+ </para>
+
+ <para>
+ Backtrace support is not available on all platforms, and the quality
+ of the backtraces depends on compilation options.
+ </para>
+
+ <para>
+ Only superusers and users with the appropriate <literal>SET</literal>
+ privilege can change this setting.
+ </para>
+ </listitem>
+ </varlistentry>
+
+
<varlistentry id="guc-backtrace-on-internal-error" xreflabel="backtrace_on_internal_error">
<term><varname>backtrace_on_internal_error</varname> (<type>boolean</type>)
<indexterm>
diff --git a/src/backend/utils/error/elog.c b/src/backend/utils/error/elog.c
index bba00a0087f..8364125f44a 100644
--- a/src/backend/utils/error/elog.c
+++ b/src/backend/utils/error/elog.c
@@ -500,6 +500,7 @@ errfinish(const char *filename, int lineno, const char *funcname)
if (!edata->backtrace &&
((edata->funcname &&
backtrace_functions &&
+ edata->elevel >= backtrace_functions_min_level &&
matches_backtrace_functions(edata->funcname)) ||
(edata->sqlerrcode == ERRCODE_INTERNAL_ERROR &&
backtrace_on_internal_error)))
diff --git a/src/backend/utils/misc/guc_tables.c b/src/backend/utils/misc/guc_tables.c
index 527a2b27340..20cedc208e7 100644
--- a/src/backend/utils/misc/guc_tables.c
+++ b/src/backend/utils/misc/guc_tables.c
@@ -529,6 +529,7 @@ double log_statement_sample_rate = 1.0;
double log_xact_sample_rate = 0;
char *backtrace_functions;
bool backtrace_on_internal_error = false;
+int backtrace_functions_min_level = ERROR;
int temp_file_limit = -1;
@@ -4658,6 +4659,17 @@ struct config_enum ConfigureNamesEnum[] =
NULL, NULL, NULL
},
+ {
+ {"backtrace_functions_min_level", PGC_SUSET, DEVELOPER_OPTIONS,
+ gettext_noop("Sets the message levels that create backtraces when backtrace_functions is configured"),
+ NULL,
+ GUC_NOT_IN_SAMPLE
+ },
+ &backtrace_functions_min_level,
+ ERROR, client_message_level_options,
+ NULL, NULL, NULL
+ },
+
{
{"bytea_output", PGC_USERSET, CLIENT_CONN_STATEMENT,
gettext_noop("Sets the output format for bytea."),
diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h
index 471d53da8f0..69d5cb7a125 100644
--- a/src/include/utils/guc.h
+++ b/src/include/utils/guc.h
@@ -267,6 +267,7 @@ extern PGDLLIMPORT double log_statement_sample_rate;
extern PGDLLIMPORT double log_xact_sample_rate;
extern PGDLLIMPORT char *backtrace_functions;
extern PGDLLIMPORT bool backtrace_on_internal_error;
+extern PGDLLIMPORT int backtrace_functions_min_level;
extern PGDLLIMPORT int temp_file_limit;
base-commit: 92d2ab7554f92b841ea71bcc72eaa8ab11aae662
--
2.34.1
On 27 Feb 2024, at 18:03, Jelte Fennema-Nio <me@jeltef.nl> wrote:
On Mon, 12 Feb 2024 at 14:27, Jelte Fennema-Nio <me@jeltef.nl> wrote:
Would a backtrace_functions_level GUC that would default to ERROR be
acceptable in this case?I implemented it this way in the attached patchset.
I'm not excited about adding even more GUCs but maybe it's the least bad option
here.
+ If a log entry is raised with a level higher than
+ <xref linkend="guc-backtrace-functions-min-level"/> and the name of the
This should be "equal to or higher" right?
--
Daniel Gustafsson
On Wed, 28 Feb 2024 at 19:04, Daniel Gustafsson <daniel@yesql.se> wrote:
This should be "equal to or higher" right?
Correct, nicely spotted. Fixed that. I also updated the docs for the
new backtrace_functions_min_level GUC itself too, as well as creating
a dedicated options array for the GUC. Because when updating its docs
I realized that none of the existing level arrays matched what we
wanted.
Attachments:
v4-0002-Add-wildcard-support-to-backtrace_functions-GUC.patchtext/x-patch; charset=US-ASCII; name=v4-0002-Add-wildcard-support-to-backtrace_functions-GUC.patchDownload
From 5ab507155a1cb60e490209d28a092fc2d7c0f6be Mon Sep 17 00:00:00 2001
From: Jelte Fennema-Nio <jelte.fennema@microsoft.com>
Date: Wed, 20 Dec 2023 11:41:18 +0100
Subject: [PATCH v4 2/2] Add wildcard support to backtrace_functions GUC
With this change setting backtrace_functions to '*' will start logging
backtraces for all errors (or more precisely all logs).
---
doc/src/sgml/config.sgml | 5 +++++
src/backend/utils/error/elog.c | 8 +++++---
2 files changed, 10 insertions(+), 3 deletions(-)
diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
index bc066284334..2a6d015d6d4 100644
--- a/doc/src/sgml/config.sgml
+++ b/doc/src/sgml/config.sgml
@@ -11275,6 +11275,11 @@ dynamic_library_path = 'C:\tools\postgresql;H:\my_project\lib;$libdir'
code.
</para>
+ <para>
+ A single <literal>*</literal> character is interpreted as a wildcard and
+ will cause all errors in the log to contain backtraces.
+ </para>
+
<para>
Backtrace support is not available on all platforms, and the quality
of the backtraces depends on compilation options.
diff --git a/src/backend/utils/error/elog.c b/src/backend/utils/error/elog.c
index 699d9d0a241..553e4785520 100644
--- a/src/backend/utils/error/elog.c
+++ b/src/backend/utils/error/elog.c
@@ -843,6 +843,8 @@ matches_backtrace_functions(const char *funcname)
if (*p == '\0') /* end of backtrace_function_list */
break;
+ if (strcmp("*", p) == 0)
+ return true;
if (strcmp(funcname, p) == 0)
return true;
p += strlen(p) + 1;
@@ -2133,14 +2135,14 @@ check_backtrace_functions(char **newval, void **extra, GucSource source)
int j;
/*
- * Allow characters that can be C identifiers and commas as separators, as
- * well as some whitespace for readability.
+ * Allow characters that can be C identifiers, commas as separators, the
+ * wildcard symbol, as well as some whitespace for readability.
*/
validlen = strspn(*newval,
"0123456789_"
"abcdefghijklmnopqrstuvwxyz"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
- ", \n\t");
+ ",* \n\t");
if (validlen != newvallen)
{
GUC_check_errdetail("Invalid character");
--
2.34.1
v4-0001-Add-backtrace_functions_min_level.patchtext/x-patch; charset=US-ASCII; name=v4-0001-Add-backtrace_functions_min_level.patchDownload
From d928c3e49593f3bf08def8a40c246d3aa8de46ac Mon Sep 17 00:00:00 2001
From: Jelte Fennema-Nio <jelte.fennema@microsoft.com>
Date: Tue, 27 Feb 2024 17:31:24 +0100
Subject: [PATCH v4 1/2] Add backtrace_functions_min_level
Before this change a stacktrace would be attached to all logs messages
in a function that matched backtrace_functions. But in most cases people
only care about the stacktraces for messages with an ERROR level. This
changes that default to only log stacktraces for ERROR messages but
keeps the option open of logging stacktraces for different log levels
too by having users configure the new backtrace_functions_min_level GUC.
---
doc/src/sgml/config.sgml | 46 ++++++++++++++++++++++++++---
src/backend/utils/error/elog.c | 1 +
src/backend/utils/misc/guc_tables.c | 29 ++++++++++++++++++
src/include/utils/guc.h | 1 +
4 files changed, 73 insertions(+), 4 deletions(-)
diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
index 43b1a132a2c..bc066284334 100644
--- a/doc/src/sgml/config.sgml
+++ b/doc/src/sgml/config.sgml
@@ -11267,10 +11267,12 @@ dynamic_library_path = 'C:\tools\postgresql;H:\my_project\lib;$libdir'
<listitem>
<para>
This parameter contains a comma-separated list of C function names.
- If an error is raised and the name of the internal C function where
- the error happens matches a value in the list, then a backtrace is
- written to the server log together with the error message. This can
- be used to debug specific areas of the source code.
+ If a log entry is raised with a level equal to or higher than
+ <xref linkend="guc-backtrace-functions-min-level"/> and the name of the
+ internal C function where the error happens matches a value in the
+ list, then a backtrace is written to the server log together with the
+ error message. This can be used to debug specific areas of the source
+ code.
</para>
<para>
@@ -11285,6 +11287,42 @@ dynamic_library_path = 'C:\tools\postgresql;H:\my_project\lib;$libdir'
</listitem>
</varlistentry>
+ <varlistentry id="guc-backtrace-functions-min-level" xreflabel="backtrace_functions_min_level">
+ <term><varname>backtrace_functions_min_level</varname> (<type>string</type>)
+ <indexterm>
+ <primary><varname>backtrace_functions_min_level</varname> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Controls which <link linkend="runtime-config-severity-levels">message
+ levels</link> cause stack traces to be written to the log, for messages
+ raised from C functions that match the configured
+ <xref linkend="guc-backtrace-functions"/>.
+ Valid values are <literal>DEBUG5</literal>, <literal>DEBUG4</literal>,
+ <literal>DEBUG3</literal>, <literal>DEBUG2</literal>, <literal>DEBUG1</literal>,
+ <literal>LOG</literal>, <literal>INFO</literal>, <literal>NOTICE</literal>,
+ <literal>WARNING</literal>, <literal>ERROR</literal>, <literal>FATAL</literal>,
+ and <literal>PANIC</literal>. Each level includes all the levels that
+ follow it. The later the level, the fewer messages result in a
+ backtrace. The default is <literal>ERROR</literal>. Note that
+ <literal>LOG</literal> has a different rank here than in
+ <xref linkend="guc-log-min-messages"/>.
+ </para>
+
+ <para>
+ Backtrace support is not available on all platforms, and the quality
+ of the backtraces depends on compilation options.
+ </para>
+
+ <para>
+ Only superusers and users with the appropriate <literal>SET</literal>
+ privilege can change this setting.
+ </para>
+ </listitem>
+ </varlistentry>
+
+
<varlistentry id="guc-backtrace-on-internal-error" xreflabel="backtrace_on_internal_error">
<term><varname>backtrace_on_internal_error</varname> (<type>boolean</type>)
<indexterm>
diff --git a/src/backend/utils/error/elog.c b/src/backend/utils/error/elog.c
index c9719f358b6..699d9d0a241 100644
--- a/src/backend/utils/error/elog.c
+++ b/src/backend/utils/error/elog.c
@@ -500,6 +500,7 @@ errfinish(const char *filename, int lineno, const char *funcname)
if (!edata->backtrace &&
((edata->funcname &&
backtrace_functions &&
+ edata->elevel >= backtrace_functions_min_level &&
matches_backtrace_functions(edata->funcname)) ||
(edata->sqlerrcode == ERRCODE_INTERNAL_ERROR &&
backtrace_on_internal_error)))
diff --git a/src/backend/utils/misc/guc_tables.c b/src/backend/utils/misc/guc_tables.c
index 93ded31ed92..94497e0174d 100644
--- a/src/backend/utils/misc/guc_tables.c
+++ b/src/backend/utils/misc/guc_tables.c
@@ -162,6 +162,23 @@ static const struct config_enum_entry server_message_level_options[] = {
{NULL, 0, false}
};
+static const struct config_enum_entry backtrace_functions_level_options[] = {
+ {"debug5", DEBUG5, false},
+ {"debug4", DEBUG4, false},
+ {"debug3", DEBUG3, false},
+ {"debug2", DEBUG2, false},
+ {"debug1", DEBUG1, false},
+ {"debug", DEBUG2, true},
+ {"log", LOG, false},
+ {"info", INFO, true},
+ {"notice", NOTICE, false},
+ {"warning", WARNING, false},
+ {"error", ERROR, false},
+ {"fatal", FATAL, false},
+ {"panic", PANIC, false},
+ {NULL, 0, false}
+};
+
static const struct config_enum_entry intervalstyle_options[] = {
{"postgres", INTSTYLE_POSTGRES, false},
{"postgres_verbose", INTSTYLE_POSTGRES_VERBOSE, false},
@@ -530,6 +547,7 @@ double log_statement_sample_rate = 1.0;
double log_xact_sample_rate = 0;
char *backtrace_functions;
bool backtrace_on_internal_error = false;
+int backtrace_functions_min_level = ERROR;
int temp_file_limit = -1;
@@ -4689,6 +4707,17 @@ struct config_enum ConfigureNamesEnum[] =
NULL, NULL, NULL
},
+ {
+ {"backtrace_functions_min_level", PGC_SUSET, DEVELOPER_OPTIONS,
+ gettext_noop("Sets the message levels that create backtraces when backtrace_functions is configured"),
+ NULL,
+ GUC_NOT_IN_SAMPLE
+ },
+ &backtrace_functions_min_level,
+ ERROR, backtrace_functions_level_options,
+ NULL, NULL, NULL
+ },
+
{
{"bytea_output", PGC_USERSET, CLIENT_CONN_STATEMENT,
gettext_noop("Sets the output format for bytea."),
diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h
index 471d53da8f0..69d5cb7a125 100644
--- a/src/include/utils/guc.h
+++ b/src/include/utils/guc.h
@@ -267,6 +267,7 @@ extern PGDLLIMPORT double log_statement_sample_rate;
extern PGDLLIMPORT double log_xact_sample_rate;
extern PGDLLIMPORT char *backtrace_functions;
extern PGDLLIMPORT bool backtrace_on_internal_error;
+extern PGDLLIMPORT int backtrace_functions_min_level;
extern PGDLLIMPORT int temp_file_limit;
base-commit: 53c2a97a92665be6bd7d70bd62ae6158fe4db96e
--
2.34.1
On 28 Feb 2024, at 19:50, Jelte Fennema-Nio <me@jeltef.nl> wrote:
On Wed, 28 Feb 2024 at 19:04, Daniel Gustafsson <daniel@yesql.se> wrote:
This should be "equal to or higher" right?
Correct, nicely spotted. Fixed that. I also updated the docs for the
new backtrace_functions_min_level GUC itself too, as well as creating
a dedicated options array for the GUC. Because when updating its docs
I realized that none of the existing level arrays matched what we
wanted.
Looks good, I'm marking this ready for committer for now. I just have a few
small comments:
+ A single <literal>*</literal> character is interpreted as a wildcard and
+ will cause all errors in the log to contain backtraces.
This should mention that it's all error matching the level (or higher) of the
newly introduced GUC.
+ gettext_noop("Sets the message levels that create backtraces when backtrace_functions is configured"),
I think we should add the same "Each level includes.." long_desc, and the
short_desc should end with period.
+ <para>
+ Backtrace support is not available on all platforms, and the quality
+ of the backtraces depends on compilation options.
+ </para>
I don't think we need to duplicate this para here, having it on
backtrace_functions suffice.
--
Daniel Gustafsson
On 2024-Feb-28, Jelte Fennema-Nio wrote:
diff --git a/src/backend/utils/error/elog.c b/src/backend/utils/error/elog.c index 699d9d0a241..553e4785520 100644 --- a/src/backend/utils/error/elog.c +++ b/src/backend/utils/error/elog.c @@ -843,6 +843,8 @@ matches_backtrace_functions(const char *funcname) if (*p == '\0') /* end of backtrace_function_list */ break;+ if (strcmp("*", p) == 0)
+ return true;
if (strcmp(funcname, p) == 0)
return true;
p += strlen(p) + 1;
Hmm, so if I write "foo,*" this will work but check all function names
first and on the second entry. But if I write "foo*" the GUC value will
be accepted but match nothing (as will "*foo" or "foo*bar"). I don't
like either of these behaviors. I think we should tighten this up: an
asterisk should be allowed only if it appears alone in the string
(short-circuiting check_backtrace_functions before strspn); and let's
leave the strspn() call alone.
--
Álvaro Herrera 48°01'N 7°57'E — https://www.EnterpriseDB.com/
Bob [Floyd] used to say that he was planning to get a Ph.D. by the "green
stamp method," namely by saving envelopes addressed to him as 'Dr. Floyd'.
After collecting 500 such letters, he mused, a university somewhere in
Arizona would probably grant him a degree. (Don Knuth)
On Thu, Feb 29, 2024 at 4:05 PM Alvaro Herrera <alvherre@alvh.no-ip.org> wrote:
Hmm, so if I write "foo,*" this will work but check all function names
first and on the second entry. But if I write "foo*" the GUC value will
be accepted but match nothing (as will "*foo" or "foo*bar"). I don't
like either of these behaviors. I think we should tighten this up: an
asterisk should be allowed only if it appears alone in the string
(short-circuiting check_backtrace_functions before strspn); and let's
leave the strspn() call alone.
+1 for disallowing *foo or foo* or foo*bar etc. combinations. I think
we need to go a bit further and convert backtrace_functions of type
GUC_LIST_INPUT so that check_backtrace_functions can just use
SplitIdentifierString to parse the list of identifiers. Then, the
strspn can just be something like below for each token:
validlen = strspn(*tok,
"0123456789_"
"abcdefghijklmnopqrstuvwxyz"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ");
Does anyone see a problem with it?
FWIW, I've recently noticed for my work on
https://commitfest.postgresql.org/47/2863/ that there isn't any test
covering all the backtrace related code - backtrace_functions GUC,
backtrace_on_internal_error GUC, set_backtrace(), backtrace(),
backtrace_symbols(). I came up with a test module covering these areas
https://commitfest.postgresql.org/47/4823/. I could make the TAP tests
pass on all the CF bot animals. Interestingly, the new code that gets
added for this thread can also be covered with it. Any thoughts are
welcome.
--
Bharath Rupireddy
PostgreSQL Contributors Team
RDS Open Source Databases
Amazon Web Services: https://aws.amazon.com
On 2024-Mar-06, Bharath Rupireddy wrote:
+1 for disallowing *foo or foo* or foo*bar etc. combinations.
Cool.
I think we need to go a bit further and convert backtrace_functions of
type GUC_LIST_INPUT so that check_backtrace_functions can just use
SplitIdentifierString to parse the list of identifiers. Then, the
strspn can just be something like below for each token:validlen = strspn(*tok,
"0123456789_"
"abcdefghijklmnopqrstuvwxyz"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ");Does anyone see a problem with it?
IIRC the reason it's coded as it is, is so that we have a single palloc
chunk of memory to free when the value changes; we purposefully stayed
away from SplitIdentifierString and the like. What problem do you see
with the idea I proposed? That was:
On Thu, Feb 29, 2024 at 4:05 PM Alvaro Herrera <alvherre@alvh.no-ip.org> wrote:
I think we should tighten this up: an asterisk should be allowed
only if it appears alone in the string (short-circuiting
check_backtrace_functions before strspn); and let's leave the
strspn() call alone.
That means, just add something like this at the top of
check_backtrace_functions and don't do anything to this function
otherwise (untested code):
if (newval[0] == '*' && newval[1] == '\0')
{
someval = guc_malloc(ERROR, 2);
if (someval == NULL)
return false;
someval[0] = '*';
someval[1] = '\0';
*extra = someval;
return true;
}
(Not sure if a second trailing \0 is necessary.)
--
Álvaro Herrera Breisgau, Deutschland — https://www.EnterpriseDB.com/
Voy a acabar con todos los humanos / con los humanos yo acabaré
voy a acabar con todos (bis) / con todos los humanos acabaré ¡acabaré! (Bender)
On Wed, Mar 6, 2024 at 12:41 AM Alvaro Herrera <alvherre@alvh.no-ip.org> wrote:
I think we need to go a bit further and convert backtrace_functions of
type GUC_LIST_INPUT so that check_backtrace_functions can just use
SplitIdentifierString to parse the list of identifiers. Then, the
strspn can just be something like below for each token:validlen = strspn(*tok,
"0123456789_"
"abcdefghijklmnopqrstuvwxyz"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ");Does anyone see a problem with it?
IIRC the reason it's coded as it is, is so that we have a single palloc
chunk of memory to free when the value changes; we purposefully stayed
away from SplitIdentifierString and the like.
Why do we even need to prepare another list backtrace_function_list
from the parsed identifiers? Why can't we just do something like
v4-0003? Existing logic looks a bit complicated to me personally.
I still don't understand why we can't just turn backtrace_functions to
GUC_LIST_INPUT and use SplitIdentifierString? I see a couple of
advantages with this approach:
1. It simplifies the backtrace_functions GUC related code a lot.
2. We don't need assign_backtrace_functions() and a separate variable
backtrace_function_list, we can just rely on the GUC value
backtrace_functions.
3. All we do now in check_backtrace_functions() is just parse the user
entered backtrace_functions value, and quickly exit if we have found
'*'.
4. In matches_backtrace_functions(), we iterate over the list as we
already do right now.
With the v4-0003, all of the below test cases work:
ALTER SYSTEM SET backtrace_functions = 'pg_terminate_backend,
pg_create_restore_point';
SELECT pg_reload_conf();
SHOW backtrace_functions;
-- Must see backtrace
SELECT pg_create_restore_point(repeat('A', 1024));
-- Must see backtrace
SELECT pg_terminate_backend(1234, -1);
ALTER SYSTEM SET backtrace_functions = '*, pg_create_restore_point';
SELECT pg_reload_conf();
SHOW backtrace_functions;
-- Must see backtrace as * is specified
SELECT pg_terminate_backend(1234, -1);
-- Must see an error as * is specified in between the identifier name
ALTER SYSTEM SET backtrace_functions = 'pg*_create_restore_point';
ERROR: invalid value for parameter "backtrace_functions":
"pg*_create_restore_point"
DETAIL: Invalid character
What problem do you see with the idea I proposed? That was:
On Thu, Feb 29, 2024 at 4:05 PM Alvaro Herrera <alvherre@alvh.no-ip.org> wrote:
I think we should tighten this up: an asterisk should be allowed
only if it appears alone in the string (short-circuiting
check_backtrace_functions before strspn); and let's leave the
strspn() call alone.That means, just add something like this at the top of
check_backtrace_functions and don't do anything to this function
otherwise (untested code):if (newval[0] == '*' && newval[1] == '\0')
{
someval = guc_malloc(ERROR, 2);
if (someval == NULL)
return false;
someval[0] = '*';
someval[1] = '\0';
*extra = someval;
return true;
}
This works only if '* 'is specified as the only one character in
backtrace_functions = '*', right? If yes, what if someone sets
backtrace_functions = 'foo, bar, *, baz'?
--
Bharath Rupireddy
PostgreSQL Contributors Team
RDS Open Source Databases
Amazon Web Services: https://aws.amazon.com
Attachments:
v4-0001-Add-backtrace_functions_min_level.patchapplication/octet-stream; name=v4-0001-Add-backtrace_functions_min_level.patchDownload
From d928c3e49593f3bf08def8a40c246d3aa8de46ac Mon Sep 17 00:00:00 2001
From: Jelte Fennema-Nio <jelte.fennema@microsoft.com>
Date: Tue, 27 Feb 2024 17:31:24 +0100
Subject: [PATCH v4 1/2] Add backtrace_functions_min_level
Before this change a stacktrace would be attached to all logs messages
in a function that matched backtrace_functions. But in most cases people
only care about the stacktraces for messages with an ERROR level. This
changes that default to only log stacktraces for ERROR messages but
keeps the option open of logging stacktraces for different log levels
too by having users configure the new backtrace_functions_min_level GUC.
---
doc/src/sgml/config.sgml | 46 ++++++++++++++++++++++++++---
src/backend/utils/error/elog.c | 1 +
src/backend/utils/misc/guc_tables.c | 29 ++++++++++++++++++
src/include/utils/guc.h | 1 +
4 files changed, 73 insertions(+), 4 deletions(-)
diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
index 43b1a132a2c..bc066284334 100644
--- a/doc/src/sgml/config.sgml
+++ b/doc/src/sgml/config.sgml
@@ -11267,10 +11267,12 @@ dynamic_library_path = 'C:\tools\postgresql;H:\my_project\lib;$libdir'
<listitem>
<para>
This parameter contains a comma-separated list of C function names.
- If an error is raised and the name of the internal C function where
- the error happens matches a value in the list, then a backtrace is
- written to the server log together with the error message. This can
- be used to debug specific areas of the source code.
+ If a log entry is raised with a level equal to or higher than
+ <xref linkend="guc-backtrace-functions-min-level"/> and the name of the
+ internal C function where the error happens matches a value in the
+ list, then a backtrace is written to the server log together with the
+ error message. This can be used to debug specific areas of the source
+ code.
</para>
<para>
@@ -11285,6 +11287,42 @@ dynamic_library_path = 'C:\tools\postgresql;H:\my_project\lib;$libdir'
</listitem>
</varlistentry>
+ <varlistentry id="guc-backtrace-functions-min-level" xreflabel="backtrace_functions_min_level">
+ <term><varname>backtrace_functions_min_level</varname> (<type>string</type>)
+ <indexterm>
+ <primary><varname>backtrace_functions_min_level</varname> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Controls which <link linkend="runtime-config-severity-levels">message
+ levels</link> cause stack traces to be written to the log, for messages
+ raised from C functions that match the configured
+ <xref linkend="guc-backtrace-functions"/>.
+ Valid values are <literal>DEBUG5</literal>, <literal>DEBUG4</literal>,
+ <literal>DEBUG3</literal>, <literal>DEBUG2</literal>, <literal>DEBUG1</literal>,
+ <literal>LOG</literal>, <literal>INFO</literal>, <literal>NOTICE</literal>,
+ <literal>WARNING</literal>, <literal>ERROR</literal>, <literal>FATAL</literal>,
+ and <literal>PANIC</literal>. Each level includes all the levels that
+ follow it. The later the level, the fewer messages result in a
+ backtrace. The default is <literal>ERROR</literal>. Note that
+ <literal>LOG</literal> has a different rank here than in
+ <xref linkend="guc-log-min-messages"/>.
+ </para>
+
+ <para>
+ Backtrace support is not available on all platforms, and the quality
+ of the backtraces depends on compilation options.
+ </para>
+
+ <para>
+ Only superusers and users with the appropriate <literal>SET</literal>
+ privilege can change this setting.
+ </para>
+ </listitem>
+ </varlistentry>
+
+
<varlistentry id="guc-backtrace-on-internal-error" xreflabel="backtrace_on_internal_error">
<term><varname>backtrace_on_internal_error</varname> (<type>boolean</type>)
<indexterm>
diff --git a/src/backend/utils/error/elog.c b/src/backend/utils/error/elog.c
index c9719f358b6..699d9d0a241 100644
--- a/src/backend/utils/error/elog.c
+++ b/src/backend/utils/error/elog.c
@@ -500,6 +500,7 @@ errfinish(const char *filename, int lineno, const char *funcname)
if (!edata->backtrace &&
((edata->funcname &&
backtrace_functions &&
+ edata->elevel >= backtrace_functions_min_level &&
matches_backtrace_functions(edata->funcname)) ||
(edata->sqlerrcode == ERRCODE_INTERNAL_ERROR &&
backtrace_on_internal_error)))
diff --git a/src/backend/utils/misc/guc_tables.c b/src/backend/utils/misc/guc_tables.c
index 93ded31ed92..94497e0174d 100644
--- a/src/backend/utils/misc/guc_tables.c
+++ b/src/backend/utils/misc/guc_tables.c
@@ -162,6 +162,23 @@ static const struct config_enum_entry server_message_level_options[] = {
{NULL, 0, false}
};
+static const struct config_enum_entry backtrace_functions_level_options[] = {
+ {"debug5", DEBUG5, false},
+ {"debug4", DEBUG4, false},
+ {"debug3", DEBUG3, false},
+ {"debug2", DEBUG2, false},
+ {"debug1", DEBUG1, false},
+ {"debug", DEBUG2, true},
+ {"log", LOG, false},
+ {"info", INFO, true},
+ {"notice", NOTICE, false},
+ {"warning", WARNING, false},
+ {"error", ERROR, false},
+ {"fatal", FATAL, false},
+ {"panic", PANIC, false},
+ {NULL, 0, false}
+};
+
static const struct config_enum_entry intervalstyle_options[] = {
{"postgres", INTSTYLE_POSTGRES, false},
{"postgres_verbose", INTSTYLE_POSTGRES_VERBOSE, false},
@@ -530,6 +547,7 @@ double log_statement_sample_rate = 1.0;
double log_xact_sample_rate = 0;
char *backtrace_functions;
bool backtrace_on_internal_error = false;
+int backtrace_functions_min_level = ERROR;
int temp_file_limit = -1;
@@ -4689,6 +4707,17 @@ struct config_enum ConfigureNamesEnum[] =
NULL, NULL, NULL
},
+ {
+ {"backtrace_functions_min_level", PGC_SUSET, DEVELOPER_OPTIONS,
+ gettext_noop("Sets the message levels that create backtraces when backtrace_functions is configured"),
+ NULL,
+ GUC_NOT_IN_SAMPLE
+ },
+ &backtrace_functions_min_level,
+ ERROR, backtrace_functions_level_options,
+ NULL, NULL, NULL
+ },
+
{
{"bytea_output", PGC_USERSET, CLIENT_CONN_STATEMENT,
gettext_noop("Sets the output format for bytea."),
diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h
index 471d53da8f0..69d5cb7a125 100644
--- a/src/include/utils/guc.h
+++ b/src/include/utils/guc.h
@@ -267,6 +267,7 @@ extern PGDLLIMPORT double log_statement_sample_rate;
extern PGDLLIMPORT double log_xact_sample_rate;
extern PGDLLIMPORT char *backtrace_functions;
extern PGDLLIMPORT bool backtrace_on_internal_error;
+extern PGDLLIMPORT int backtrace_functions_min_level;
extern PGDLLIMPORT int temp_file_limit;
base-commit: 53c2a97a92665be6bd7d70bd62ae6158fe4db96e
--
2.34.1
v4-0002-Add-wildcard-support-to-backtrace_functions-GUC.patchapplication/octet-stream; name=v4-0002-Add-wildcard-support-to-backtrace_functions-GUC.patchDownload
From 5ab507155a1cb60e490209d28a092fc2d7c0f6be Mon Sep 17 00:00:00 2001
From: Jelte Fennema-Nio <jelte.fennema@microsoft.com>
Date: Wed, 20 Dec 2023 11:41:18 +0100
Subject: [PATCH v4 2/2] Add wildcard support to backtrace_functions GUC
With this change setting backtrace_functions to '*' will start logging
backtraces for all errors (or more precisely all logs).
---
doc/src/sgml/config.sgml | 5 +++++
src/backend/utils/error/elog.c | 8 +++++---
2 files changed, 10 insertions(+), 3 deletions(-)
diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
index bc066284334..2a6d015d6d4 100644
--- a/doc/src/sgml/config.sgml
+++ b/doc/src/sgml/config.sgml
@@ -11275,6 +11275,11 @@ dynamic_library_path = 'C:\tools\postgresql;H:\my_project\lib;$libdir'
code.
</para>
+ <para>
+ A single <literal>*</literal> character is interpreted as a wildcard and
+ will cause all errors in the log to contain backtraces.
+ </para>
+
<para>
Backtrace support is not available on all platforms, and the quality
of the backtraces depends on compilation options.
diff --git a/src/backend/utils/error/elog.c b/src/backend/utils/error/elog.c
index 699d9d0a241..553e4785520 100644
--- a/src/backend/utils/error/elog.c
+++ b/src/backend/utils/error/elog.c
@@ -843,6 +843,8 @@ matches_backtrace_functions(const char *funcname)
if (*p == '\0') /* end of backtrace_function_list */
break;
+ if (strcmp("*", p) == 0)
+ return true;
if (strcmp(funcname, p) == 0)
return true;
p += strlen(p) + 1;
@@ -2133,14 +2135,14 @@ check_backtrace_functions(char **newval, void **extra, GucSource source)
int j;
/*
- * Allow characters that can be C identifiers and commas as separators, as
- * well as some whitespace for readability.
+ * Allow characters that can be C identifiers, commas as separators, the
+ * wildcard symbol, as well as some whitespace for readability.
*/
validlen = strspn(*newval,
"0123456789_"
"abcdefghijklmnopqrstuvwxyz"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
- ", \n\t");
+ ",* \n\t");
if (validlen != newvallen)
{
GUC_check_errdetail("Invalid character");
--
2.34.1
v4-0003-Simplify-backtrace_functions-GUC-code.patchapplication/octet-stream; name=v4-0003-Simplify-backtrace_functions-GUC-code.patchDownload
From 452c828f54312f34c6c099304007eb4b45bd6102 Mon Sep 17 00:00:00 2001
From: Bharath Rupireddy <bharath.rupireddyforpostgres@gmail.com>
Date: Fri, 8 Mar 2024 05:57:24 +0000
Subject: [PATCH v4] Simplify backtrace_functions GUC code
---
src/backend/utils/error/elog.c | 125 ++++++++++++++--------------
src/backend/utils/misc/guc_tables.c | 4 +-
src/include/utils/guc_hooks.h | 1 -
3 files changed, 63 insertions(+), 67 deletions(-)
diff --git a/src/backend/utils/error/elog.c b/src/backend/utils/error/elog.c
index d5fb5fd4f2..fa41a4c65e 100644
--- a/src/backend/utils/error/elog.c
+++ b/src/backend/utils/error/elog.c
@@ -114,9 +114,6 @@ char *Log_destination_string = NULL;
bool syslog_sequence_numbers = true;
bool syslog_split_messages = true;
-/* Processed form of backtrace_functions GUC */
-static char *backtrace_function_list;
-
#ifdef HAVE_SYSLOG
/*
@@ -831,24 +828,32 @@ set_stack_entry_location(ErrorData *edata,
static bool
matches_backtrace_functions(const char *funcname)
{
- const char *p;
+ char *rawstring;
+ List *elemlist;
+ ListCell *l;
+ bool is_parase_okay PG_USED_FOR_ASSERTS_ONLY;
- if (!backtrace_function_list || funcname == NULL || funcname[0] == '\0')
- return false;
+ /* Need a modifiable copy of string */
+ rawstring = pstrdup(backtrace_functions);
+
+ /* Parse string into list of identifiers */
+ is_parase_okay = SplitIdentifierString(rawstring, ',', &elemlist);
+ Assert(is_parase_okay);
- p = backtrace_function_list;
- for (;;)
+ foreach(l, elemlist)
{
- if (*p == '\0') /* end of backtrace_function_list */
- break;
+ char *tok = (char *) lfirst(l);
- if (strcmp("*", p) == 0)
- return true;
- if (strcmp(funcname, p) == 0)
+ if (strcmp(tok, "*") == 0 || strcmp(tok, funcname) == 0)
+ {
+ pfree(rawstring);
+ list_free(elemlist);
return true;
- p += strlen(p) + 1;
+ }
}
+ pfree(rawstring);
+ list_free(elemlist);
return false;
}
@@ -2127,68 +2132,60 @@ DebugFileOpen(void)
bool
check_backtrace_functions(char **newval, void **extra, GucSource source)
{
- int newvallen = strlen(*newval);
- char *someval;
- int validlen;
- int i;
- int j;
+ char *rawstring;
+ List *elemlist;
+ ListCell *l;
- /*
- * Allow characters that can be C identifiers, commas as separators, the
- * wildcard symbol, as well as some whitespace for readability.
- */
- validlen = strspn(*newval,
- "0123456789_"
- "abcdefghijklmnopqrstuvwxyz"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
- ",* \n\t");
- if (validlen != newvallen)
+ /* Need a modifiable copy of string */
+ rawstring = pstrdup(*newval);
+
+ /* Parse string into list of identifiers */
+ if (!SplitIdentifierString(rawstring, ',', &elemlist))
{
- GUC_check_errdetail("Invalid character");
+ /* syntax error in list */
+ GUC_check_errdetail("List syntax is invalid.");
+ pfree(rawstring);
+ list_free(elemlist);
return false;
}
- if (*newval[0] == '\0')
+ foreach(l, elemlist)
{
- *extra = NULL;
- return true;
- }
+ char *tok = (char *) lfirst(l);
+ int toklen = strlen(tok);
+ int validlen;
- /*
- * Allocate space for the output and create the copy. We could discount
- * whitespace chars to save some memory, but it doesn't seem worth the
- * trouble.
- */
- someval = guc_malloc(ERROR, newvallen + 1 + 1);
- for (i = 0, j = 0; i < newvallen; i++)
- {
- if ((*newval)[i] == ',')
- someval[j++] = '\0'; /* next item */
- else if ((*newval)[i] == ' ' ||
- (*newval)[i] == '\n' ||
- (*newval)[i] == '\t')
- ; /* ignore these */
- else
- someval[j++] = (*newval)[i]; /* copy anything else */
- }
+ if (strcmp(tok, "*") == 0)
+ {
+ pfree(rawstring);
+ list_free(elemlist);
+ return true;
+ }
+
+ /*
+ * Allow characters that can be C identifiers, commas as separators,
+ * the wildcard symbol, as well as some whitespace for readability.
+ */
+ validlen = strspn(tok,
+ "0123456789_"
+ "abcdefghijklmnopqrstuvwxyz"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ ", \n\t");
- /* two \0s end the setting */
- someval[j] = '\0';
- someval[j + 1] = '\0';
+ if (validlen != toklen)
+ {
+ GUC_check_errdetail("Invalid character");
+ pfree(rawstring);
+ list_free(elemlist);
+ return false;
+ }
+ }
- *extra = someval;
+ pfree(rawstring);
+ list_free(elemlist);
return true;
}
-/*
- * GUC assign_hook for backtrace_functions
- */
-void
-assign_backtrace_functions(const char *newval, void *extra)
-{
- backtrace_function_list = (char *) extra;
-}
-
/*
* GUC check_hook for log_destination
*/
diff --git a/src/backend/utils/misc/guc_tables.c b/src/backend/utils/misc/guc_tables.c
index ff799a296a..e4ae8e1573 100644
--- a/src/backend/utils/misc/guc_tables.c
+++ b/src/backend/utils/misc/guc_tables.c
@@ -4670,11 +4670,11 @@ struct config_string ConfigureNamesString[] =
{"backtrace_functions", PGC_SUSET, DEVELOPER_OPTIONS,
gettext_noop("Log backtrace for errors in these functions."),
NULL,
- GUC_NOT_IN_SAMPLE
+ GUC_LIST_INPUT | GUC_NOT_IN_SAMPLE
},
&backtrace_functions,
"",
- check_backtrace_functions, assign_backtrace_functions, NULL
+ check_backtrace_functions, NULL, NULL
},
{
diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h
index d64dc5fcdb..b9b801216a 100644
--- a/src/include/utils/guc_hooks.h
+++ b/src/include/utils/guc_hooks.h
@@ -37,7 +37,6 @@ extern bool check_vacuum_buffer_usage_limit(int *newval, void **extra,
GucSource source);
extern bool check_backtrace_functions(char **newval, void **extra,
GucSource source);
-extern void assign_backtrace_functions(const char *newval, void *extra);
extern bool check_bonjour(bool *newval, void **extra, GucSource source);
extern bool check_canonical_path(char **newval, void **extra, GucSource source);
extern void assign_checkpoint_completion_target(double newval, void *extra);
--
2.34.1
On 2024-Mar-08, Bharath Rupireddy wrote:
This works only if '* 'is specified as the only one character in
backtrace_functions = '*', right? If yes, what if someone sets
backtrace_functions = 'foo, bar, *, baz'?
It throws an error, as expected. This is a useless waste of resources:
checking for "foo" and "bar" is pointless, since the * is going to give
a positive match anyway. And the "baz" is a waste of memory which is
never going to be checked.
--
Álvaro Herrera Breisgau, Deutschland — https://www.EnterpriseDB.com/
"I love the Postgres community. It's all about doing things _properly_. :-)"
(David Garamond)
On Fri, 8 Mar 2024 at 10:59, Alvaro Herrera <alvherre@alvh.no-ip.org> wrote:
On 2024-Mar-08, Bharath Rupireddy wrote:
This works only if '* 'is specified as the only one character in
backtrace_functions = '*', right? If yes, what if someone sets
backtrace_functions = 'foo, bar, *, baz'?It throws an error, as expected. This is a useless waste of resources:
checking for "foo" and "bar" is pointless, since the * is going to give
a positive match anyway. And the "baz" is a waste of memory which is
never going to be checked.
Makes sense. Attached is a new patchset that implements it that way.
I've not included Bharath his 0003 patch, since it's a much bigger
change than the others, and thus might need some more discussion.
Attachments:
v5-0002-Add-wildcard-support-to-backtrace_functions-GUC.patchapplication/octet-stream; name=v5-0002-Add-wildcard-support-to-backtrace_functions-GUC.patchDownload
From 317975f40e8747b76108937f4ecbdd0bba3121a7 Mon Sep 17 00:00:00 2001
From: Jelte Fennema-Nio <jelte.fennema@microsoft.com>
Date: Wed, 20 Dec 2023 11:41:18 +0100
Subject: [PATCH v5 2/2] Add wildcard support to backtrace_functions GUC
With this change setting backtrace_functions to '*' will start logging
backtraces for all errors (or more precisely all logs).
---
doc/src/sgml/config.sgml | 6 ++++++
src/backend/utils/error/elog.c | 9 +++++++++
2 files changed, 15 insertions(+)
diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
index 254b75382f8..cb195ffb553 100644
--- a/doc/src/sgml/config.sgml
+++ b/doc/src/sgml/config.sgml
@@ -11314,6 +11314,12 @@ dynamic_library_path = 'C:\tools\postgresql;H:\my_project\lib;$libdir'
code.
</para>
+ <para>
+ A single <literal>*</literal> character can be used instead of a list
+ of C functions. This <literal>*</literal> is interpreted as a wildcard
+ and will cause all errors in the log to contain backtraces.
+ </para>
+
<para>
Backtrace support is not available on all platforms, and the quality
of the backtraces depends on compilation options.
diff --git a/src/backend/utils/error/elog.c b/src/backend/utils/error/elog.c
index b214747500c..ca621ea3fff 100644
--- a/src/backend/utils/error/elog.c
+++ b/src/backend/utils/error/elog.c
@@ -836,6 +836,9 @@ matches_backtrace_functions(const char *funcname)
if (!backtrace_function_list || funcname == NULL || funcname[0] == '\0')
return false;
+ if (strcmp(backtrace_function_list, "*") == 0)
+ return true;
+
p = backtrace_function_list;
for (;;)
{
@@ -2131,6 +2134,12 @@ check_backtrace_functions(char **newval, void **extra, GucSource source)
int i;
int j;
+ if (strcmp(*newval, "*") == 0)
+ {
+ *extra = guc_strdup(ERROR, "*");
+ return true;
+ }
+
/*
* Allow characters that can be C identifiers and commas as separators, as
* well as some whitespace for readability.
--
2.34.1
v5-0001-Add-backtrace_functions_min_level.patchapplication/octet-stream; name=v5-0001-Add-backtrace_functions_min_level.patchDownload
From 1c89dd0312c6edb9bb663030522794c0b532582d Mon Sep 17 00:00:00 2001
From: Jelte Fennema-Nio <jelte.fennema@microsoft.com>
Date: Tue, 27 Feb 2024 17:31:24 +0100
Subject: [PATCH v5 1/2] Add backtrace_functions_min_level
Before this change a stacktrace would be attached to all logs messages
in a function that matched backtrace_functions. But in most cases people
only care about the stacktraces for messages with an ERROR level. This
changes that default to only log stacktraces for ERROR messages but
keeps the option open of logging stacktraces for different log levels
too by having users configure the new backtrace_functions_min_level GUC.
---
doc/src/sgml/config.sgml | 46 ++++++++++++++++++++++++++---
src/backend/utils/error/elog.c | 1 +
src/backend/utils/misc/guc_tables.c | 29 ++++++++++++++++++
src/include/utils/guc.h | 1 +
4 files changed, 73 insertions(+), 4 deletions(-)
diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
index 65a6e6c4086..254b75382f8 100644
--- a/doc/src/sgml/config.sgml
+++ b/doc/src/sgml/config.sgml
@@ -11306,10 +11306,12 @@ dynamic_library_path = 'C:\tools\postgresql;H:\my_project\lib;$libdir'
<listitem>
<para>
This parameter contains a comma-separated list of C function names.
- If an error is raised and the name of the internal C function where
- the error happens matches a value in the list, then a backtrace is
- written to the server log together with the error message. This can
- be used to debug specific areas of the source code.
+ If a log entry is raised with a level equal to or higher than
+ <xref linkend="guc-backtrace-functions-min-level"/> and the name of the
+ internal C function where the error happens matches a value in the
+ list, then a backtrace is written to the server log together with the
+ error message. This can be used to debug specific areas of the source
+ code.
</para>
<para>
@@ -11324,6 +11326,42 @@ dynamic_library_path = 'C:\tools\postgresql;H:\my_project\lib;$libdir'
</listitem>
</varlistentry>
+ <varlistentry id="guc-backtrace-functions-min-level" xreflabel="backtrace_functions_min_level">
+ <term><varname>backtrace_functions_min_level</varname> (<type>string</type>)
+ <indexterm>
+ <primary><varname>backtrace_functions_min_level</varname> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Controls which <link linkend="runtime-config-severity-levels">message
+ levels</link> cause stack traces to be written to the log, for messages
+ raised from C functions that match the configured
+ <xref linkend="guc-backtrace-functions"/>.
+ Valid values are <literal>DEBUG5</literal>, <literal>DEBUG4</literal>,
+ <literal>DEBUG3</literal>, <literal>DEBUG2</literal>, <literal>DEBUG1</literal>,
+ <literal>LOG</literal>, <literal>INFO</literal>, <literal>NOTICE</literal>,
+ <literal>WARNING</literal>, <literal>ERROR</literal>, <literal>FATAL</literal>,
+ and <literal>PANIC</literal>. Each level includes all the levels that
+ follow it. The later the level, the fewer messages result in a
+ backtrace. The default is <literal>ERROR</literal>. Note that
+ <literal>LOG</literal> has a different rank here than in
+ <xref linkend="guc-log-min-messages"/>.
+ </para>
+
+ <para>
+ Backtrace support is not available on all platforms, and the quality
+ of the backtraces depends on compilation options.
+ </para>
+
+ <para>
+ Only superusers and users with the appropriate <literal>SET</literal>
+ privilege can change this setting.
+ </para>
+ </listitem>
+ </varlistentry>
+
+
<varlistentry id="guc-backtrace-on-internal-error" xreflabel="backtrace_on_internal_error">
<term><varname>backtrace_on_internal_error</varname> (<type>boolean</type>)
<indexterm>
diff --git a/src/backend/utils/error/elog.c b/src/backend/utils/error/elog.c
index ed8aa5c9fa4..b214747500c 100644
--- a/src/backend/utils/error/elog.c
+++ b/src/backend/utils/error/elog.c
@@ -499,6 +499,7 @@ errfinish(const char *filename, int lineno, const char *funcname)
if (!edata->backtrace &&
((edata->funcname &&
backtrace_functions &&
+ edata->elevel >= backtrace_functions_min_level &&
matches_backtrace_functions(edata->funcname)) ||
(edata->sqlerrcode == ERRCODE_INTERNAL_ERROR &&
backtrace_on_internal_error)))
diff --git a/src/backend/utils/misc/guc_tables.c b/src/backend/utils/misc/guc_tables.c
index d77214795de..ff799a296a8 100644
--- a/src/backend/utils/misc/guc_tables.c
+++ b/src/backend/utils/misc/guc_tables.c
@@ -162,6 +162,23 @@ static const struct config_enum_entry server_message_level_options[] = {
{NULL, 0, false}
};
+static const struct config_enum_entry backtrace_functions_level_options[] = {
+ {"debug5", DEBUG5, false},
+ {"debug4", DEBUG4, false},
+ {"debug3", DEBUG3, false},
+ {"debug2", DEBUG2, false},
+ {"debug1", DEBUG1, false},
+ {"debug", DEBUG2, true},
+ {"log", LOG, false},
+ {"info", INFO, true},
+ {"notice", NOTICE, false},
+ {"warning", WARNING, false},
+ {"error", ERROR, false},
+ {"fatal", FATAL, false},
+ {"panic", PANIC, false},
+ {NULL, 0, false}
+};
+
static const struct config_enum_entry intervalstyle_options[] = {
{"postgres", INTSTYLE_POSTGRES, false},
{"postgres_verbose", INTSTYLE_POSTGRES_VERBOSE, false},
@@ -530,6 +547,7 @@ double log_statement_sample_rate = 1.0;
double log_xact_sample_rate = 0;
char *backtrace_functions;
bool backtrace_on_internal_error = false;
+int backtrace_functions_min_level = ERROR;
int temp_file_limit = -1;
@@ -4703,6 +4721,17 @@ struct config_enum ConfigureNamesEnum[] =
NULL, NULL, NULL
},
+ {
+ {"backtrace_functions_min_level", PGC_SUSET, DEVELOPER_OPTIONS,
+ gettext_noop("Sets the message levels that create backtraces when backtrace_functions is configured"),
+ NULL,
+ GUC_NOT_IN_SAMPLE
+ },
+ &backtrace_functions_min_level,
+ ERROR, backtrace_functions_level_options,
+ NULL, NULL, NULL
+ },
+
{
{"bytea_output", PGC_USERSET, CLIENT_CONN_STATEMENT,
gettext_noop("Sets the output format for bytea."),
diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h
index 3712aba09b0..66dbf637c68 100644
--- a/src/include/utils/guc.h
+++ b/src/include/utils/guc.h
@@ -267,6 +267,7 @@ extern PGDLLIMPORT double log_statement_sample_rate;
extern PGDLLIMPORT double log_xact_sample_rate;
extern PGDLLIMPORT char *backtrace_functions;
extern PGDLLIMPORT bool backtrace_on_internal_error;
+extern PGDLLIMPORT int backtrace_functions_min_level;
extern PGDLLIMPORT int temp_file_limit;
base-commit: 6d9751fa8fd40c988541c9c72ac7a2095ba73c19
--
2.34.1
On 8 Mar 2024, at 12:25, Jelte Fennema-Nio <me@jeltef.nl> wrote:
On Fri, 8 Mar 2024 at 10:59, Alvaro Herrera <alvherre@alvh.no-ip.org> wrote:
On 2024-Mar-08, Bharath Rupireddy wrote:
This works only if '* 'is specified as the only one character in
backtrace_functions = '*', right? If yes, what if someone sets
backtrace_functions = 'foo, bar, *, baz'?It throws an error, as expected. This is a useless waste of resources:
checking for "foo" and "bar" is pointless, since the * is going to give
a positive match anyway. And the "baz" is a waste of memory which is
never going to be checked.Makes sense. Attached is a new patchset that implements it that way.
This version address the concerns raised by Alvaro, and even simplifies the
code over earlier revisions. My documentation comments from upthread still
stands, but other than those this version LGTM.
I've not included Bharath his 0003 patch, since it's a much bigger
change than the others, and thus might need some more discussion.
Agreed.
--
Daniel Gustafsson
On Fri, Mar 8, 2024 at 7:12 PM Daniel Gustafsson <daniel@yesql.se> wrote:
On 8 Mar 2024, at 12:25, Jelte Fennema-Nio <me@jeltef.nl> wrote:
On Fri, 8 Mar 2024 at 10:59, Alvaro Herrera <alvherre@alvh.no-ip.org> wrote:
On 2024-Mar-08, Bharath Rupireddy wrote:
This works only if '* 'is specified as the only one character in
backtrace_functions = '*', right? If yes, what if someone sets
backtrace_functions = 'foo, bar, *, baz'?It throws an error, as expected. This is a useless waste of resources:
checking for "foo" and "bar" is pointless, since the * is going to give
a positive match anyway. And the "baz" is a waste of memory which is
never going to be checked.Makes sense. Attached is a new patchset that implements it that way.
This version address the concerns raised by Alvaro, and even simplifies the
code over earlier revisions. My documentation comments from upthread still
stands, but other than those this version LGTM.
So, to get backtraces of all functions at
backtrace_functions_min_level level, one has to specify
backtrace_functions = '*'; combining it with function names is not
allowed. This looks cleaner.
postgres=# ALTER SYSTEM SET backtrace_functions = '*, pg_create_restore_point';
ERROR: invalid value for parameter "backtrace_functions": "*,
pg_create_restore_point"
DETAIL: Invalid character
I have one comment on 0002, otherwise all looks good.
+ <para>
+ A single <literal>*</literal> character can be used instead of a list
+ of C functions. This <literal>*</literal> is interpreted as a wildcard
+ and will cause all errors in the log to contain backtraces.
+ </para>
It's not always the ERRORs for which backtraces get logged, it really
depends on the new GUC backtrace_functions_min_level. If my
understanding is right, can we specify that in the above note?
I've not included Bharath his 0003 patch, since it's a much bigger
change than the others, and thus might need some more discussion.
+1. I'll see if I can start a new thread for this.
--
Bharath Rupireddy
PostgreSQL Contributors Team
RDS Open Source Databases
Amazon Web Services: https://aws.amazon.com
On 8 Mar 2024, at 15:01, Bharath Rupireddy <bharath.rupireddyforpostgres@gmail.com> wrote:
So, to get backtraces of all functions at
backtrace_functions_min_level level, one has to specify
backtrace_functions = '*'; combining it with function names is not
allowed. This looks cleaner.postgres=# ALTER SYSTEM SET backtrace_functions = '*, pg_create_restore_point';
ERROR: invalid value for parameter "backtrace_functions": "*,
pg_create_restore_point"
DETAIL: Invalid character
If we want to be extra helpful here we could add something like the below to
give an errhint when a wildcard was found. Also, the errdetail should read
like a full sentence so it should be slightly expanded anyways.
diff --git a/src/backend/utils/error/elog.c b/src/backend/utils/error/elog.c
index ca621ea3ff..7bc655ecd2 100644
--- a/src/backend/utils/error/elog.c
+++ b/src/backend/utils/error/elog.c
@@ -2151,7 +2151,9 @@ check_backtrace_functions(char **newval, void **extra, GucSource source)
", \n\t");
if (validlen != newvallen)
{
- GUC_check_errdetail("Invalid character");
+ GUC_check_errdetail("Invalid character in function name.");
+ if ((*newval)[validlen] == '*')
+ GUC_check_errhint("For wildcard matching, use a single \"*\" without any other function names.");
return false;
}
--
Daniel Gustafsson
On 08.03.24 12:25, Jelte Fennema-Nio wrote:
On Fri, 8 Mar 2024 at 10:59, Alvaro Herrera <alvherre@alvh.no-ip.org> wrote:
On 2024-Mar-08, Bharath Rupireddy wrote:
This works only if '* 'is specified as the only one character in
backtrace_functions = '*', right? If yes, what if someone sets
backtrace_functions = 'foo, bar, *, baz'?It throws an error, as expected. This is a useless waste of resources:
checking for "foo" and "bar" is pointless, since the * is going to give
a positive match anyway. And the "baz" is a waste of memory which is
never going to be checked.Makes sense. Attached is a new patchset that implements it that way.
I've not included Bharath his 0003 patch, since it's a much bigger
change than the others, and thus might need some more discussion.
What is the relationship of these changes with the recently added
backtrace_on_internal_error? We had similar discussions there, I feel
like we are doing similar things here but slightly differently. Like,
shouldn't backtrace_functions_min_level also affect
backtrace_on_internal_error? Don't you really just want
backtrace_on_any_error? You are sneaking that in through the backdoor
via backtrace_functions. Can we somehow combine all these use cases
more elegantly? backtrace_on_error = {all|internal|none}?
Btw., your code/documentation sometimes writes "stack trace". Let's
stick to backtrace for consistency.
On Fri, 8 Mar 2024 at 14:42, Daniel Gustafsson <daniel@yesql.se> wrote:
My documentation comments from upthread still
stands, but other than those this version LGTM.
Ah yeah, I forgot about those. Fixed now.
Attachments:
v6-0001-Add-backtrace_functions_min_level.patchapplication/octet-stream; name=v6-0001-Add-backtrace_functions_min_level.patchDownload
From 4edd05bb9c611989b832e6a01552b28b8b18486c Mon Sep 17 00:00:00 2001
From: Jelte Fennema-Nio <jelte.fennema@microsoft.com>
Date: Tue, 27 Feb 2024 17:31:24 +0100
Subject: [PATCH v6 1/2] Add backtrace_functions_min_level
Before this change a backtrace would be attached to all logs messages
in a function that matched backtrace_functions. But in most cases people
only care about the backtraces for messages with an ERROR level. This
changes that default to only log backtraces for ERROR messages but
keeps the option open of logging backtraces for different log levels
too by having users configure the new backtrace_functions_min_level GUC.
---
doc/src/sgml/config.sgml | 41 ++++++++++++++++++++++++++---
src/backend/utils/error/elog.c | 1 +
src/backend/utils/misc/guc_tables.c | 29 ++++++++++++++++++++
src/include/utils/guc.h | 1 +
4 files changed, 68 insertions(+), 4 deletions(-)
diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
index 65a6e6c4086..c76e97d2d33 100644
--- a/doc/src/sgml/config.sgml
+++ b/doc/src/sgml/config.sgml
@@ -11306,10 +11306,12 @@ dynamic_library_path = 'C:\tools\postgresql;H:\my_project\lib;$libdir'
<listitem>
<para>
This parameter contains a comma-separated list of C function names.
- If an error is raised and the name of the internal C function where
- the error happens matches a value in the list, then a backtrace is
- written to the server log together with the error message. This can
- be used to debug specific areas of the source code.
+ If a log entry is raised with a level equal to or higher than
+ <xref linkend="guc-backtrace-functions-min-level"/> and the name of the
+ internal C function where the error happens matches a value in the
+ list, then a backtrace is written to the server log together with the
+ error message. This can be used to debug specific areas of the source
+ code.
</para>
<para>
@@ -11324,6 +11326,37 @@ dynamic_library_path = 'C:\tools\postgresql;H:\my_project\lib;$libdir'
</listitem>
</varlistentry>
+ <varlistentry id="guc-backtrace-functions-min-level" xreflabel="backtrace_functions_min_level">
+ <term><varname>backtrace_functions_min_level</varname> (<type>string</type>)
+ <indexterm>
+ <primary><varname>backtrace_functions_min_level</varname> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Controls which <link linkend="runtime-config-severity-levels">message
+ levels</link> cause backtraces to be written to the log, for messages
+ raised from C functions that match the configured
+ <xref linkend="guc-backtrace-functions"/>.
+ Valid values are <literal>DEBUG5</literal>, <literal>DEBUG4</literal>,
+ <literal>DEBUG3</literal>, <literal>DEBUG2</literal>, <literal>DEBUG1</literal>,
+ <literal>LOG</literal>, <literal>INFO</literal>, <literal>NOTICE</literal>,
+ <literal>WARNING</literal>, <literal>ERROR</literal>, <literal>FATAL</literal>,
+ and <literal>PANIC</literal>. Each level includes all the levels that
+ follow it. The later the level, the fewer messages result in a
+ backtrace. The default is <literal>ERROR</literal>. Note that
+ <literal>LOG</literal> has a different rank here than in
+ <xref linkend="guc-log-min-messages"/>.
+ </para>
+
+ <para>
+ Only superusers and users with the appropriate <literal>SET</literal>
+ privilege can change this setting.
+ </para>
+ </listitem>
+ </varlistentry>
+
+
<varlistentry id="guc-backtrace-on-internal-error" xreflabel="backtrace_on_internal_error">
<term><varname>backtrace_on_internal_error</varname> (<type>boolean</type>)
<indexterm>
diff --git a/src/backend/utils/error/elog.c b/src/backend/utils/error/elog.c
index ed8aa5c9fa4..b214747500c 100644
--- a/src/backend/utils/error/elog.c
+++ b/src/backend/utils/error/elog.c
@@ -499,6 +499,7 @@ errfinish(const char *filename, int lineno, const char *funcname)
if (!edata->backtrace &&
((edata->funcname &&
backtrace_functions &&
+ edata->elevel >= backtrace_functions_min_level &&
matches_backtrace_functions(edata->funcname)) ||
(edata->sqlerrcode == ERRCODE_INTERNAL_ERROR &&
backtrace_on_internal_error)))
diff --git a/src/backend/utils/misc/guc_tables.c b/src/backend/utils/misc/guc_tables.c
index d77214795de..aa81d763b16 100644
--- a/src/backend/utils/misc/guc_tables.c
+++ b/src/backend/utils/misc/guc_tables.c
@@ -162,6 +162,23 @@ static const struct config_enum_entry server_message_level_options[] = {
{NULL, 0, false}
};
+static const struct config_enum_entry backtrace_functions_level_options[] = {
+ {"debug5", DEBUG5, false},
+ {"debug4", DEBUG4, false},
+ {"debug3", DEBUG3, false},
+ {"debug2", DEBUG2, false},
+ {"debug1", DEBUG1, false},
+ {"debug", DEBUG2, true},
+ {"log", LOG, false},
+ {"info", INFO, true},
+ {"notice", NOTICE, false},
+ {"warning", WARNING, false},
+ {"error", ERROR, false},
+ {"fatal", FATAL, false},
+ {"panic", PANIC, false},
+ {NULL, 0, false}
+};
+
static const struct config_enum_entry intervalstyle_options[] = {
{"postgres", INTSTYLE_POSTGRES, false},
{"postgres_verbose", INTSTYLE_POSTGRES_VERBOSE, false},
@@ -530,6 +547,7 @@ double log_statement_sample_rate = 1.0;
double log_xact_sample_rate = 0;
char *backtrace_functions;
bool backtrace_on_internal_error = false;
+int backtrace_functions_min_level = ERROR;
int temp_file_limit = -1;
@@ -4703,6 +4721,17 @@ struct config_enum ConfigureNamesEnum[] =
NULL, NULL, NULL
},
+ {
+ {"backtrace_functions_min_level", PGC_SUSET, DEVELOPER_OPTIONS,
+ gettext_noop("Sets the message levels that create backtraces when backtrace_functions is configured."),
+ gettext_noop("Each level includes all the levels that follow it. The later"
+ " the level, the fewer backtraces are created.")
+ },
+ &backtrace_functions_min_level,
+ ERROR, backtrace_functions_level_options,
+ NULL, NULL, NULL
+ },
+
{
{"bytea_output", PGC_USERSET, CLIENT_CONN_STATEMENT,
gettext_noop("Sets the output format for bytea."),
diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h
index 3712aba09b0..66dbf637c68 100644
--- a/src/include/utils/guc.h
+++ b/src/include/utils/guc.h
@@ -267,6 +267,7 @@ extern PGDLLIMPORT double log_statement_sample_rate;
extern PGDLLIMPORT double log_xact_sample_rate;
extern PGDLLIMPORT char *backtrace_functions;
extern PGDLLIMPORT bool backtrace_on_internal_error;
+extern PGDLLIMPORT int backtrace_functions_min_level;
extern PGDLLIMPORT int temp_file_limit;
base-commit: 6d9751fa8fd40c988541c9c72ac7a2095ba73c19
--
2.34.1
v6-0002-Add-wildcard-support-to-backtrace_functions-GUC.patchapplication/octet-stream; name=v6-0002-Add-wildcard-support-to-backtrace_functions-GUC.patchDownload
From 2dcea42f5583e773864fe7f84c0c218cdea68d76 Mon Sep 17 00:00:00 2001
From: Jelte Fennema-Nio <jelte.fennema@microsoft.com>
Date: Wed, 20 Dec 2023 11:41:18 +0100
Subject: [PATCH v6 2/2] Add wildcard support to backtrace_functions GUC
With this change setting backtrace_functions to '*' will start logging
backtraces for all errors (or more precisely all logs).
---
doc/src/sgml/config.sgml | 8 ++++++++
src/backend/utils/error/elog.c | 9 +++++++++
2 files changed, 17 insertions(+)
diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
index c76e97d2d33..1fddc0fce04 100644
--- a/doc/src/sgml/config.sgml
+++ b/doc/src/sgml/config.sgml
@@ -11314,6 +11314,14 @@ dynamic_library_path = 'C:\tools\postgresql;H:\my_project\lib;$libdir'
code.
</para>
+ <para>
+ A single <literal>*</literal> character can be used instead of a list
+ of C functions. This <literal>*</literal> is interpreted as a wildcard
+ and will cause all log entries equal to or higher than
+ <xref linkend="guc-backtrace-functions-min-level"/> in the log to
+ contain backtraces.
+ </para>
+
<para>
Backtrace support is not available on all platforms, and the quality
of the backtraces depends on compilation options.
diff --git a/src/backend/utils/error/elog.c b/src/backend/utils/error/elog.c
index b214747500c..ca621ea3fff 100644
--- a/src/backend/utils/error/elog.c
+++ b/src/backend/utils/error/elog.c
@@ -836,6 +836,9 @@ matches_backtrace_functions(const char *funcname)
if (!backtrace_function_list || funcname == NULL || funcname[0] == '\0')
return false;
+ if (strcmp(backtrace_function_list, "*") == 0)
+ return true;
+
p = backtrace_function_list;
for (;;)
{
@@ -2131,6 +2134,12 @@ check_backtrace_functions(char **newval, void **extra, GucSource source)
int i;
int j;
+ if (strcmp(*newval, "*") == 0)
+ {
+ *extra = guc_strdup(ERROR, "*");
+ return true;
+ }
+
/*
* Allow characters that can be C identifiers and commas as separators, as
* well as some whitespace for readability.
--
2.34.1
On Fri, 8 Mar 2024 at 15:51, Peter Eisentraut <peter@eisentraut.org> wrote:
What is the relationship of these changes with the recently added
backtrace_on_internal_error?
I think that's a reasonable question. And the follow up ones too.
I think it all depends on how close we consider
backtrace_on_internal_error and backtrace_functions. While they
obviously have similar functionality, I feel like
backtrace_on_internal_error is probably a function that we'd want to
turn on by default in the future. While backtrace_functions seems like
it's mostly useful for developers. (i.e. the current grouping of
backtrace_on_internal_error under DEVELOPER_OPTIONS seems wrong to me)
shouldn't backtrace_functions_min_level also affect
backtrace_on_internal_error?
I guess that depends on the default behaviour that we want. Would we
want warnings with ERRCODE_INTERNAL_ERROR to be backtraced by default
or not. There is at least one example of such a warning in the
codebase:
ereport(WARNING,
errcode(ERRCODE_INTERNAL_ERROR),
errmsg_internal("could not parse XML declaration in stored value"),
errdetail_for_xml_code(res_code));
Btw., your code/documentation sometimes writes "stack trace". Let's
stick to backtrace for consistency.
Fixed that in the latest patset in the email I sent right before this one.
On Fri, Mar 8, 2024 at 9:25 PM Jelte Fennema-Nio <me@jeltef.nl> wrote:
On Fri, 8 Mar 2024 at 15:51, Peter Eisentraut <peter@eisentraut.org> wrote:
What is the relationship of these changes with the recently added
backtrace_on_internal_error?I think that's a reasonable question. And the follow up ones too.
I think it all depends on how close we consider
backtrace_on_internal_error and backtrace_functions. While they
obviously have similar functionality, I feel like
backtrace_on_internal_error is probably a function that we'd want to
turn on by default in the future.
Hm, we may not want backtrace_on_internal_error to be on by default.
AFAICS, all ERRCODE_INTERNAL_ERROR are identifiable with the error
message, so it's sort of easy for one to track down the cause of it
without actually needing to log backtrace by default.
On Fri, Mar 8, 2024 at 8:21 PM Peter Eisentraut <peter@eisentraut.org> wrote:
What is the relationship of these changes with the recently added
backtrace_on_internal_error? We had similar discussions there, I feel
like we are doing similar things here but slightly differently. Like,
shouldn't backtrace_functions_min_level also affect
backtrace_on_internal_error? Don't you really just want
backtrace_on_any_error? You are sneaking that in through the backdoor
via backtrace_functions. Can we somehow combine all these use cases
more elegantly? backtrace_on_error = {all|internal|none}?
I see a merit in Peter's point. I like the idea of
backtrace_functions_min_level controlling backtrace_on_internal_error
too. Less GUCs for similar functionality is always a good idea IMHO.
Here's what I think:
1. Rename the new GUC backtrace_functions_min_level to backtrace_min_level.
2. Add 'internal' to backtrace_min_level_options enum
+static const struct config_enum_entry backtrace_functions_level_options[] = {
+ {"internal", INTERNAL, false},
+ {"debug5", DEBUG5, false},
+ {"debug4", DEBUG4, false},
3. Remove backtrace_on_internal_error GUC which is now effectively
covered by backtrace_min_level = 'internal';
Does anyone see a problem with it?
--
Bharath Rupireddy
PostgreSQL Contributors Team
RDS Open Source Databases
Amazon Web Services: https://aws.amazon.com
On Fri, 8 Mar 2024 at 17:17, Bharath Rupireddy
<bharath.rupireddyforpostgres@gmail.com> wrote:
Hm, we may not want backtrace_on_internal_error to be on by default.
AFAICS, all ERRCODE_INTERNAL_ERROR are identifiable with the error
message, so it's sort of easy for one to track down the cause of it
without actually needing to log backtrace by default.
While maybe all messages uniquely identify the exact error, these
errors usually originate somewhere deep down the call stack in a
function that is called from many other places. Having the full stack
trace can thus greatly help us to find what caused this specific error
to occur. I think that would be quite useful to enable by default, if
only because it would make many bug reports much more actionable.
1. Rename the new GUC backtrace_functions_min_level to backtrace_min_level. 2. Add 'internal' to backtrace_min_level_options enum +static const struct config_enum_entry backtrace_functions_level_options[] = { + {"internal", INTERNAL, false}, + {"debug5", DEBUG5, false}, + {"debug4", DEBUG4, false}, 3. Remove backtrace_on_internal_error GUC which is now effectively covered by backtrace_min_level = 'internal';Does anyone see a problem with it?
Honestly, it seems a bit confusing to me to add INTERNAL as a level,
since it's an error code not log level. Also merging it in this way,
brings up certain questions:
1. How do you get the current backtrace_on_internal_error=true
behaviour? Would you need to set both backtrace_functions='*' and
backtrace_min_level=INTERNAL?
2. What is the default value for backtrace_min_level?
3. You still wouldn't be able to limit INTERNAL errors to FATAL level
I personally think having three GUCs in this patchset make sense,
especially since I think it would be good to turn
backtrace_on_internal_error on by default. The only additional change
that I think might be worth making is to make
backtrace_on_internal_error take a level argument, so that you could
configure postgres to only add stack traces to FATAL internal errors.
(attached is a patch that should fix the CI issue by adding
GUC_NOT_IN_SAMPLE backtrace_functions_min_level)
Attachments:
v7-0002-Add-wildcard-support-to-backtrace_functions-GUC.patchapplication/octet-stream; name=v7-0002-Add-wildcard-support-to-backtrace_functions-GUC.patchDownload
From b2ffab2a64243690e4031eb873fd233569fb83ba Mon Sep 17 00:00:00 2001
From: Jelte Fennema-Nio <jelte.fennema@microsoft.com>
Date: Wed, 20 Dec 2023 11:41:18 +0100
Subject: [PATCH v7 2/2] Add wildcard support to backtrace_functions GUC
With this change setting backtrace_functions to '*' will start logging
backtraces for all errors (or more precisely all logs).
---
doc/src/sgml/config.sgml | 8 ++++++++
src/backend/utils/error/elog.c | 9 +++++++++
2 files changed, 17 insertions(+)
diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
index c76e97d2d33..1fddc0fce04 100644
--- a/doc/src/sgml/config.sgml
+++ b/doc/src/sgml/config.sgml
@@ -11314,6 +11314,14 @@ dynamic_library_path = 'C:\tools\postgresql;H:\my_project\lib;$libdir'
code.
</para>
+ <para>
+ A single <literal>*</literal> character can be used instead of a list
+ of C functions. This <literal>*</literal> is interpreted as a wildcard
+ and will cause all log entries equal to or higher than
+ <xref linkend="guc-backtrace-functions-min-level"/> in the log to
+ contain backtraces.
+ </para>
+
<para>
Backtrace support is not available on all platforms, and the quality
of the backtraces depends on compilation options.
diff --git a/src/backend/utils/error/elog.c b/src/backend/utils/error/elog.c
index b214747500c..ca621ea3fff 100644
--- a/src/backend/utils/error/elog.c
+++ b/src/backend/utils/error/elog.c
@@ -836,6 +836,9 @@ matches_backtrace_functions(const char *funcname)
if (!backtrace_function_list || funcname == NULL || funcname[0] == '\0')
return false;
+ if (strcmp(backtrace_function_list, "*") == 0)
+ return true;
+
p = backtrace_function_list;
for (;;)
{
@@ -2131,6 +2134,12 @@ check_backtrace_functions(char **newval, void **extra, GucSource source)
int i;
int j;
+ if (strcmp(*newval, "*") == 0)
+ {
+ *extra = guc_strdup(ERROR, "*");
+ return true;
+ }
+
/*
* Allow characters that can be C identifiers and commas as separators, as
* well as some whitespace for readability.
--
2.34.1
v7-0001-Add-backtrace_functions_min_level.patchapplication/octet-stream; name=v7-0001-Add-backtrace_functions_min_level.patchDownload
From 91d002469c1fe87f459534860d2ba271c905025d Mon Sep 17 00:00:00 2001
From: Jelte Fennema-Nio <jelte.fennema@microsoft.com>
Date: Tue, 27 Feb 2024 17:31:24 +0100
Subject: [PATCH v7 1/2] Add backtrace_functions_min_level
Before this change a backtrace would be attached to all logs messages
in a function that matched backtrace_functions. But in most cases people
only care about the backtraces for messages with an ERROR level. This
changes that default to only log backtraces for ERROR messages but
keeps the option open of logging backtraces for different log levels
too by having users configure the new backtrace_functions_min_level GUC.
---
doc/src/sgml/config.sgml | 41 ++++++++++++++++++++++++++---
src/backend/utils/error/elog.c | 1 +
src/backend/utils/misc/guc_tables.c | 30 +++++++++++++++++++++
src/include/utils/guc.h | 1 +
4 files changed, 69 insertions(+), 4 deletions(-)
diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
index 65a6e6c4086..c76e97d2d33 100644
--- a/doc/src/sgml/config.sgml
+++ b/doc/src/sgml/config.sgml
@@ -11306,10 +11306,12 @@ dynamic_library_path = 'C:\tools\postgresql;H:\my_project\lib;$libdir'
<listitem>
<para>
This parameter contains a comma-separated list of C function names.
- If an error is raised and the name of the internal C function where
- the error happens matches a value in the list, then a backtrace is
- written to the server log together with the error message. This can
- be used to debug specific areas of the source code.
+ If a log entry is raised with a level equal to or higher than
+ <xref linkend="guc-backtrace-functions-min-level"/> and the name of the
+ internal C function where the error happens matches a value in the
+ list, then a backtrace is written to the server log together with the
+ error message. This can be used to debug specific areas of the source
+ code.
</para>
<para>
@@ -11324,6 +11326,37 @@ dynamic_library_path = 'C:\tools\postgresql;H:\my_project\lib;$libdir'
</listitem>
</varlistentry>
+ <varlistentry id="guc-backtrace-functions-min-level" xreflabel="backtrace_functions_min_level">
+ <term><varname>backtrace_functions_min_level</varname> (<type>string</type>)
+ <indexterm>
+ <primary><varname>backtrace_functions_min_level</varname> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Controls which <link linkend="runtime-config-severity-levels">message
+ levels</link> cause backtraces to be written to the log, for messages
+ raised from C functions that match the configured
+ <xref linkend="guc-backtrace-functions"/>.
+ Valid values are <literal>DEBUG5</literal>, <literal>DEBUG4</literal>,
+ <literal>DEBUG3</literal>, <literal>DEBUG2</literal>, <literal>DEBUG1</literal>,
+ <literal>LOG</literal>, <literal>INFO</literal>, <literal>NOTICE</literal>,
+ <literal>WARNING</literal>, <literal>ERROR</literal>, <literal>FATAL</literal>,
+ and <literal>PANIC</literal>. Each level includes all the levels that
+ follow it. The later the level, the fewer messages result in a
+ backtrace. The default is <literal>ERROR</literal>. Note that
+ <literal>LOG</literal> has a different rank here than in
+ <xref linkend="guc-log-min-messages"/>.
+ </para>
+
+ <para>
+ Only superusers and users with the appropriate <literal>SET</literal>
+ privilege can change this setting.
+ </para>
+ </listitem>
+ </varlistentry>
+
+
<varlistentry id="guc-backtrace-on-internal-error" xreflabel="backtrace_on_internal_error">
<term><varname>backtrace_on_internal_error</varname> (<type>boolean</type>)
<indexterm>
diff --git a/src/backend/utils/error/elog.c b/src/backend/utils/error/elog.c
index ed8aa5c9fa4..b214747500c 100644
--- a/src/backend/utils/error/elog.c
+++ b/src/backend/utils/error/elog.c
@@ -499,6 +499,7 @@ errfinish(const char *filename, int lineno, const char *funcname)
if (!edata->backtrace &&
((edata->funcname &&
backtrace_functions &&
+ edata->elevel >= backtrace_functions_min_level &&
matches_backtrace_functions(edata->funcname)) ||
(edata->sqlerrcode == ERRCODE_INTERNAL_ERROR &&
backtrace_on_internal_error)))
diff --git a/src/backend/utils/misc/guc_tables.c b/src/backend/utils/misc/guc_tables.c
index d77214795de..7a19214ee0a 100644
--- a/src/backend/utils/misc/guc_tables.c
+++ b/src/backend/utils/misc/guc_tables.c
@@ -162,6 +162,23 @@ static const struct config_enum_entry server_message_level_options[] = {
{NULL, 0, false}
};
+static const struct config_enum_entry backtrace_functions_level_options[] = {
+ {"debug5", DEBUG5, false},
+ {"debug4", DEBUG4, false},
+ {"debug3", DEBUG3, false},
+ {"debug2", DEBUG2, false},
+ {"debug1", DEBUG1, false},
+ {"debug", DEBUG2, true},
+ {"log", LOG, false},
+ {"info", INFO, true},
+ {"notice", NOTICE, false},
+ {"warning", WARNING, false},
+ {"error", ERROR, false},
+ {"fatal", FATAL, false},
+ {"panic", PANIC, false},
+ {NULL, 0, false}
+};
+
static const struct config_enum_entry intervalstyle_options[] = {
{"postgres", INTSTYLE_POSTGRES, false},
{"postgres_verbose", INTSTYLE_POSTGRES_VERBOSE, false},
@@ -530,6 +547,7 @@ double log_statement_sample_rate = 1.0;
double log_xact_sample_rate = 0;
char *backtrace_functions;
bool backtrace_on_internal_error = false;
+int backtrace_functions_min_level = ERROR;
int temp_file_limit = -1;
@@ -4703,6 +4721,18 @@ struct config_enum ConfigureNamesEnum[] =
NULL, NULL, NULL
},
+ {
+ {"backtrace_functions_min_level", PGC_SUSET, DEVELOPER_OPTIONS,
+ gettext_noop("Sets the message levels that create backtraces when backtrace_functions is configured."),
+ gettext_noop("Each level includes all the levels that follow it. The later"
+ " the level, the fewer backtraces are created."),
+ GUC_NOT_IN_SAMPLE
+ },
+ &backtrace_functions_min_level,
+ ERROR, backtrace_functions_level_options,
+ NULL, NULL, NULL
+ },
+
{
{"bytea_output", PGC_USERSET, CLIENT_CONN_STATEMENT,
gettext_noop("Sets the output format for bytea."),
diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h
index 3712aba09b0..66dbf637c68 100644
--- a/src/include/utils/guc.h
+++ b/src/include/utils/guc.h
@@ -267,6 +267,7 @@ extern PGDLLIMPORT double log_statement_sample_rate;
extern PGDLLIMPORT double log_xact_sample_rate;
extern PGDLLIMPORT char *backtrace_functions;
extern PGDLLIMPORT bool backtrace_on_internal_error;
+extern PGDLLIMPORT int backtrace_functions_min_level;
extern PGDLLIMPORT int temp_file_limit;
base-commit: 6d9751fa8fd40c988541c9c72ac7a2095ba73c19
--
2.34.1
On 08.03.24 16:55, Jelte Fennema-Nio wrote:
On Fri, 8 Mar 2024 at 15:51, Peter Eisentraut <peter@eisentraut.org> wrote:
What is the relationship of these changes with the recently added
backtrace_on_internal_error?I think that's a reasonable question. And the follow up ones too.
I think it all depends on how close we consider
backtrace_on_internal_error and backtrace_functions. While they
obviously have similar functionality, I feel like
backtrace_on_internal_error is probably a function that we'd want to
turn on by default in the future. While backtrace_functions seems like
it's mostly useful for developers. (i.e. the current grouping of
backtrace_on_internal_error under DEVELOPER_OPTIONS seems wrong to me)
Hence the idea
backtrace_on_error = {all|internal|none}
which could default to 'internal'.
On Wed, Mar 13, 2024 at 7:50 PM Peter Eisentraut <peter@eisentraut.org> wrote:
I think it all depends on how close we consider
backtrace_on_internal_error and backtrace_functions. While they
obviously have similar functionality, I feel like
backtrace_on_internal_error is probably a function that we'd want to
turn on by default in the future. While backtrace_functions seems like
it's mostly useful for developers. (i.e. the current grouping of
backtrace_on_internal_error under DEVELOPER_OPTIONS seems wrong to me)Hence the idea
backtrace_on_error = {all|internal|none}
which could default to 'internal'.
So, are you suggesting to just have backtrace_on_error =
{all|internal|none} leaving backtrace_functions_min_level aside?
In that case, I'd like to understand how backtrace_on_error and
backtrace_functions interact with each other? Does one need to set
backtrace_on_error = all to get backtrace of functions specified in
backtrace_functions?
What must be the behaviour of backtrace_on_error = all?
--
Bharath Rupireddy
PostgreSQL Contributors Team
RDS Open Source Databases
Amazon Web Services: https://aws.amazon.com
On Wed, 13 Mar 2024 at 15:20, Peter Eisentraut <peter@eisentraut.org> wrote:
Hence the idea
backtrace_on_error = {all|internal|none}
which could default to 'internal'.
I think one use-case that I'd personally at least would like to see
covered is being able to get backtraces on all warnings. How would
that be done with this setting?
backtrace_on_error = all
backtrace_min_level = warning
In that case backtrace_on_error seems like a weird name, since it can
include backtraces for warnings if you change backtrace_min_level. How
about the following aproach. It still uses 3 GUCs, but they now all
work together. There's one entry point and two additional filters
(level and function name)
# Says what log entries to log backtraces for
log_backtrace = {all|internal|none} (default: internal)
# Excludes log entries from log_include_backtrace by level
backtrace_min_level = {debug4|...|fatal} (default: error)
# Excludes log entries from log_include_backtrace if function name
# does not match list, but empty string disables this filter (thus
# logging for all functions)
backtrace_functions = {...} (default: '')
PS. Other naming option for log_backtrace could be log_include_backtrace
On Wed, 13 Mar 2024 at 16:32, Jelte Fennema-Nio <me@jeltef.nl> wrote:
How
about the following aproach. It still uses 3 GUCs, but they now all
work together. There's one entry point and two additional filters
(level and function name)# Says what log entries to log backtraces for
log_backtrace = {all|internal|none} (default: internal)# Excludes log entries from log_include_backtrace by level
backtrace_min_level = {debug4|...|fatal} (default: error)# Excludes log entries from log_include_backtrace if function name
# does not match list, but empty string disables this filter (thus
# logging for all functions)
backtrace_functions = {...} (default: '')
Attached is a patch that implements this. Since the more I think about
it, the more I like this approach.
Attachments:
v8-0001-Add-PGErrorVerbosity-to-typedefs.list.patchapplication/octet-stream; name=v8-0001-Add-PGErrorVerbosity-to-typedefs.list.patchDownload
From eb4f9871dd0cdd47d26811849a1b3d42b1273113 Mon Sep 17 00:00:00 2001
From: Jelte Fennema-Nio <jelte.fennema@microsoft.com>
Date: Thu, 21 Mar 2024 13:05:35 +0100
Subject: [PATCH v8 1/2] Add PGErrorVerbosity to typedefs.list
This one was missing, resulting in some strange alignment.
---
src/include/utils/elog.h | 2 +-
src/tools/pgindent/typedefs.list | 1 +
2 files changed, 2 insertions(+), 1 deletion(-)
diff --git a/src/include/utils/elog.h b/src/include/utils/elog.h
index 054dd2bf62f..da1a7469fa5 100644
--- a/src/include/utils/elog.h
+++ b/src/include/utils/elog.h
@@ -493,7 +493,7 @@ typedef enum
PGERROR_TERSE, /* single-line error messages */
PGERROR_DEFAULT, /* recommended style */
PGERROR_VERBOSE, /* all the facts, ma'am */
-} PGErrorVerbosity;
+} PGErrorVerbosity;
extern PGDLLIMPORT int Log_error_verbosity;
extern PGDLLIMPORT char *Log_line_prefix;
diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list
index 3b8cec58abc..13048910e46 100644
--- a/src/tools/pgindent/typedefs.list
+++ b/src/tools/pgindent/typedefs.list
@@ -1737,6 +1737,7 @@ PGAsyncStatusType
PGCALL2
PGChecksummablePage
PGContextVisibility
+PGErrorVerbosity
PGEvent
PGEventConnDestroy
PGEventConnReset
base-commit: 1db689715d44276407dc4d6fadbc11da8d391bd9
--
2.34.1
v8-0002-Restructure-backtrace-related-GUCs.patchapplication/octet-stream; name=v8-0002-Restructure-backtrace-related-GUCs.patchDownload
From e70dc5571e825af563435204ea07be2bac64f86c Mon Sep 17 00:00:00 2001
From: Jelte Fennema-Nio <jelte.fennema@microsoft.com>
Date: Tue, 27 Feb 2024 17:31:24 +0100
Subject: [PATCH v8 2/2] Restructure backtrace related GUCs
Our GUCs that controlled backtraces were added a bit ad-hoc. This
restructures them in a more complete and more easily extendable design:
1. Replaces the `backtrace_on_internal_error` GUC with a `log_backtrace`
one, which can be set to `internal` and `none` to match the previous
behaviour of the `on` and `off` values of
`backtrace_on_internal_error`. But it can also be set to `all`
2. Make `backtrace_functions` behave as an additional filter on top of
`log_backtrace`. The empty string (the default) is now interpreted as
doing no filtering based on function name.
3. Add a `backtrace_min_level` GUC, which limits for which log entries
backtraces are written, based on their log level. This defaults to
ERROR.
Being able to log backtraces for all ERROR logs was the trigger for this
redesign of the backtrace GUCs. This is now possible by simply setting
log_backtrace to "all".
---
doc/src/sgml/config.sgml | 91 ++++++++++++++-----
src/backend/utils/error/elog.c | 32 +++++--
src/backend/utils/misc/guc_tables.c | 61 ++++++++++---
src/backend/utils/misc/postgresql.conf.sample | 1 +
src/include/utils/elog.h | 8 ++
src/include/utils/guc.h | 2 +-
src/tools/pgindent/typedefs.list | 1 +
7 files changed, 153 insertions(+), 43 deletions(-)
diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
index 65a6e6c4086..c3f343be00d 100644
--- a/doc/src/sgml/config.sgml
+++ b/doc/src/sgml/config.sgml
@@ -7270,6 +7270,44 @@ local0.* /var/log/postgresql
</listitem>
</varlistentry>
+ <varlistentry id="guc-log-backtrace" xreflabel="backtrace_on_internal_error">
+ <term><varname>log_backtrace</varname> (<type>boolean</type>)
+ <indexterm>
+ <primary><varname>log_backtrace</varname> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ If this parameter is set to <literal>all</literal> then for all log
+ entries a backtrace is written to the server log together with the log
+ message. If this parameter is set to <literal>internal</literal> then
+ only such a backtrace is only written for logs with error code XX000
+ (internal error; see also <xref linkend="errcodes-appendix"/>).
+ This can be used to debug such internal errors (which should normally
+ not happen in production). The default is <literal>none</literal>,
+ which means backtraces are never written to the server log.
+ </para>
+
+ <para>
+ The logs for which a backtrace is written can be further restricted
+ using <xref linkend="guc-backtrace-min-level"/> (default:
+ <literal>error</literal>) and <xref linkend="guc-backtrace-functions"/>
+ (default: empty string, meaning all).
+ </para>
+
+ <para>
+ Backtrace support is not available on all platforms, and the quality
+ of the backtraces depends on compilation options.
+ </para>
+
+ <para>
+ Only superusers and users with the appropriate <literal>SET</literal>
+ privilege can change this setting.
+ </para>
+ </listitem>
+ </varlistentry>
+
+
<varlistentry id="guc-log-checkpoints" xreflabel="log_checkpoints">
<term><varname>log_checkpoints</varname> (<type>boolean</type>)
<indexterm>
@@ -11305,43 +11343,45 @@ dynamic_library_path = 'C:\tools\postgresql;H:\my_project\lib;$libdir'
</term>
<listitem>
<para>
- This parameter contains a comma-separated list of C function names.
- If an error is raised and the name of the internal C function where
- the error happens matches a value in the list, then a backtrace is
- written to the server log together with the error message. This can
- be used to debug specific areas of the source code.
- </para>
-
- <para>
- Backtrace support is not available on all platforms, and the quality
- of the backtraces depends on compilation options.
+ This parameter can contain a comma-separated list of C function names,
+ which can be used to filter for which logs a backtrace is written to
+ the server log.
+ If a log entry is raised and the name of the
+ internal C function where the error happens does not match any of the
+ values in the list, then no backtrace is written to the server log.
+ This can be used to only debug specific areas of the source code.
</para>
<para>
- Only superusers and users with the appropriate <literal>SET</literal>
- privilege can change this setting.
+ The empty string (the default) disables any such filtering. So for any
+ logs that match both <xref linkend="guc-log-backtrace"/> and
+ <xref linkend="guc-backtrace-min-level"/> a backtrace is
+ written to the server log.
</para>
</listitem>
</varlistentry>
- <varlistentry id="guc-backtrace-on-internal-error" xreflabel="backtrace_on_internal_error">
- <term><varname>backtrace_on_internal_error</varname> (<type>boolean</type>)
+ <varlistentry id="guc-backtrace-min-level" xreflabel="backtrace_min_level">
+ <term><varname>backtrace_min_level</varname> (<type>string</type>)
<indexterm>
- <primary><varname>backtrace_on_internal_error</varname> configuration parameter</primary>
+ <primary><varname>backtrace_min_level</varname> configuration parameter</primary>
</indexterm>
</term>
<listitem>
<para>
- If this parameter is on and an error with error code XX000 (internal
- error; see also <xref linkend="errcodes-appendix"/>) is raised, then a
- backtrace is written to the server log together with the error
- message. This can be used to debug such internal errors (which should
- normally not happen in production). The default is off.
- </para>
-
- <para>
- Backtrace support is not available on all platforms, and the quality
- of the backtraces depends on compilation options.
+ Controls which <link linkend="runtime-config-severity-levels">message
+ levels</link> cause backtraces to be written to the log, for log
+ messages that match both <xref linkend="guc-log-backtrace"/> and
+ <xref linkend="guc-backtrace-functions"/>.
+ Valid values are <literal>DEBUG5</literal>, <literal>DEBUG4</literal>,
+ <literal>DEBUG3</literal>, <literal>DEBUG2</literal>, <literal>DEBUG1</literal>,
+ <literal>LOG</literal>, <literal>INFO</literal>, <literal>NOTICE</literal>,
+ <literal>WARNING</literal>, <literal>ERROR</literal>, <literal>FATAL</literal>,
+ and <literal>PANIC</literal>. Each level includes all the levels that
+ follow it. The later the level, the fewer messages result in a
+ backtrace. The default is <literal>ERROR</literal>. Note that
+ <literal>LOG</literal> has a different rank here than in
+ <xref linkend="guc-log-min-messages"/>.
</para>
<para>
@@ -11351,6 +11391,7 @@ dynamic_library_path = 'C:\tools\postgresql;H:\my_project\lib;$libdir'
</listitem>
</varlistentry>
+
<varlistentry id="guc-debug-discard-caches" xreflabel="debug_discard_caches">
<term><varname>debug_discard_caches</varname> (<type>integer</type>)
<indexterm>
diff --git a/src/backend/utils/error/elog.c b/src/backend/utils/error/elog.c
index 52bc01058c5..8f6a107d285 100644
--- a/src/backend/utils/error/elog.c
+++ b/src/backend/utils/error/elog.c
@@ -111,6 +111,7 @@ int Log_error_verbosity = PGERROR_DEFAULT;
char *Log_line_prefix = NULL; /* format for extra log line info */
int Log_destination = LOG_DESTINATION_STDERR;
char *Log_destination_string = NULL;
+int log_backtrace = LOGBACKTRACE_NONE;
bool syslog_sequence_numbers = true;
bool syslog_split_messages = true;
@@ -181,6 +182,7 @@ static void set_stack_entry_domain(ErrorData *edata, const char *domain);
static void set_stack_entry_location(ErrorData *edata,
const char *filename, int lineno,
const char *funcname);
+static bool matches_backtrace_gucs(ErrorData *edata);
static bool matches_backtrace_functions(const char *funcname);
static pg_noinline void set_backtrace(ErrorData *edata, int num_skip);
static void set_errdata_field(MemoryContextData *cxt, char **ptr, const char *str);
@@ -496,12 +498,7 @@ errfinish(const char *filename, int lineno, const char *funcname)
oldcontext = MemoryContextSwitchTo(ErrorContext);
/* Collect backtrace, if enabled and we didn't already */
- if (!edata->backtrace &&
- ((edata->funcname &&
- backtrace_functions &&
- matches_backtrace_functions(edata->funcname)) ||
- (edata->sqlerrcode == ERRCODE_INTERNAL_ERROR &&
- backtrace_on_internal_error)))
+ if (!edata->backtrace && matches_backtrace_gucs(edata))
set_backtrace(edata, 2);
/*
@@ -821,6 +818,26 @@ set_stack_entry_location(ErrorData *edata,
edata->funcname = funcname;
}
+/*
+ * matches_backtrace_gucs --- checks whether the log entry matches
+ * log_backtrace, backtrace_min_level and backtrace_functions.
+ */
+static bool
+matches_backtrace_gucs(ErrorData *edata)
+{
+ if (log_backtrace == LOGBACKTRACE_NONE)
+ return false;
+
+ if (log_backtrace == LOGBACKTRACE_INTERNAL &&
+ edata->sqlerrcode != ERRCODE_INTERNAL_ERROR)
+ return false;
+
+ if (backtrace_min_level > edata->elevel)
+ return false;
+
+ return matches_backtrace_functions(edata->funcname);
+}
+
/*
* matches_backtrace_functions --- checks whether the given funcname matches
* backtrace_functions
@@ -832,6 +849,9 @@ matches_backtrace_functions(const char *funcname)
{
const char *p;
+ if (!backtrace_functions || backtrace_functions[0] == '\0')
+ return true;
+
if (!backtrace_function_list || funcname == NULL || funcname[0] == '\0')
return false;
diff --git a/src/backend/utils/misc/guc_tables.c b/src/backend/utils/misc/guc_tables.c
index 1e71e7db4a0..f6f4f0521e8 100644
--- a/src/backend/utils/misc/guc_tables.c
+++ b/src/backend/utils/misc/guc_tables.c
@@ -162,6 +162,23 @@ static const struct config_enum_entry server_message_level_options[] = {
{NULL, 0, false}
};
+static const struct config_enum_entry backtrace_functions_level_options[] = {
+ {"debug5", DEBUG5, false},
+ {"debug4", DEBUG4, false},
+ {"debug3", DEBUG3, false},
+ {"debug2", DEBUG2, false},
+ {"debug1", DEBUG1, false},
+ {"debug", DEBUG2, true},
+ {"log", LOG, false},
+ {"info", INFO, true},
+ {"notice", NOTICE, false},
+ {"warning", WARNING, false},
+ {"error", ERROR, false},
+ {"fatal", FATAL, false},
+ {"panic", PANIC, false},
+ {NULL, 0, false}
+};
+
static const struct config_enum_entry intervalstyle_options[] = {
{"postgres", INTSTYLE_POSTGRES, false},
{"postgres_verbose", INTSTYLE_POSTGRES_VERBOSE, false},
@@ -199,6 +216,16 @@ static const struct config_enum_entry log_error_verbosity_options[] = {
StaticAssertDecl(lengthof(log_error_verbosity_options) == (PGERROR_VERBOSE + 2),
"array length mismatch");
+static const struct config_enum_entry log_backtrace_options[] = {
+ {"none", LOGBACKTRACE_NONE, false},
+ {"internal", LOGBACKTRACE_INTERNAL, false},
+ {"all", LOGBACKTRACE_ALL, false},
+ {NULL, 0, false}
+};
+
+StaticAssertDecl(lengthof(log_backtrace_options) == (LOGBACKTRACE_ALL + 2),
+ "array length mismatch");
+
static const struct config_enum_entry log_statement_options[] = {
{"none", LOGSTMT_NONE, false},
{"ddl", LOGSTMT_DDL, false},
@@ -529,7 +556,7 @@ int log_temp_files = -1;
double log_statement_sample_rate = 1.0;
double log_xact_sample_rate = 0;
char *backtrace_functions;
-bool backtrace_on_internal_error = false;
+int backtrace_min_level = ERROR;
int temp_file_limit = -1;
@@ -768,16 +795,6 @@ StaticAssertDecl(lengthof(config_type_names) == (PGC_ENUM + 1),
struct config_bool ConfigureNamesBool[] =
{
- {
- {"backtrace_on_internal_error", PGC_SUSET, DEVELOPER_OPTIONS,
- gettext_noop("Log backtrace for any error with error code XX000 (internal error)."),
- NULL,
- GUC_NOT_IN_SAMPLE
- },
- &backtrace_on_internal_error,
- false,
- NULL, NULL, NULL
- },
{
{"enable_seqscan", PGC_USERSET, QUERY_TUNING_METHOD,
gettext_noop("Enables the planner's use of sequential-scan plans."),
@@ -4703,6 +4720,18 @@ struct config_enum ConfigureNamesEnum[] =
NULL, NULL, NULL
},
+ {
+ {"backtrace_min_level", PGC_SUSET, DEVELOPER_OPTIONS,
+ gettext_noop("Sets the message levels that create backtraces when log_backtrace is configured."),
+ gettext_noop("Each level includes all the levels that follow it. The later"
+ " the level, the fewer backtraces are created."),
+ GUC_NOT_IN_SAMPLE
+ },
+ &backtrace_min_level,
+ ERROR, backtrace_functions_level_options,
+ NULL, NULL, NULL
+ },
+
{
{"bytea_output", PGC_USERSET, CLIENT_CONN_STATEMENT,
gettext_noop("Sets the output format for bytea."),
@@ -4799,6 +4828,16 @@ struct config_enum ConfigureNamesEnum[] =
NULL, NULL, NULL
},
+ {
+ {"log_backtrace", PGC_SUSET, LOGGING_WHAT,
+ gettext_noop("Sets if logs should include a backtrace."),
+ NULL
+ },
+ &log_backtrace,
+ LOGBACKTRACE_NONE, log_backtrace_options,
+ NULL, NULL, NULL
+ },
+
{
{"log_error_verbosity", PGC_SUSET, LOGGING_WHAT,
gettext_noop("Sets the verbosity of logged messages."),
diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample
index 2244ee52f79..46d21df6b60 100644
--- a/src/backend/utils/misc/postgresql.conf.sample
+++ b/src/backend/utils/misc/postgresql.conf.sample
@@ -574,6 +574,7 @@
# their durations, > 0 logs only
# actions running at least this number
# of milliseconds.
+#log_backtrace = 'none'
#log_checkpoints = on
#log_connections = off
#log_disconnections = off
diff --git a/src/include/utils/elog.h b/src/include/utils/elog.h
index da1a7469fa5..6370f23f27d 100644
--- a/src/include/utils/elog.h
+++ b/src/include/utils/elog.h
@@ -495,9 +495,17 @@ typedef enum
PGERROR_VERBOSE, /* all the facts, ma'am */
} PGErrorVerbosity;
+typedef enum
+{
+ LOGBACKTRACE_NONE, /* no backtrace */
+ LOGBACKTRACE_INTERNAL, /* backtrace for internal error code */
+ LOGBACKTRACE_ALL, /* backtrace for all logs */
+} LogBacktraceVerbosity;
+
extern PGDLLIMPORT int Log_error_verbosity;
extern PGDLLIMPORT char *Log_line_prefix;
extern PGDLLIMPORT int Log_destination;
+extern PGDLLIMPORT int log_backtrace;
extern PGDLLIMPORT char *Log_destination_string;
extern PGDLLIMPORT bool syslog_sequence_numbers;
extern PGDLLIMPORT bool syslog_split_messages;
diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h
index 3712aba09b0..2398ab7d730 100644
--- a/src/include/utils/guc.h
+++ b/src/include/utils/guc.h
@@ -266,7 +266,7 @@ extern PGDLLIMPORT int log_temp_files;
extern PGDLLIMPORT double log_statement_sample_rate;
extern PGDLLIMPORT double log_xact_sample_rate;
extern PGDLLIMPORT char *backtrace_functions;
-extern PGDLLIMPORT bool backtrace_on_internal_error;
+extern PGDLLIMPORT int backtrace_min_level;
extern PGDLLIMPORT int temp_file_limit;
diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list
index 13048910e46..0123e347890 100644
--- a/src/tools/pgindent/typedefs.list
+++ b/src/tools/pgindent/typedefs.list
@@ -1489,6 +1489,7 @@ LockTupleMode
LockViewRecurse_context
LockWaitPolicy
LockingClause
+LogBacktraceVerbosity
LogOpts
LogStmtLevel
LogicalDecodeBeginCB
--
2.34.1
On Thu, 21 Mar 2024 at 15:41, Jelte Fennema-Nio <me@jeltef.nl> wrote:
Attached is a patch that implements this. Since the more I think about
it, the more I like this approach.
I now added a 3rd patch to this patchset which changes the
log_backtrace default to "internal", because it seems quite useful to
me if user error reports of internal errors included a backtrace.
Attachments:
v9-0002-Restructure-backtrace-related-GUCs.patchapplication/octet-stream; name=v9-0002-Restructure-backtrace-related-GUCs.patchDownload
From 287accb62c25a960294d6054a1a97777a3625bdd Mon Sep 17 00:00:00 2001
From: Jelte Fennema-Nio <jelte.fennema@microsoft.com>
Date: Tue, 27 Feb 2024 17:31:24 +0100
Subject: [PATCH v9 2/3] Restructure backtrace related GUCs
Our GUCs that controlled backtraces were added a bit ad-hoc. This
restructures them in a more complete and more easily extendable design:
1. Replaces the `backtrace_on_internal_error` GUC with a `log_backtrace`
one, which can be set to `internal` and `none` to match the previous
behaviour of the `on` and `off` values of
`backtrace_on_internal_error`. But it can also be set to `all`
2. Make `backtrace_functions` behave as an additional filter on top of
`log_backtrace`. The empty string (the default) is now interpreted as
doing no filtering based on function name.
3. Add a `backtrace_min_level` GUC, which limits for which log entries
backtraces are written, based on their log level. This defaults to
ERROR.
Being able to log backtraces for all ERROR logs was the trigger for this
redesign of the backtrace GUCs. This is now possible by simply setting
log_backtrace to "all".
---
doc/src/sgml/config.sgml | 92 ++++++++++++++-----
src/backend/utils/error/elog.c | 32 +++++--
src/backend/utils/misc/guc_tables.c | 61 +++++++++---
src/backend/utils/misc/postgresql.conf.sample | 1 +
src/include/utils/elog.h | 8 ++
src/include/utils/guc.h | 2 +-
src/tools/pgindent/typedefs.list | 1 +
7 files changed, 154 insertions(+), 43 deletions(-)
diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
index 65a6e6c4086..b315c84ce98 100644
--- a/doc/src/sgml/config.sgml
+++ b/doc/src/sgml/config.sgml
@@ -7270,6 +7270,45 @@ local0.* /var/log/postgresql
</listitem>
</varlistentry>
+ <varlistentry id="guc-log-backtrace" xreflabel="backtrace_on_internal_error">
+ <term><varname>log_backtrace</varname> (<type>boolean</type>)
+ <indexterm>
+ <primary><varname>log_backtrace</varname> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ If this parameter is set to <literal>all</literal> then for all log
+ entries a backtrace is written to the server log together with the log
+ message. If this parameter is set to <literal>internal</literal> then
+ such a backtrace is only written for logs with error code XX000
+ (internal error; see also <xref linkend="errcodes-appendix"/>).
+ This can be used to debug such internal errors (which should normally
+ not happen in production). Finally, if this parameter is set to
+ <literal>none</literal> (the default), no backtraces are ever written
+ to the server log.
+ </para>
+
+ <para>
+ The logs for which a backtrace is written can be further restricted
+ using <xref linkend="guc-backtrace-min-level"/> (default:
+ <literal>error</literal>) and <xref linkend="guc-backtrace-functions"/>
+ (default: empty string, meaning all).
+ </para>
+
+ <para>
+ Backtrace support is not available on all platforms, and the quality
+ of the backtraces depends on compilation options.
+ </para>
+
+ <para>
+ Only superusers and users with the appropriate <literal>SET</literal>
+ privilege can change this setting.
+ </para>
+ </listitem>
+ </varlistentry>
+
+
<varlistentry id="guc-log-checkpoints" xreflabel="log_checkpoints">
<term><varname>log_checkpoints</varname> (<type>boolean</type>)
<indexterm>
@@ -11305,43 +11344,45 @@ dynamic_library_path = 'C:\tools\postgresql;H:\my_project\lib;$libdir'
</term>
<listitem>
<para>
- This parameter contains a comma-separated list of C function names.
- If an error is raised and the name of the internal C function where
- the error happens matches a value in the list, then a backtrace is
- written to the server log together with the error message. This can
- be used to debug specific areas of the source code.
- </para>
-
- <para>
- Backtrace support is not available on all platforms, and the quality
- of the backtraces depends on compilation options.
+ This parameter can contain a comma-separated list of C function names,
+ which can be used to filter for which logs a backtrace is written to
+ the server log.
+ If a log entry is raised and the name of the
+ internal C function where the error happens does not match any of the
+ values in the list, then no backtrace is written to the server log.
+ This can be used to only debug specific areas of the source code.
</para>
<para>
- Only superusers and users with the appropriate <literal>SET</literal>
- privilege can change this setting.
+ The empty string (the default) disables any such filtering. So for any
+ logs that match both <xref linkend="guc-log-backtrace"/> and
+ <xref linkend="guc-backtrace-min-level"/> a backtrace is
+ written to the server log.
</para>
</listitem>
</varlistentry>
- <varlistentry id="guc-backtrace-on-internal-error" xreflabel="backtrace_on_internal_error">
- <term><varname>backtrace_on_internal_error</varname> (<type>boolean</type>)
+ <varlistentry id="guc-backtrace-min-level" xreflabel="backtrace_min_level">
+ <term><varname>backtrace_min_level</varname> (<type>string</type>)
<indexterm>
- <primary><varname>backtrace_on_internal_error</varname> configuration parameter</primary>
+ <primary><varname>backtrace_min_level</varname> configuration parameter</primary>
</indexterm>
</term>
<listitem>
<para>
- If this parameter is on and an error with error code XX000 (internal
- error; see also <xref linkend="errcodes-appendix"/>) is raised, then a
- backtrace is written to the server log together with the error
- message. This can be used to debug such internal errors (which should
- normally not happen in production). The default is off.
- </para>
-
- <para>
- Backtrace support is not available on all platforms, and the quality
- of the backtraces depends on compilation options.
+ Controls which <link linkend="runtime-config-severity-levels">message
+ levels</link> cause backtraces to be written to the log, for log
+ messages that match both <xref linkend="guc-log-backtrace"/> and
+ <xref linkend="guc-backtrace-functions"/>.
+ Valid values are <literal>DEBUG5</literal>, <literal>DEBUG4</literal>,
+ <literal>DEBUG3</literal>, <literal>DEBUG2</literal>, <literal>DEBUG1</literal>,
+ <literal>LOG</literal>, <literal>INFO</literal>, <literal>NOTICE</literal>,
+ <literal>WARNING</literal>, <literal>ERROR</literal>, <literal>FATAL</literal>,
+ and <literal>PANIC</literal>. Each level includes all the levels that
+ follow it. The later the level, the fewer messages result in a
+ backtrace. The default is <literal>ERROR</literal>. Note that
+ <literal>LOG</literal> has a different rank here than in
+ <xref linkend="guc-log-min-messages"/>.
</para>
<para>
@@ -11351,6 +11392,7 @@ dynamic_library_path = 'C:\tools\postgresql;H:\my_project\lib;$libdir'
</listitem>
</varlistentry>
+
<varlistentry id="guc-debug-discard-caches" xreflabel="debug_discard_caches">
<term><varname>debug_discard_caches</varname> (<type>integer</type>)
<indexterm>
diff --git a/src/backend/utils/error/elog.c b/src/backend/utils/error/elog.c
index 52bc01058c5..8f6a107d285 100644
--- a/src/backend/utils/error/elog.c
+++ b/src/backend/utils/error/elog.c
@@ -111,6 +111,7 @@ int Log_error_verbosity = PGERROR_DEFAULT;
char *Log_line_prefix = NULL; /* format for extra log line info */
int Log_destination = LOG_DESTINATION_STDERR;
char *Log_destination_string = NULL;
+int log_backtrace = LOGBACKTRACE_NONE;
bool syslog_sequence_numbers = true;
bool syslog_split_messages = true;
@@ -181,6 +182,7 @@ static void set_stack_entry_domain(ErrorData *edata, const char *domain);
static void set_stack_entry_location(ErrorData *edata,
const char *filename, int lineno,
const char *funcname);
+static bool matches_backtrace_gucs(ErrorData *edata);
static bool matches_backtrace_functions(const char *funcname);
static pg_noinline void set_backtrace(ErrorData *edata, int num_skip);
static void set_errdata_field(MemoryContextData *cxt, char **ptr, const char *str);
@@ -496,12 +498,7 @@ errfinish(const char *filename, int lineno, const char *funcname)
oldcontext = MemoryContextSwitchTo(ErrorContext);
/* Collect backtrace, if enabled and we didn't already */
- if (!edata->backtrace &&
- ((edata->funcname &&
- backtrace_functions &&
- matches_backtrace_functions(edata->funcname)) ||
- (edata->sqlerrcode == ERRCODE_INTERNAL_ERROR &&
- backtrace_on_internal_error)))
+ if (!edata->backtrace && matches_backtrace_gucs(edata))
set_backtrace(edata, 2);
/*
@@ -821,6 +818,26 @@ set_stack_entry_location(ErrorData *edata,
edata->funcname = funcname;
}
+/*
+ * matches_backtrace_gucs --- checks whether the log entry matches
+ * log_backtrace, backtrace_min_level and backtrace_functions.
+ */
+static bool
+matches_backtrace_gucs(ErrorData *edata)
+{
+ if (log_backtrace == LOGBACKTRACE_NONE)
+ return false;
+
+ if (log_backtrace == LOGBACKTRACE_INTERNAL &&
+ edata->sqlerrcode != ERRCODE_INTERNAL_ERROR)
+ return false;
+
+ if (backtrace_min_level > edata->elevel)
+ return false;
+
+ return matches_backtrace_functions(edata->funcname);
+}
+
/*
* matches_backtrace_functions --- checks whether the given funcname matches
* backtrace_functions
@@ -832,6 +849,9 @@ matches_backtrace_functions(const char *funcname)
{
const char *p;
+ if (!backtrace_functions || backtrace_functions[0] == '\0')
+ return true;
+
if (!backtrace_function_list || funcname == NULL || funcname[0] == '\0')
return false;
diff --git a/src/backend/utils/misc/guc_tables.c b/src/backend/utils/misc/guc_tables.c
index 1e71e7db4a0..f6f4f0521e8 100644
--- a/src/backend/utils/misc/guc_tables.c
+++ b/src/backend/utils/misc/guc_tables.c
@@ -162,6 +162,23 @@ static const struct config_enum_entry server_message_level_options[] = {
{NULL, 0, false}
};
+static const struct config_enum_entry backtrace_functions_level_options[] = {
+ {"debug5", DEBUG5, false},
+ {"debug4", DEBUG4, false},
+ {"debug3", DEBUG3, false},
+ {"debug2", DEBUG2, false},
+ {"debug1", DEBUG1, false},
+ {"debug", DEBUG2, true},
+ {"log", LOG, false},
+ {"info", INFO, true},
+ {"notice", NOTICE, false},
+ {"warning", WARNING, false},
+ {"error", ERROR, false},
+ {"fatal", FATAL, false},
+ {"panic", PANIC, false},
+ {NULL, 0, false}
+};
+
static const struct config_enum_entry intervalstyle_options[] = {
{"postgres", INTSTYLE_POSTGRES, false},
{"postgres_verbose", INTSTYLE_POSTGRES_VERBOSE, false},
@@ -199,6 +216,16 @@ static const struct config_enum_entry log_error_verbosity_options[] = {
StaticAssertDecl(lengthof(log_error_verbosity_options) == (PGERROR_VERBOSE + 2),
"array length mismatch");
+static const struct config_enum_entry log_backtrace_options[] = {
+ {"none", LOGBACKTRACE_NONE, false},
+ {"internal", LOGBACKTRACE_INTERNAL, false},
+ {"all", LOGBACKTRACE_ALL, false},
+ {NULL, 0, false}
+};
+
+StaticAssertDecl(lengthof(log_backtrace_options) == (LOGBACKTRACE_ALL + 2),
+ "array length mismatch");
+
static const struct config_enum_entry log_statement_options[] = {
{"none", LOGSTMT_NONE, false},
{"ddl", LOGSTMT_DDL, false},
@@ -529,7 +556,7 @@ int log_temp_files = -1;
double log_statement_sample_rate = 1.0;
double log_xact_sample_rate = 0;
char *backtrace_functions;
-bool backtrace_on_internal_error = false;
+int backtrace_min_level = ERROR;
int temp_file_limit = -1;
@@ -768,16 +795,6 @@ StaticAssertDecl(lengthof(config_type_names) == (PGC_ENUM + 1),
struct config_bool ConfigureNamesBool[] =
{
- {
- {"backtrace_on_internal_error", PGC_SUSET, DEVELOPER_OPTIONS,
- gettext_noop("Log backtrace for any error with error code XX000 (internal error)."),
- NULL,
- GUC_NOT_IN_SAMPLE
- },
- &backtrace_on_internal_error,
- false,
- NULL, NULL, NULL
- },
{
{"enable_seqscan", PGC_USERSET, QUERY_TUNING_METHOD,
gettext_noop("Enables the planner's use of sequential-scan plans."),
@@ -4703,6 +4720,18 @@ struct config_enum ConfigureNamesEnum[] =
NULL, NULL, NULL
},
+ {
+ {"backtrace_min_level", PGC_SUSET, DEVELOPER_OPTIONS,
+ gettext_noop("Sets the message levels that create backtraces when log_backtrace is configured."),
+ gettext_noop("Each level includes all the levels that follow it. The later"
+ " the level, the fewer backtraces are created."),
+ GUC_NOT_IN_SAMPLE
+ },
+ &backtrace_min_level,
+ ERROR, backtrace_functions_level_options,
+ NULL, NULL, NULL
+ },
+
{
{"bytea_output", PGC_USERSET, CLIENT_CONN_STATEMENT,
gettext_noop("Sets the output format for bytea."),
@@ -4799,6 +4828,16 @@ struct config_enum ConfigureNamesEnum[] =
NULL, NULL, NULL
},
+ {
+ {"log_backtrace", PGC_SUSET, LOGGING_WHAT,
+ gettext_noop("Sets if logs should include a backtrace."),
+ NULL
+ },
+ &log_backtrace,
+ LOGBACKTRACE_NONE, log_backtrace_options,
+ NULL, NULL, NULL
+ },
+
{
{"log_error_verbosity", PGC_SUSET, LOGGING_WHAT,
gettext_noop("Sets the verbosity of logged messages."),
diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample
index 2244ee52f79..46d21df6b60 100644
--- a/src/backend/utils/misc/postgresql.conf.sample
+++ b/src/backend/utils/misc/postgresql.conf.sample
@@ -574,6 +574,7 @@
# their durations, > 0 logs only
# actions running at least this number
# of milliseconds.
+#log_backtrace = 'none'
#log_checkpoints = on
#log_connections = off
#log_disconnections = off
diff --git a/src/include/utils/elog.h b/src/include/utils/elog.h
index da1a7469fa5..6370f23f27d 100644
--- a/src/include/utils/elog.h
+++ b/src/include/utils/elog.h
@@ -495,9 +495,17 @@ typedef enum
PGERROR_VERBOSE, /* all the facts, ma'am */
} PGErrorVerbosity;
+typedef enum
+{
+ LOGBACKTRACE_NONE, /* no backtrace */
+ LOGBACKTRACE_INTERNAL, /* backtrace for internal error code */
+ LOGBACKTRACE_ALL, /* backtrace for all logs */
+} LogBacktraceVerbosity;
+
extern PGDLLIMPORT int Log_error_verbosity;
extern PGDLLIMPORT char *Log_line_prefix;
extern PGDLLIMPORT int Log_destination;
+extern PGDLLIMPORT int log_backtrace;
extern PGDLLIMPORT char *Log_destination_string;
extern PGDLLIMPORT bool syslog_sequence_numbers;
extern PGDLLIMPORT bool syslog_split_messages;
diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h
index 3712aba09b0..2398ab7d730 100644
--- a/src/include/utils/guc.h
+++ b/src/include/utils/guc.h
@@ -266,7 +266,7 @@ extern PGDLLIMPORT int log_temp_files;
extern PGDLLIMPORT double log_statement_sample_rate;
extern PGDLLIMPORT double log_xact_sample_rate;
extern PGDLLIMPORT char *backtrace_functions;
-extern PGDLLIMPORT bool backtrace_on_internal_error;
+extern PGDLLIMPORT int backtrace_min_level;
extern PGDLLIMPORT int temp_file_limit;
diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list
index a2e6d4fdc6a..a6b1d9f11e7 100644
--- a/src/tools/pgindent/typedefs.list
+++ b/src/tools/pgindent/typedefs.list
@@ -1489,6 +1489,7 @@ LockTupleMode
LockViewRecurse_context
LockWaitPolicy
LockingClause
+LogBacktraceVerbosity
LogOpts
LogStmtLevel
LogicalDecodeBeginCB
--
2.34.1
v9-0001-Add-PGErrorVerbosity-to-typedefs.list.patchapplication/octet-stream; name=v9-0001-Add-PGErrorVerbosity-to-typedefs.list.patchDownload
From 8a9c67c8c60afff7341f5fa8dfc99d795b393dd3 Mon Sep 17 00:00:00 2001
From: Jelte Fennema-Nio <jelte.fennema@microsoft.com>
Date: Thu, 21 Mar 2024 13:05:35 +0100
Subject: [PATCH v9 1/3] Add PGErrorVerbosity to typedefs.list
This one was missing, resulting in some strange alignment.
---
src/include/utils/elog.h | 2 +-
src/tools/pgindent/typedefs.list | 1 +
2 files changed, 2 insertions(+), 1 deletion(-)
diff --git a/src/include/utils/elog.h b/src/include/utils/elog.h
index 054dd2bf62f..da1a7469fa5 100644
--- a/src/include/utils/elog.h
+++ b/src/include/utils/elog.h
@@ -493,7 +493,7 @@ typedef enum
PGERROR_TERSE, /* single-line error messages */
PGERROR_DEFAULT, /* recommended style */
PGERROR_VERBOSE, /* all the facts, ma'am */
-} PGErrorVerbosity;
+} PGErrorVerbosity;
extern PGDLLIMPORT int Log_error_verbosity;
extern PGDLLIMPORT char *Log_line_prefix;
diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list
index e2a0525dd4a..a2e6d4fdc6a 100644
--- a/src/tools/pgindent/typedefs.list
+++ b/src/tools/pgindent/typedefs.list
@@ -1737,6 +1737,7 @@ PGAsyncStatusType
PGCALL2
PGChecksummablePage
PGContextVisibility
+PGErrorVerbosity
PGEvent
PGEventConnDestroy
PGEventConnReset
base-commit: b4080fa3dcf6c6359e542169e0e81a0662c53ba8
--
2.34.1
v9-0003-Change-log_backtrace-default-to-internal.patchapplication/octet-stream; name=v9-0003-Change-log_backtrace-default-to-internal.patchDownload
From 71a31fc3ec25590f6a799118a923ab6366a37ad0 Mon Sep 17 00:00:00 2001
From: Jelte Fennema-Nio <jelte.fennema@microsoft.com>
Date: Fri, 22 Mar 2024 10:58:53 +0100
Subject: [PATCH v9 3/3] Change log_backtrace default to "internal"
Internal errors should not happen in production. When they do it is
likely a bug and it can be very useful to have a backtrace when trying
to determine it's exact cause. This changes the default for
log_backtrace to "internal" so that the bug reports we receive are much
more likely to include such a backtrace.
---
doc/src/sgml/config.sgml | 4 ++--
src/backend/utils/error/elog.c | 2 +-
src/backend/utils/misc/guc_tables.c | 2 +-
3 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
index b315c84ce98..223442afbe5 100644
--- a/doc/src/sgml/config.sgml
+++ b/doc/src/sgml/config.sgml
@@ -7280,12 +7280,12 @@ local0.* /var/log/postgresql
<para>
If this parameter is set to <literal>all</literal> then for all log
entries a backtrace is written to the server log together with the log
- message. If this parameter is set to <literal>internal</literal> then
+ message. If this parameter is set to <literal>internal</literal> (the default) then
such a backtrace is only written for logs with error code XX000
(internal error; see also <xref linkend="errcodes-appendix"/>).
This can be used to debug such internal errors (which should normally
not happen in production). Finally, if this parameter is set to
- <literal>none</literal> (the default), no backtraces are ever written
+ <literal>none</literal>, no backtraces are ever written
to the server log.
</para>
diff --git a/src/backend/utils/error/elog.c b/src/backend/utils/error/elog.c
index 8f6a107d285..c199538e270 100644
--- a/src/backend/utils/error/elog.c
+++ b/src/backend/utils/error/elog.c
@@ -111,7 +111,7 @@ int Log_error_verbosity = PGERROR_DEFAULT;
char *Log_line_prefix = NULL; /* format for extra log line info */
int Log_destination = LOG_DESTINATION_STDERR;
char *Log_destination_string = NULL;
-int log_backtrace = LOGBACKTRACE_NONE;
+int log_backtrace = LOGBACKTRACE_INTERNAL;
bool syslog_sequence_numbers = true;
bool syslog_split_messages = true;
diff --git a/src/backend/utils/misc/guc_tables.c b/src/backend/utils/misc/guc_tables.c
index f6f4f0521e8..f2a79a0980a 100644
--- a/src/backend/utils/misc/guc_tables.c
+++ b/src/backend/utils/misc/guc_tables.c
@@ -4834,7 +4834,7 @@ struct config_enum ConfigureNamesEnum[] =
NULL
},
&log_backtrace,
- LOGBACKTRACE_NONE, log_backtrace_options,
+ LOGBACKTRACE_INTERNAL, log_backtrace_options,
NULL, NULL, NULL
},
--
2.34.1
On Thu, Mar 21, 2024 at 8:11 PM Jelte Fennema-Nio <me@jeltef.nl> wrote:
Attached is a patch that implements this. Since the more I think about
it, the more I like this approach.
Thanks. Overall the design looks good. log_backtrace is the entry
point for one to control if a backtrace needs to be emitted at all.
backtrace_min_level controls at what elevel the backtraces need to be
emitted.
If one wants to get backtraces for all internal ERRORs, then
log_backtrace = 'internal' and backtrace_min_level = 'error' must be
set. If backtrace_min_level = 'panic', then backtraces won't get
logged for internal ERRORs. But, this is not the case right now, one
can just set backtrace_on_internal_error = 'on' to get backtraces for
all internal ERROR/FATAL or whatever just the errcode has to be
ERRCODE_INTERNAL_ERROR. This is one change of behaviour and looks fine
to me.
If one wants to get backtrace from a function for all elog/ereport
calls, then log_backtrace = either 'internal' or 'all',
backtrace_min_level = 'debug5' and backtrace_functions =
'<function_name>' must be set. But, right now, one can just set
backtrace_functions = '<function_name>' to get backtrace from the
functions for any of elog/ereport calls.
A few comments:
1.
@@ -832,6 +849,9 @@ matches_backtrace_functions(const char *funcname)
{
const char *p;
+ if (!backtrace_functions || backtrace_functions[0] == '\0')
+ return true;
+
Shouldn't this be returning false to not log set backtrace when
backtrace_functions is not set? Am I missing something here?
2.
+ {
+ {"log_backtrace", PGC_SUSET, LOGGING_WHAT,
+ gettext_noop("Sets if logs should include a backtrace."),
+ NULL
IMV, log_backtrace, backtrace_min_level and backtrace_functions are
interlinked, so keeping all of them as DEVELOPER_OPTIONS looks fine to
me than having log_backtrace at just LOGGING_WHAT kind. Also, we must
also mark log_backtrace as GUC_NOT_IN_SAMPLE.
3. I think it's worth adding a few examples to get backtraces in docs.
For instance, what to set to get backtraces of all internal errors and
what to set to get backtraces of all ERRORs coming from a specific
function etc.
4. I see the support for wildcard in backtrace_functions is missing.
Is it intentionally left out? If not, can you make it part of 0003
patch?
5. The amount of backtraces generated is going to be too huge when
setting log_backtrace = 'all' and backtrace_min_level = 'debug5'. With
this setting installcheck generated 12MB worth of log and the test
took about 55 seconds (as opposed to 48 seconds without it) The point
is if these settings are misused, it can easily slow down the entire
system and fill up disk space leading to crashes eventually. This
makes a strong case for marking log_backtrace a developer only
function.
6. In continuation to comment #5, does anyone need backtrace for
elevels like debugX and LOG etc.? What's the use of the backtrace in
such cases?
--
Bharath Rupireddy
PostgreSQL Contributors Team
RDS Open Source Databases
Amazon Web Services: https://aws.amazon.com
On Fri, 22 Mar 2024 at 11:14, Bharath Rupireddy
<bharath.rupireddyforpostgres@gmail.com> wrote:
A few comments:
1.
@@ -832,6 +849,9 @@ matches_backtrace_functions(const char *funcname)
{
const char *p;+ if (!backtrace_functions || backtrace_functions[0] == '\0') + return true; +Shouldn't this be returning false to not log set backtrace when
backtrace_functions is not set? Am I missing something here?
Empty string is considered the new wildcard, i.e. backtrace_functions
filtering is not enabled if it is empty. This seemed reasonable to me
since you should now disable backtraces by using log_backtrace=none,
having backtrace_functions='' mean the same thing seems rather
useless. I also documented this in the updated docs.
2. + { + {"log_backtrace", PGC_SUSET, LOGGING_WHAT, + gettext_noop("Sets if logs should include a backtrace."), + NULLIMV, log_backtrace, backtrace_min_level and backtrace_functions are
interlinked, so keeping all of them as DEVELOPER_OPTIONS looks fine to
me than having log_backtrace at just LOGGING_WHAT kind. Also, we must
also mark log_backtrace as GUC_NOT_IN_SAMPLE.
I agree they are linked, but I don't think it's just useful for
developers to be able to set log_backtrace to internal (even if we
choose not to make "internal" the default).
3. I think it's worth adding a few examples to get backtraces in docs.
For instance, what to set to get backtraces of all internal errors and
what to set to get backtraces of all ERRORs coming from a specific
function etc.
Good idea, I'll try to add those later. For now your specific cases would be:
log_backtrace = 'internal' (default in 0003)
backtrace_functions = '' (default)
backtrace_min_level = 'ERROR' (default)
and
log_backtrace = 'all'
backtrace_functions = 'someFunc'
backtrace_min_level = 'ERROR' (default)
4. I see the support for wildcard in backtrace_functions is missing.
Is it intentionally left out? If not, can you make it part of 0003
patch?
Yes it's intentional, see answer on 1.
5. The amount of backtraces generated is going to be too huge when
setting log_backtrace = 'all' and backtrace_min_level = 'debug5'. With
this setting installcheck generated 12MB worth of log and the test
took about 55 seconds (as opposed to 48 seconds without it) The point
is if these settings are misused, it can easily slow down the entire
system and fill up disk space leading to crashes eventually. This
makes a strong case for marking log_backtrace a developer only
function.
I think the same argument can be made for many other GUCs that are not
marked as developer options (e.g. log_min_messages). Normally we
"protect" such options by using PGC_SUSET. DEVELOPER_OPTIONS is really
only meant for options that are only useful for developers
6. In continuation to comment #5, does anyone need backtrace for
elevels like debugX and LOG etc.? What's the use of the backtrace in
such cases?
I think at least WARNING and NOTICE could be useful in practice, but I
agree LOG and DEBUGX seem kinda useless. But it seems kinda strange to
not have them in the list, especially given it is pretty much no
effort to support them too.
On Fri, 22 Mar 2024 at 11:09, Jelte Fennema-Nio <me@jeltef.nl> wrote:
On Thu, 21 Mar 2024 at 15:41, Jelte Fennema-Nio <me@jeltef.nl> wrote:
Attached is a patch that implements this. Since the more I think about
it, the more I like this approach.I now added a 3rd patch to this patchset which changes the
log_backtrace default to "internal", because it seems quite useful to
me if user error reports of internal errors included a backtrace.
I think patch 0002 should be considered an Open Item for PG17. Since
it's proposing changing the name of the newly introduced
backtrace_on_internal_error GUC. If we want to change it in this way,
we should do it before the release and preferably before the beta.
I added it to the Open Items list[1]https://wiki.postgresql.org/wiki/PostgreSQL_17_Open_Items so we don't forget to at least
decide on this.
[1]: https://wiki.postgresql.org/wiki/PostgreSQL_17_Open_Items
On Wed, Apr 10, 2024 at 11:07:00AM +0200, Jelte Fennema-Nio wrote:
I think patch 0002 should be considered an Open Item for PG17. Since
it's proposing changing the name of the newly introduced
backtrace_on_internal_error GUC. If we want to change it in this way,
we should do it before the release and preferably before the beta.
Indeed, it makes little sense to redesign this at the beginning of v18
if we're unhappy with the current outcome of v17. So tweaking that is
worth considering at this stage.
log_backtrace speaks a bit more to me as a name for this stuff because
it logs a backtrace. Now, there is consistency on HEAD as well
because these GUCs are all prefixed with "backtrace_". Would
something like a backtrace_mode where we have an enum rather than a
boolean be better? One thing would be to redesign the existing GUC as
having two values on HEAD as of:
- "none", to log nothing.
- "internal", to log backtraces for internal errors.
Then this could be extended with more modes, to discuss in future
releases as new features.
What you are suggesting with backtrace_min_level is an entirely new
feature. Perhaps using an extra GUC to control the interactions of
the modes that can be assigned to the primary GUC "log_backtrace" in
your 0002 is better, but all that sounds like v18 material at this
stage. The code that resolves the interactions between the existing
GUC and the new "level" GUC does not use LOGBACKTRACE_ALL. Perhaps it
should use a case/switch.
+ gettext_noop("Each level includes all the levels that follow it. The later"
+ " the level, the fewer backtraces are created."),
I added it to the Open Items list[1] so we don't forget to at least
decide on this.[1]: https://wiki.postgresql.org/wiki/PostgreSQL_17_Open_Items
Thanks.
--
Michael
On Fri, Apr 12, 2024 at 09:36:36AM +0900, Michael Paquier wrote:
log_backtrace speaks a bit more to me as a name for this stuff because
it logs a backtrace. Now, there is consistency on HEAD as well
because these GUCs are all prefixed with "backtrace_". Would
something like a backtrace_mode where we have an enum rather than a
boolean be better? One thing would be to redesign the existing GUC as
having two values on HEAD as of:
- "none", to log nothing.
- "internal", to log backtraces for internal errors.Then this could be extended with more modes, to discuss in future
releases as new features.
As this is an open item, let's move on here.
Attached is a proposal of patch for this open item, switching
backtrace_on_internal_error to backtrace_mode with two values:
- "none", to log no backtraces.
- "internal", to log backtraces for internal errors.
The rest of the proposals had better happen as a v18 discussion, where
extending this GUC is a benefit.
--
Michael
Attachments:
0001-backtrace_on_internal_error-backtrace_mode.patchtext/x-diff; charset=us-asciiDownload
From 348c3d45ddf4c29163c6963cb640c372fdbe72d5 Mon Sep 17 00:00:00 2001
From: Michael Paquier <michael@paquier.xyz>
Date: Thu, 18 Apr 2024 15:57:10 +0900
Subject: [PATCH] backtrace_on_internal_error -> backtrace_mode
This currently supports two values:
- "none", to log no backtraces.
- "internal", to log a backtrace with an internal error.
---
src/include/utils/elog.h | 6 ++++++
src/include/utils/guc.h | 2 +-
src/backend/utils/error/elog.c | 2 +-
src/backend/utils/misc/guc_tables.c | 33 +++++++++++++++++++----------
doc/src/sgml/config.sgml | 19 ++++++++++-------
src/tools/pgindent/typedefs.list | 1 +
6 files changed, 42 insertions(+), 21 deletions(-)
diff --git a/src/include/utils/elog.h b/src/include/utils/elog.h
index 054dd2bf62..b132f89e98 100644
--- a/src/include/utils/elog.h
+++ b/src/include/utils/elog.h
@@ -495,6 +495,12 @@ typedef enum
PGERROR_VERBOSE, /* all the facts, ma'am */
} PGErrorVerbosity;
+typedef enum
+{
+ BACKTRACE_MODE_NONE, /* no backtraces */
+ BACKTRACE_MODE_INTERNAL, /* backtraces for internal error code */
+} BacktraceMode;
+
extern PGDLLIMPORT int Log_error_verbosity;
extern PGDLLIMPORT char *Log_line_prefix;
extern PGDLLIMPORT int Log_destination;
diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h
index 8d1fe04078..53dd28222a 100644
--- a/src/include/utils/guc.h
+++ b/src/include/utils/guc.h
@@ -267,7 +267,7 @@ extern PGDLLIMPORT int log_temp_files;
extern PGDLLIMPORT double log_statement_sample_rate;
extern PGDLLIMPORT double log_xact_sample_rate;
extern PGDLLIMPORT char *backtrace_functions;
-extern PGDLLIMPORT bool backtrace_on_internal_error;
+extern PGDLLIMPORT int backtrace_mode;
extern PGDLLIMPORT int temp_file_limit;
diff --git a/src/backend/utils/error/elog.c b/src/backend/utils/error/elog.c
index 605ff3b045..1c108b86ec 100644
--- a/src/backend/utils/error/elog.c
+++ b/src/backend/utils/error/elog.c
@@ -501,7 +501,7 @@ errfinish(const char *filename, int lineno, const char *funcname)
backtrace_functions &&
matches_backtrace_functions(edata->funcname)) ||
(edata->sqlerrcode == ERRCODE_INTERNAL_ERROR &&
- backtrace_on_internal_error)))
+ backtrace_mode == BACKTRACE_MODE_INTERNAL)))
set_backtrace(edata, 2);
/*
diff --git a/src/backend/utils/misc/guc_tables.c b/src/backend/utils/misc/guc_tables.c
index c68fdc008b..d5a9f3b73e 100644
--- a/src/backend/utils/misc/guc_tables.c
+++ b/src/backend/utils/misc/guc_tables.c
@@ -79,6 +79,7 @@
#include "tsearch/ts_cache.h"
#include "utils/builtins.h"
#include "utils/bytea.h"
+#include "utils/elog.h"
#include "utils/float.h"
#include "utils/guc_hooks.h"
#include "utils/guc_tables.h"
@@ -117,6 +118,15 @@ extern bool optimize_bounded_sort;
* NOTE! Option values may not contain double quotes!
*/
+static const struct config_enum_entry backtrace_mode_options[] = {
+ {"none", BACKTRACE_MODE_NONE, false},
+ {"internal", BACKTRACE_MODE_INTERNAL, false},
+ {NULL, 0, false}
+};
+
+StaticAssertDecl(lengthof(backtrace_mode_options) == (BACKTRACE_MODE_INTERNAL + 2),
+ "array length mismatch");
+
static const struct config_enum_entry bytea_output_options[] = {
{"escape", BYTEA_OUTPUT_ESCAPE, false},
{"hex", BYTEA_OUTPUT_HEX, false},
@@ -531,7 +541,7 @@ int log_temp_files = -1;
double log_statement_sample_rate = 1.0;
double log_xact_sample_rate = 0;
char *backtrace_functions;
-bool backtrace_on_internal_error = false;
+int backtrace_mode = BACKTRACE_MODE_NONE;
int temp_file_limit = -1;
@@ -770,16 +780,6 @@ StaticAssertDecl(lengthof(config_type_names) == (PGC_ENUM + 1),
struct config_bool ConfigureNamesBool[] =
{
- {
- {"backtrace_on_internal_error", PGC_SUSET, DEVELOPER_OPTIONS,
- gettext_noop("Log backtrace for any error with error code XX000 (internal error)."),
- NULL,
- GUC_NOT_IN_SAMPLE
- },
- &backtrace_on_internal_error,
- false,
- NULL, NULL, NULL
- },
{
{"enable_seqscan", PGC_USERSET, QUERY_TUNING_METHOD,
gettext_noop("Enables the planner's use of sequential-scan plans."),
@@ -4745,6 +4745,17 @@ struct config_enum ConfigureNamesEnum[] =
NULL, NULL, NULL
},
+ {
+ {"backtrace_mode", PGC_SUSET, DEVELOPER_OPTIONS,
+ gettext_noop("Controls backtrace logging."),
+ NULL,
+ GUC_NOT_IN_SAMPLE
+ },
+ &backtrace_mode,
+ BACKTRACE_MODE_NONE, backtrace_mode_options,
+ NULL, NULL, NULL
+ },
+
{
{"bytea_output", PGC_USERSET, CLIENT_CONN_STATEMENT,
gettext_noop("Sets the output format for bytea."),
diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
index d8e1282e12..b9a317b15d 100644
--- a/doc/src/sgml/config.sgml
+++ b/doc/src/sgml/config.sgml
@@ -11381,19 +11381,22 @@ dynamic_library_path = 'C:\tools\postgresql;H:\my_project\lib;$libdir'
</listitem>
</varlistentry>
- <varlistentry id="guc-backtrace-on-internal-error" xreflabel="backtrace_on_internal_error">
- <term><varname>backtrace_on_internal_error</varname> (<type>boolean</type>)
+ <varlistentry id="guc-backtrace-mode" xreflabel="backtrace_mode">
+ <term><varname>backtrace_mode</varname> (<type>enum</type>)
<indexterm>
- <primary><varname>backtrace_on_internal_error</varname> configuration parameter</primary>
+ <primary><varname>backtrace_mode</varname> configuration parameter</primary>
</indexterm>
</term>
<listitem>
<para>
- If this parameter is on and an error with error code XX000 (internal
- error; see also <xref linkend="errcodes-appendix"/>) is raised, then a
- backtrace is written to the server log together with the error
- message. This can be used to debug such internal errors (which should
- normally not happen in production). The default is off.
+ Controls how backtraces should be logged.
+ If this parameter is <literal>internal</literal> and an error
+ with error code XX000 (internal error; see also
+ <xref linkend="errcodes-appendix"/>) is raised, then a backtrace
+ is written to the server log together with the error message.
+ This can be used to debug such internal errors (which should
+ normally not happen in production). The default is
+ <literal>none</literal>, to not log backtraces.
</para>
<para>
diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list
index d551ada325..6119a5afb3 100644
--- a/src/tools/pgindent/typedefs.list
+++ b/src/tools/pgindent/typedefs.list
@@ -240,6 +240,7 @@ BackgroundWorker
BackgroundWorkerArray
BackgroundWorkerHandle
BackgroundWorkerSlot
+BacktraceMode
BackupState
Barrier
BaseBackupCmd
--
2.43.0
On 18.04.24 09:02, Michael Paquier wrote:
On Fri, Apr 12, 2024 at 09:36:36AM +0900, Michael Paquier wrote:
log_backtrace speaks a bit more to me as a name for this stuff because
it logs a backtrace. Now, there is consistency on HEAD as well
because these GUCs are all prefixed with "backtrace_". Would
something like a backtrace_mode where we have an enum rather than a
boolean be better? One thing would be to redesign the existing GUC as
having two values on HEAD as of:
- "none", to log nothing.
- "internal", to log backtraces for internal errors.Then this could be extended with more modes, to discuss in future
releases as new features.As this is an open item, let's move on here.
Attached is a proposal of patch for this open item, switching
backtrace_on_internal_error to backtrace_mode with two values:
- "none", to log no backtraces.
- "internal", to log backtraces for internal errors.The rest of the proposals had better happen as a v18 discussion, where
extending this GUC is a benefit.
Why exactly is this an open item? Is there anything wrong with the
existing feature?
On Thu, 18 Apr 2024 at 10:50, Peter Eisentraut <peter@eisentraut.org> wrote:
Why exactly is this an open item? Is there anything wrong with the
existing feature?
The name of the GUC backtrace_on_internal_error is so specific that
it's impossible to extend our backtrace behaviour in future releases
without adding yet another backtrace GUC. You started the discussion
on renaming it upthread:
Show quoted text
On Fri, 8 Mar 2024 at 15:51, Peter Eisentraut <peter@eisentraut.org> wrote:
What is the relationship of these changes with the recently added
backtrace_on_internal_error? We had similar discussions there, I feel
like we are doing similar things here but slightly differently. Like,
shouldn't backtrace_functions_min_level also affect
backtrace_on_internal_error? Don't you really just want
backtrace_on_any_error? You are sneaking that in through the backdoor
via backtrace_functions. Can we somehow combine all these use cases
more elegantly? backtrace_on_error = {all|internal|none}?
On Thu, 18 Apr 2024 at 09:02, Michael Paquier <michael@paquier.xyz> wrote:
On Fri, Apr 12, 2024 at 09:36:36AM +0900, Michael Paquier wrote:
log_backtrace speaks a bit more to me as a name for this stuff because
it logs a backtrace. Now, there is consistency on HEAD as well
because these GUCs are all prefixed with "backtrace_". Would
something like a backtrace_mode where we have an enum rather than a
boolean be better?
I guess it depends what we want consistency with. If we want naming
consistency with all other LOGGING_WHAT GUCs or if we want naming
consistency with the current backtrace_functions GUC. I personally
like log_backtrace slightly better, but I don't have a super strong
opinion on this either. Another option could be plain "backtrace".
One thing would be to redesign the existing GUC as
having two values on HEAD as of:
- "none", to log nothing.
- "internal", to log backtraces for internal errors.
If we go for backtrace_mode or backtrace, then I think I'd prefer
"disabled"/"off" and "internal_error" for these values.
The rest of the proposals had better happen as a v18 discussion, where
extending this GUC is a benefit.
agreed
On Thu, Apr 18, 2024 at 12:21:56PM +0200, Jelte Fennema-Nio wrote:
On Thu, 18 Apr 2024 at 09:02, Michael Paquier <michael@paquier.xyz> wrote:
On Fri, Apr 12, 2024 at 09:36:36AM +0900, Michael Paquier wrote:
log_backtrace speaks a bit more to me as a name for this stuff because
it logs a backtrace. Now, there is consistency on HEAD as well
because these GUCs are all prefixed with "backtrace_". Would
something like a backtrace_mode where we have an enum rather than a
boolean be better?I guess it depends what we want consistency with. If we want naming
consistency with all other LOGGING_WHAT GUCs or if we want naming
consistency with the current backtrace_functions GUC. I personally
like log_backtrace slightly better, but I don't have a super strong
opinion on this either. Another option could be plain "backtrace".
"backtrace" is too generic IMO. I'd append a "mode" as an effect of
backtrace_functions, which is also a developer option, and has been
around for a couple of releases now.
One thing would be to redesign the existing GUC as
having two values on HEAD as of:
- "none", to log nothing.
- "internal", to log backtraces for internal errors.If we go for backtrace_mode or backtrace, then I think I'd prefer
"disabled"/"off" and "internal_error" for these values.
"internal_error" as a value sounds fine to me, that speaks more than
just "internal". "off" rather that "none" or "disabled", less so,
because it requires more enum entries to map with the boolean values
that could be expected from it. "disabled" would be mostly a first in
the GUCs, icu_validation_level being the first one using it, so I'd
rather choose "none" over "disabled". No strong preference on this
one, TBH, but as we're bike-shedding that..
--
Michael
On 18.04.24 11:54, Jelte Fennema-Nio wrote:
On Thu, 18 Apr 2024 at 10:50, Peter Eisentraut<peter@eisentraut.org> wrote:
Why exactly is this an open item? Is there anything wrong with the
existing feature?The name of the GUC backtrace_on_internal_error is so specific that
it's impossible to extend our backtrace behaviour in future releases
without adding yet another backtrace GUC. You started the discussion
on renaming it upthread:
This presupposes that there is consensus about how the future
functionality should look like. This topic has gone through half a
dozen designs over a few months, and I think it would be premature to
randomly freeze that discussion now and backport that design.
If a better, more comprehensive design arises for PG18, I think it would
be pretty easy to either remove backtrace_on_internal_error or just
internally remap it.
On Fri, 19 Apr 2024 at 10:58, Peter Eisentraut <peter@eisentraut.org> wrote:
This presupposes that there is consensus about how the future
functionality should look like. This topic has gone through half a
dozen designs over a few months, and I think it would be premature to
randomly freeze that discussion now and backport that design.
While there maybe isn't consensus on what a new design exactly looks
like, I do feel like there's consensus on this thread that the
backtrace_on_internal_error GUC is almost certainly not the design
that we want. I guess a more conservative approach to this problem
would be to revert the backtrace_on_internal_error commit and agree on
a better design for PG18. But I didn't think that would be necessary
if we could agree on the name for a more flexibly named GUC, which
seemed quite possible to me (after a little bit of bikeshedding).
If a better, more comprehensive design arises for PG18, I think it would
be pretty easy to either remove backtrace_on_internal_error or just
internally remap it.
I think releasing a GUC (even if it's just meant for developers) in
PG17 and then deprecating it for a newer version in PG18 wouldn't be a
great look. And even if that's not a huge problem, it still seems
better not to have the problem at all. Renaming the GUC now seems to
have only upsides to me: worst case the new design turns out not to be
what we want either, and we have to deprecate the GUC. But in the best
case we don't need to deprecate anything.
On Thu, Apr 18, 2024 at 3:02 AM Michael Paquier <michael@paquier.xyz> wrote:
As this is an open item, let's move on here.
Attached is a proposal of patch for this open item, switching
backtrace_on_internal_error to backtrace_mode with two values:
- "none", to log no backtraces.
- "internal", to log backtraces for internal errors.The rest of the proposals had better happen as a v18 discussion, where
extending this GUC is a benefit.
-1. That's just weird. There's no reason to replace a Boolean with a
non-Boolean without adding a third value. Either we decide this
concern is important enough to justify a post-feature-freeze design
change, and add the third value now, or we leave it alone and revisit
it in a future release. I'm probably OK with either one, but being
halfway in between has no appeal for me.
--
Robert Haas
EDB: http://www.enterprisedb.com
On Fri, Apr 19, 2024 at 7:31 AM Jelte Fennema-Nio <me@jeltef.nl> wrote:
While there maybe isn't consensus on what a new design exactly looks
like, I do feel like there's consensus on this thread that the
backtrace_on_internal_error GUC is almost certainly not the design
that we want. I guess a more conservative approach to this problem
would be to revert the backtrace_on_internal_error commit and agree on
a better design for PG18. But I didn't think that would be necessary
if we could agree on the name for a more flexibly named GUC, which
seemed quite possible to me (after a little bit of bikeshedding).
I think Peter is correct that this presupposes we more or less agree
on the final destination. For example, I think that log_backtrace =
error | internal | all is a bit odd; why not backtrace_errcodes =
<comma-separated list of error codes>? I've written a logging hook for
EDB that can filter out error messages by error code, so I don't think
it's at all a stretch to think that someone might want to do something
similar here. I agree that it's somewhat likely that the name we want
going forward isn't backtrace_on_internal_error, but I don't think we
know that completely for certain, or what new name we necessarily
want.
I think releasing a GUC (even if it's just meant for developers) in
PG17 and then deprecating it for a newer version in PG18 wouldn't be a
great look. And even if that's not a huge problem, it still seems
better not to have the problem at all. Renaming the GUC now seems to
have only upsides to me: worst case the new design turns out not to be
what we want either, and we have to deprecate the GUC. But in the best
case we don't need to deprecate anything.
There are some things that are pretty hard to change once we've
released them. For example, if we had a function or operator and
somebody embeds it in a view definition, removing or renaming it
prevents people from upgrading. But GUCs are not as bad. If you don't
port your postgresql.conf forward to the new version, or if you
haven't uncommented this particular setting, then there's no issue at
all, and when there is a problem, removing a GUC setting from
postgresql.conf is pretty straightforward compared to getting some
construct out of your application code. I agree it's not amazing if we
end up changing this exactly one release after it was introduced, but
we don't really know that we're going to change it next release, or at
all, and even if we do, I still don't think that's a catastrophe.
I'm not completely certain that "let's just leave this alone for right
now" is the correct conclusion, but the fact that we might need to
rename a GUC down the road is not, by itself, a critical flaw in the
status quo.
--
Robert Haas
EDB: http://www.enterprisedb.com
Robert Haas <robertmhaas@gmail.com> writes:
There are some things that are pretty hard to change once we've
released them. For example, if we had a function or operator and
somebody embeds it in a view definition, removing or renaming it
prevents people from upgrading. But GUCs are not as bad.
Really? Are we certain that nobody will put SETs of this GUC
into their applications, or even just activate it via ALTER DATABASE
SET? If they've done that, then a GUC change means dump/reload/upgrade
failure.
I've not been following this thread, so I don't have an opinion
about what the design ought to be. But if we still aren't settled
on it by now, I think the prudent thing is to revert the feature
out of v17 altogether, and try again in v18. When we're still
designing something after feature freeze, that is a good indication
that we are trying to ship something that's not ready for prime time.
regards, tom lane
On Fri, Apr 19, 2024 at 2:08 PM Tom Lane <tgl@sss.pgh.pa.us> wrote:
Robert Haas <robertmhaas@gmail.com> writes:
There are some things that are pretty hard to change once we've
released them. For example, if we had a function or operator and
somebody embeds it in a view definition, removing or renaming it
prevents people from upgrading. But GUCs are not as bad.Really? Are we certain that nobody will put SETs of this GUC
into their applications, or even just activate it via ALTER DATABASE
SET? If they've done that, then a GUC change means dump/reload/upgrade
failure.
That's fair. That feature isn't super-widely used, but it wouldn't be
crazy for someone to use it with this feature, either.
I've not been following this thread, so I don't have an opinion
about what the design ought to be. But if we still aren't settled
on it by now, I think the prudent thing is to revert the feature
out of v17 altogether, and try again in v18. When we're still
designing something after feature freeze, that is a good indication
that we are trying to ship something that's not ready for prime time.
There are two features at issue here. One is
backtrace_on_internal_error, committed as
a740b213d4b4d3360ad0cac696e47e5ec0eb8864. The other is a feature to
produce backtraces for all errors, which was originally proposed as
backtrace_functions='*', backtrace_functions_level=ERROR but which has
subsequently been proposed with a few other spellings that involve
merging that functionality into backtrace_on_internal_error. To the
extent that there's an open question here for PG17, it's not about
reverting this patch (which AIUI has never been committed) but about
reverting the earlier patch for backtrace_on_internal_error. So is
that the right thing to do?
Well, on the one hand, I confess to having had a passing thought that
backtrace_on_internal_error is awfully specific. Surely, user A's
criterion for which messages should have backtraces might be anything,
and we cannot reasonably add backtrace_on_$WHATEVER for all $WHATEVER
in some large set. And the debate here suggests that I wasn't the only
one to have that concern. So that argues for a revert.
But on the other hand, in my personal experience,
backtrace_on_internal_error would be the right thing in a really large
number of cases. I was disappointed to see it added as a developer
option with GUC_NOT_IN_SAMPLE. My vote would have been to put it in
postgresql.conf and enable it by default. We have a somewhat debatable
habit of using the exact same message in many places with similar
kinds of problems, and when a production system manages to hit one of
those errors, figuring out what actually went wrong is hard. In fact,
it's often hard even when the error text only occurs in one or two
places, because it's often some very low-level part of the code where
you can't get enough context to understand the problem without knowing
where that code got called from. So I sort of hate to see one of the
most useful extensions of backtrace functionality that I can
personally imagine get pulled back out of the tree because it turns
out that someone else has something else that they want.
I wonder whether a practical solution here might be to replace
backtrace_on_internal_error=true|false with
backtrace_on_error=true|internal|false. (Yes, I know that more
proposed resolutions is not necessarily what we need right now, but I
can't resist floating the idea.)
--
Robert Haas
EDB: http://www.enterprisedb.com
Robert Haas <robertmhaas@gmail.com> writes:
On Fri, Apr 19, 2024 at 2:08 PM Tom Lane <tgl@sss.pgh.pa.us> wrote:
I've not been following this thread, so I don't have an opinion
about what the design ought to be. But if we still aren't settled
on it by now, I think the prudent thing is to revert the feature
out of v17 altogether, and try again in v18. When we're still
designing something after feature freeze, that is a good indication
that we are trying to ship something that's not ready for prime time.
There are two features at issue here. One is
backtrace_on_internal_error, committed as
a740b213d4b4d3360ad0cac696e47e5ec0eb8864. The other is a feature to
produce backtraces for all errors, which was originally proposed as
backtrace_functions='*', backtrace_functions_level=ERROR but which has
subsequently been proposed with a few other spellings that involve
merging that functionality into backtrace_on_internal_error. To the
extent that there's an open question here for PG17, it's not about
reverting this patch (which AIUI has never been committed) but about
reverting the earlier patch for backtrace_on_internal_error. So is
that the right thing to do?
I can't say that I care for "backtrace_on_internal_error".
Re-reading that thread, I see I argued for having *no* GUC and
just enabling that behavior all the time. I lost that fight,
but it should have been clear that a GUC of this exact shape
is a design dead end --- and that's what we're seeing now.
Well, on the one hand, I confess to having had a passing thought that
backtrace_on_internal_error is awfully specific. Surely, user A's
criterion for which messages should have backtraces might be anything,
and we cannot reasonably add backtrace_on_$WHATEVER for all $WHATEVER
in some large set. And the debate here suggests that I wasn't the only
one to have that concern. So that argues for a revert.
Exactly.
But on the other hand, in my personal experience,
backtrace_on_internal_error would be the right thing in a really large
number of cases.
That's why I thought we could get away with doing it automatically.
Sure, more control would be better. But if we just hard-wire it for
the moment then we aren't locking in what the eventual design for
that control will be.
regards, tom lane
On Fri, Apr 19, 2024 at 3:24 PM Tom Lane <tgl@sss.pgh.pa.us> wrote:
I can't say that I care for "backtrace_on_internal_error".
Re-reading that thread, I see I argued for having *no* GUC and
just enabling that behavior all the time. I lost that fight,
but it should have been clear that a GUC of this exact shape
is a design dead end --- and that's what we're seeing now.
Yeah, I guess I have to agree with that.
But on the other hand, in my personal experience,
backtrace_on_internal_error would be the right thing in a really large
number of cases.That's why I thought we could get away with doing it automatically.
Sure, more control would be better. But if we just hard-wire it for
the moment then we aren't locking in what the eventual design for
that control will be.
So the question before us right now is whether there's a palatable
alternative to completely ripping out a feature that both you and I
seem to agree does something useful. I don't think we necessarily need
to leap to the conclusion that a revert is radically less risky than
some other alternative. Now, if there's not some obvious alternative
upon which we can (mostly) all agree, then maybe that's where we end
up. But I would like us to be looking to save the features we can.
--
Robert Haas
EDB: http://www.enterprisedb.com
On Fri, Apr 19, 2024 at 04:17:18PM -0400, Robert Haas wrote:
On Fri, Apr 19, 2024 at 3:24 PM Tom Lane <tgl@sss.pgh.pa.us> wrote:
I can't say that I care for "backtrace_on_internal_error".
Re-reading that thread, I see I argued for having *no* GUC and
just enabling that behavior all the time. I lost that fight,
but it should have been clear that a GUC of this exact shape
is a design dead end --- and that's what we're seeing now.Yeah, I guess I have to agree with that.
Ah, I have missed this argument.
So the question before us right now is whether there's a palatable
alternative to completely ripping out a feature that both you and I
seem to agree does something useful. I don't think we necessarily need
to leap to the conclusion that a revert is radically less risky than
some other alternative. Now, if there's not some obvious alternative
upon which we can (mostly) all agree, then maybe that's where we end
up. But I would like us to be looking to save the features we can.
Removing this GUC and making the backend react by default the same way
as when this GUC was enabled sounds like a sensible route here. This
stuff is useful.
--
Michael
On 19.04.24 21:24, Tom Lane wrote:
But on the other hand, in my personal experience,
backtrace_on_internal_error would be the right thing in a really large
number of cases.That's why I thought we could get away with doing it automatically.
Sure, more control would be better. But if we just hard-wire it for
the moment then we aren't locking in what the eventual design for
that control will be.
Note that a standard test run produces a number of internal errors. I
haven't checked how likely these are in production, but one might want
to consider that before starting to dump backtraces in routine situations.
For example,
$ PG_TEST_INITDB_EXTRA_OPTS='-c backtrace_on_internal_error=on' meson
test -C build
$ grep -r 'BACKTRACE:' build/testrun | wc -l
85
On Sat, 20 Apr 2024 at 01:19, Michael Paquier <michael@paquier.xyz> wrote:
Removing this GUC and making the backend react by default the same way
as when this GUC was enabled sounds like a sensible route here. This
stuff is useful.
I definitely agree it's useful. But I feel like changing the default
of the GUC and removing the ability to disable it at the same time are
pretty radical changes that we should not be doing after a feature
freeze. I think we should at least have a way to turn this feature off
to be able to avoid log spam. Especially given the fact that
extensions use elog much more freely than core. Which afaict from
other threads[1]/messages/by-id/524751.1707240550@sss.pgh.pa.us Tom also thinks we should normally be careful about.
Of the options to resolve the open item so far, I think there are only
three somewhat reasonable to do after the feature freeze:
1. Rename the GUC to something else (but keep behaviour the same)
2. Decide to keep the GUC as is
3. Revert a740b213d4
I hoped 1 was possible, but based on the discussion so far it doesn't
seem like we'll be able to get a quick agreement on a name. IMHO 2 is
just a version of 1, but with a GUC name that no-one thinks is a good
one. So I think we are left with option 3.
On Sun, Apr 21, 2024 at 09:26:38AM +0200, Peter Eisentraut wrote:
Note that a standard test run produces a number of internal errors. I
haven't checked how likely these are in production, but one might want to
consider that before starting to dump backtraces in routine situations.For example,
$ PG_TEST_INITDB_EXTRA_OPTS='-c backtrace_on_internal_error=on' meson test
-C build
$ grep -r 'BACKTRACE:' build/testrun | wc -l
85
Ugh, I would not have expected that much. Isn't the problem you are
reporting here entirely unrelated, though? It seems to me that these
error paths should be using a proper errcode rather than the internal
errcode, as these refer to states that can be reached by the user with
a combination of queries and/or cancellations.
For example, take this one for the REFRESH matview path which is a
valid error, still using an elog():
if (!foundUniqueIndex)
elog(ERROR, "could not find suitable unique index on materialized view");
I'd like to think about this stuff in a different way: this is useful
if enabled by default because it can also help in finding out error
paths that should not use the internal errcode. Normally, there
should be zero backtraces produced, except in unexpected
never-to-be-reached cases.
--
Michael
On Mon, Apr 22, 2024 at 2:36 AM Michael Paquier <michael@paquier.xyz> wrote:
I'd like to think about this stuff in a different way: this is useful
if enabled by default because it can also help in finding out error
paths that should not use the internal errcode. Normally, there
should be zero backtraces produced, except in unexpected
never-to-be-reached cases.
That's long been my feeling about this. So, if we revert this for now,
what we ought to do is put it back right ASAP after feature freeze and
then clean all that up.
--
Robert Haas
EDB: http://www.enterprisedb.com
On Mon, Apr 22, 2024 at 09:25:15AM -0400, Robert Haas wrote:
That's long been my feeling about this. So, if we revert this for now,
what we ought to do is put it back right ASAP after feature freeze and
then clean all that up.
In the 85 backtraces I can find in the tests, we have a mixed bag of:
- Code paths that use the internal errcode, but should not.
- Code paths that use the internal errcode, and are OK with that in
the scope of the tests.
- Code paths that use the internal errcode, though the coding
assumptions behind their use feels fuzzy to me, like amcheck for some
SQL tests or satisfies_hash_partition() in one SQL test.
As cleaning up that is a separate topic, I have begun a new thread and
with a full analysis of everything I've spotted. See here:
/messages/by-id/Zic_GNgos5sMxKoa@paquier.xyz
The first class of issues refers to real problems, and should be
assigned errcodes. Having a way to switch the backtraces off can have
some benefits in the second cases. However, even if we silence them,
it would also mean to miss backtraces that could be legit. The third
cases would require a different analysis, behind the designs of the
code paths able to trigger the internal codes.
At this stage, my opinion would tend in favor of a revert of the GUC.
The second class of cases is useful to stress many unexpected cases,
and I don't expect this number to go down over time, but increase with
more advanced tests added into core (I/O failures with partial writes
for availability, etc).
--
Michael
On Tue, Apr 23, 2024 at 1:05 AM Michael Paquier <michael@paquier.xyz> wrote:
At this stage, my opinion would tend in favor of a revert of the GUC.
The second class of cases is useful to stress many unexpected cases,
and I don't expect this number to go down over time, but increase with
more advanced tests added into core (I/O failures with partial writes
for availability, etc).
All right. I think there is a consensus in favor of reverting
a740b213d4b4d3360ad0cac696e47e5ec0eb8864. Maybe not an absolutely
iron-clad consensus, but there are a couple of votes explicitly in
favor of that course of action and the other votes seem to mostly be
of the form "well, reverting is ONE option."
Peter?
--
Robert Haas
EDB: http://www.enterprisedb.com
Hi,
On 2024-04-19 15:24:17 -0400, Tom Lane wrote:
I can't say that I care for "backtrace_on_internal_error".
Re-reading that thread, I see I argued for having *no* GUC and
just enabling that behavior all the time. I lost that fight,
but it should have been clear that a GUC of this exact shape
is a design dead end --- and that's what we're seeing now.
I don't think enabling backtraces without a way to disable them is a good idea
- security vulnerablilities in backtrace generation code are far from unheard
of and can make error handling a lot slower...
Greetings,
Andres Freund
Andres Freund <andres@anarazel.de> writes:
I don't think enabling backtraces without a way to disable them is a good idea
- security vulnerablilities in backtrace generation code are far from unheard
of and can make error handling a lot slower...
Well, in that case we have to have some kind of control GUC, and
I think the consensus is that the one we have now is under-designed.
So I also vote for a full revert and try again in v18.
regards, tom lane
On 2024-04-26 14:39:16 -0400, Tom Lane wrote:
Andres Freund <andres@anarazel.de> writes:
I don't think enabling backtraces without a way to disable them is a good idea
- security vulnerablilities in backtrace generation code are far from unheard
of and can make error handling a lot slower...Well, in that case we have to have some kind of control GUC, and
I think the consensus is that the one we have now is under-designed.
So I also vote for a full revert and try again in v18.
Yea, makes sense. I just wanted to point out that some level of control is
needed, not say that what we have now is right.
On Fri, Apr 26, 2024 at 02:39:16PM -0400, Tom Lane wrote:
Well, in that case we have to have some kind of control GUC, and
I think the consensus is that the one we have now is under-designed.
So I also vote for a full revert and try again in v18.
Okay, fine by me to move on with a revert.
--
Michael
On 27.04.24 00:16, Michael Paquier wrote:
On Fri, Apr 26, 2024 at 02:39:16PM -0400, Tom Lane wrote:
Well, in that case we have to have some kind of control GUC, and
I think the consensus is that the one we have now is under-designed.
So I also vote for a full revert and try again in v18.Okay, fine by me to move on with a revert.
Ok, it's reverted.
On Mon, Apr 29, 2024 at 5:12 AM Peter Eisentraut <peter@eisentraut.org> wrote:
On 27.04.24 00:16, Michael Paquier wrote:
On Fri, Apr 26, 2024 at 02:39:16PM -0400, Tom Lane wrote:
Well, in that case we have to have some kind of control GUC, and
I think the consensus is that the one we have now is under-designed.
So I also vote for a full revert and try again in v18.Okay, fine by me to move on with a revert.
Ok, it's reverted.
Thanks, and sorry. :-(
--
Robert Haas
EDB: http://www.enterprisedb.com
On Mon, Apr 29, 2024 at 08:08:19AM -0400, Robert Haas wrote:
On Mon, Apr 29, 2024 at 5:12 AM Peter Eisentraut <peter@eisentraut.org> wrote:
Ok, it's reverted.
Thanks for taking care of it.
Thanks, and sorry. :-(
Sorry for the outcome..
--
Michael
Hi,
This patch is currently parked in the July CommitFest:
https://commitfest.postgresql.org/48/4735/
That's fine, except that I think that what the previous discussion
revealed is that we don't have consensus on how backtrace behavior
ought to be controlled: backtrace_on_internal_error was one proposal,
and this was a competing proposal, and neither one of them seemed to
be completely satisfactory. If we don't forge a consensus on what a
hypothetical patch ought to do, any particular actual patch is
probably doomed. So I would suggest that the effort ought to be
deciding what kind of design would be generally acceptable -- and that
need not wait for July, nor should it, if the goal is to get something
committed in July.
...Robert
On Wed, 15 May 2024 at 20:31, Robert Haas <robertmhaas@gmail.com> wrote:
That's fine, except that I think that what the previous discussion
revealed is that we don't have consensus on how backtrace behavior
ought to be controlled: backtrace_on_internal_error was one proposal,
and this was a competing proposal, and neither one of them seemed to
be completely satisfactory.
Attached is a rebased patchset of my previous proposal, including a
few changes that Michael preferred:
1. Renames log_backtrace to log_backtrace_mode
2. Rename internal to internal_error
I reread the thread since I previously posted the patch and apart from
Michaels feedback I don't think there was any more feedback on the
current proposal.
Rethinking about it myself though, I think the main downside of this
proposal is that if you want the previous behaviour of
backtrace_functions (add backtraces to all elog/ereports in the given
functions) you now need to set three GUCs:
log_backtrace_mode='all'
backtrace_functions='some_func'
backtrace_min_level=DEBUG5
The third one is not needed in the common case where someone only
cares about errors, but still needing to set log_backtrace_mode='all'
might seem a bit annoying. One way around that would be to make
log_backtrace_mode and backtrace_functions be additive instead of
subtractive.
Personally I think the proposed subtractive nature would be exactly
what I want for backtraces I'm interested in. Because I would want to
use backtrace_functions in this way:
1. I see an error I want a backtrace of: et log_backtrace_mode='all'
and try to trigger again.
2. Oops, there's many backtraces now let's filter by function: set
backtrace_functions=some_func
So if it's additive, I'd have to also undo log_backtrace_mode='all'
again at step 2. So changing two GUCs instead of one to do what I
want.
Attachments:
0001-Add-PGErrorVerbosity-to-typedefs.list.patchapplication/x-patch; name=0001-Add-PGErrorVerbosity-to-typedefs.list.patchDownload
From 85a894cc32381a4ff2a1c7aab31476b2bbf6bdf3 Mon Sep 17 00:00:00 2001
From: Jelte Fennema-Nio <jelte.fennema@microsoft.com>
Date: Thu, 21 Mar 2024 13:05:35 +0100
Subject: [PATCH 1/2] Add PGErrorVerbosity to typedefs.list
This one was missing, resulting in some strange alignment.
---
src/include/utils/elog.h | 2 +-
src/tools/pgindent/typedefs.list | 1 +
2 files changed, 2 insertions(+), 1 deletion(-)
diff --git a/src/include/utils/elog.h b/src/include/utils/elog.h
index 054dd2bf62f..da1a7469fa5 100644
--- a/src/include/utils/elog.h
+++ b/src/include/utils/elog.h
@@ -493,7 +493,7 @@ typedef enum
PGERROR_TERSE, /* single-line error messages */
PGERROR_DEFAULT, /* recommended style */
PGERROR_VERBOSE, /* all the facts, ma'am */
-} PGErrorVerbosity;
+} PGErrorVerbosity;
extern PGDLLIMPORT int Log_error_verbosity;
extern PGDLLIMPORT char *Log_line_prefix;
diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list
index 61ad417cde6..67ec5408a98 100644
--- a/src/tools/pgindent/typedefs.list
+++ b/src/tools/pgindent/typedefs.list
@@ -1778,6 +1778,7 @@ PGAsyncStatusType
PGCALL2
PGChecksummablePage
PGContextVisibility
+PGErrorVerbosity
PGEvent
PGEventConnDestroy
PGEventConnReset
base-commit: 3e53492aa7084bceaa92757c90e067d79768797e
--
2.34.1
0002-Allow-logging-backtraces-in-more-cases.patchapplication/x-patch; name=0002-Allow-logging-backtraces-in-more-cases.patchDownload
From 9a1256aa3e4f585e3f588122662050f2302585dc Mon Sep 17 00:00:00 2001
From: Jelte Fennema-Nio <jelte.fennema@microsoft.com>
Date: Thu, 27 Jun 2024 10:56:10 +0200
Subject: [PATCH 2/2] Allow logging backtraces in more cases
We previously only had the backtrace_functions GUC to control when
backtraces were logged. Based on mailinglist discussion there were two
common cases that people wanted backtraces that were not covered by this
GUC though:
1. Logging backtraces for all internal errors
2. Logging backtraces for all errors
To support those two usecases, as well as to allow users to continue to
log backtraces for specific warnings using `backtrace_functions`, this
modifies the GUCs in the following way:
1. Adds a `log_backtrace` GUC, which can be set to `none` (default),
`internal_error` and `all` to log different types of backtraces.
2. Change `backtrace_functions` to behave as an additional filter on top
of `log_backtrace`. The empty string (the default) is now interpreted
as doing no filtering based on function name.
3. Add a `backtrace_min_level` GUC, which limits for which log entries
backtraces are written, based on their log level. This defaults to
ERROR.
This does mean that setting `backtrace_functions=some_func` alone is not
enough to get backtraces for some_func. You now need to combine that
with `log_backtrace_mode=all` and if you want to get backtraces for
non-errors (which you previously got), you also need to change
backtrace_min_level to whichever level you want backtraces for.
---
doc/src/sgml/config.sgml | 82 +++++++++++++++++--
src/backend/utils/error/elog.c | 30 ++++++-
src/backend/utils/misc/guc_tables.c | 50 +++++++++++
src/backend/utils/misc/postgresql.conf.sample | 1 +
src/include/utils/elog.h | 8 ++
src/include/utils/guc.h | 1 +
src/tools/pgindent/typedefs.list | 1 +
7 files changed, 162 insertions(+), 11 deletions(-)
diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
index 0c7a9082c54..ff2222ef79c 100644
--- a/doc/src/sgml/config.sgml
+++ b/doc/src/sgml/config.sgml
@@ -7283,6 +7283,44 @@ local0.* /var/log/postgresql
</listitem>
</varlistentry>
+ <varlistentry id="guc-log-backtrace-mode" xreflabel="log_backtrace_mode">
+ <term><varname>log_backtrace_mode</varname> (<type>boolean</type>)
+ <indexterm>
+ <primary><varname>log_backtrace_mode</varname> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ If this parameter is set to <literal>all</literal> then for all log
+ entries a backtrace is written to the server log together with the log
+ message. If this parameter is set to <literal>internal_error</literal> then
+ such a backtrace is only written for logs with error code XX000
+ (internal error; see also <xref linkend="errcodes-appendix"/>).
+ This can be used to debug such internal errors (which should normally
+ not happen in production). Finally, if this parameter is set to
+ <literal>none</literal> (the default), no backtraces are ever written
+ to the server log.
+ </para>
+
+ <para>
+ The logs for which a backtrace is written can be further restricted
+ using <xref linkend="guc-backtrace-min-level"/> (default:
+ <literal>ERROR</literal>) and <xref linkend="guc-backtrace-functions"/>
+ (default: empty string, meaning all).
+ </para>
+
+ <para>
+ Backtrace support is not available on all platforms, and the quality
+ of the backtraces depends on compilation options.
+ </para>
+
+ <para>
+ Only superusers and users with the appropriate <literal>SET</literal>
+ privilege can change this setting.
+ </para>
+ </listitem>
+ </varlistentry>
+
<varlistentry id="guc-log-checkpoints" xreflabel="log_checkpoints">
<term><varname>log_checkpoints</varname> (<type>boolean</type>)
<indexterm>
@@ -11372,16 +11410,45 @@ dynamic_library_path = 'C:\tools\postgresql;H:\my_project\lib;$libdir'
</term>
<listitem>
<para>
- This parameter contains a comma-separated list of C function names.
- If an error is raised and the name of the internal C function where
- the error happens matches a value in the list, then a backtrace is
- written to the server log together with the error message. This can
- be used to debug specific areas of the source code.
+ This parameter can contain a comma-separated list of C function names,
+ which can be used to filter for which logs a backtrace is written to
+ the server log.
+ If a log entry is raised and the name of the
+ internal C function where the error happens does not match any of the
+ values in the list, then no backtrace is written to the server log.
+ This can be used to only debug specific areas of the source code.
</para>
<para>
- Backtrace support is not available on all platforms, and the quality
- of the backtraces depends on compilation options.
+ The empty string (the default) disables any such filtering. So for any
+ logs that match both <xref linkend="guc-log-backtrace-mode"/> and
+ <xref linkend="guc-backtrace-min-level"/> a backtrace is
+ written to the server log.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id="guc-backtrace-min-level" xreflabel="backtrace_min_level">
+ <term><varname>backtrace_min_level</varname> (<type>string</type>)
+ <indexterm>
+ <primary><varname>backtrace_min_level</varname> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Controls which <link linkend="runtime-config-severity-levels">message
+ levels</link> cause backtraces to be written to the log, for log
+ messages that match both <xref linkend="guc-log-backtrace-mode"/> and
+ <xref linkend="guc-backtrace-functions"/>.
+ Valid values are <literal>DEBUG5</literal>, <literal>DEBUG4</literal>,
+ <literal>DEBUG3</literal>, <literal>DEBUG2</literal>, <literal>DEBUG1</literal>,
+ <literal>LOG</literal>, <literal>INFO</literal>, <literal>NOTICE</literal>,
+ <literal>WARNING</literal>, <literal>ERROR</literal>, <literal>FATAL</literal>,
+ and <literal>PANIC</literal>. Each level includes all the levels that
+ follow it. The later the level, the fewer messages result in a
+ backtrace. The default is <literal>ERROR</literal>. Note that
+ <literal>LOG</literal> has a different rank here than in
+ <xref linkend="guc-log-min-messages"/>.
</para>
<para>
@@ -11391,6 +11458,7 @@ dynamic_library_path = 'C:\tools\postgresql;H:\my_project\lib;$libdir'
</listitem>
</varlistentry>
+
<varlistentry id="guc-debug-discard-caches" xreflabel="debug_discard_caches">
<term><varname>debug_discard_caches</varname> (<type>integer</type>)
<indexterm>
diff --git a/src/backend/utils/error/elog.c b/src/backend/utils/error/elog.c
index d91a85cb2d7..08ee899f6bc 100644
--- a/src/backend/utils/error/elog.c
+++ b/src/backend/utils/error/elog.c
@@ -111,6 +111,7 @@ int Log_error_verbosity = PGERROR_DEFAULT;
char *Log_line_prefix = NULL; /* format for extra log line info */
int Log_destination = LOG_DESTINATION_STDERR;
char *Log_destination_string = NULL;
+int log_backtrace = LOGBACKTRACE_NONE;
bool syslog_sequence_numbers = true;
bool syslog_split_messages = true;
@@ -181,6 +182,7 @@ static void set_stack_entry_domain(ErrorData *edata, const char *domain);
static void set_stack_entry_location(ErrorData *edata,
const char *filename, int lineno,
const char *funcname);
+static bool matches_backtrace_gucs(ErrorData *edata);
static bool matches_backtrace_functions(const char *funcname);
static pg_noinline void set_backtrace(ErrorData *edata, int num_skip);
static void set_errdata_field(MemoryContextData *cxt, char **ptr, const char *str);
@@ -496,10 +498,7 @@ errfinish(const char *filename, int lineno, const char *funcname)
oldcontext = MemoryContextSwitchTo(ErrorContext);
/* Collect backtrace, if enabled and we didn't already */
- if (!edata->backtrace &&
- edata->funcname &&
- backtrace_functions &&
- matches_backtrace_functions(edata->funcname))
+ if (!edata->backtrace && matches_backtrace_gucs(edata))
set_backtrace(edata, 2);
/*
@@ -819,6 +818,26 @@ set_stack_entry_location(ErrorData *edata,
edata->funcname = funcname;
}
+/*
+ * matches_backtrace_gucs --- checks whether the log entry matches
+ * log_backtrace_mode, backtrace_min_level and backtrace_functions.
+ */
+static bool
+matches_backtrace_gucs(ErrorData *edata)
+{
+ if (log_backtrace == LOGBACKTRACE_NONE)
+ return false;
+
+ if (log_backtrace == LOGBACKTRACE_INTERNAL_ERROR &&
+ edata->sqlerrcode != ERRCODE_INTERNAL_ERROR)
+ return false;
+
+ if (backtrace_min_level > edata->elevel)
+ return false;
+
+ return matches_backtrace_functions(edata->funcname);
+}
+
/*
* matches_backtrace_functions --- checks whether the given funcname matches
* backtrace_functions
@@ -830,6 +849,9 @@ matches_backtrace_functions(const char *funcname)
{
const char *p;
+ if (!backtrace_functions || backtrace_functions[0] == '\0')
+ return true;
+
if (!backtrace_function_list || funcname == NULL || funcname[0] == '\0')
return false;
diff --git a/src/backend/utils/misc/guc_tables.c b/src/backend/utils/misc/guc_tables.c
index 46c258be282..87826a32cfb 100644
--- a/src/backend/utils/misc/guc_tables.c
+++ b/src/backend/utils/misc/guc_tables.c
@@ -163,6 +163,23 @@ static const struct config_enum_entry server_message_level_options[] = {
{NULL, 0, false}
};
+static const struct config_enum_entry backtrace_level_options[] = {
+ {"debug5", DEBUG5, false},
+ {"debug4", DEBUG4, false},
+ {"debug3", DEBUG3, false},
+ {"debug2", DEBUG2, false},
+ {"debug1", DEBUG1, false},
+ {"debug", DEBUG2, true},
+ {"log", LOG, false},
+ {"info", INFO, true},
+ {"notice", NOTICE, false},
+ {"warning", WARNING, false},
+ {"error", ERROR, false},
+ {"fatal", FATAL, false},
+ {"panic", PANIC, false},
+ {NULL, 0, false}
+};
+
static const struct config_enum_entry intervalstyle_options[] = {
{"postgres", INTSTYLE_POSTGRES, false},
{"postgres_verbose", INTSTYLE_POSTGRES_VERBOSE, false},
@@ -200,6 +217,16 @@ static const struct config_enum_entry log_error_verbosity_options[] = {
StaticAssertDecl(lengthof(log_error_verbosity_options) == (PGERROR_VERBOSE + 2),
"array length mismatch");
+static const struct config_enum_entry log_backtrace_options[] = {
+ {"none", LOGBACKTRACE_NONE, false},
+ {"internal_error", LOGBACKTRACE_INTERNAL_ERROR, false},
+ {"all", LOGBACKTRACE_ALL, false},
+ {NULL, 0, false}
+};
+
+StaticAssertDecl(lengthof(log_backtrace_options) == (LOGBACKTRACE_ALL + 2),
+ "array length mismatch");
+
static const struct config_enum_entry log_statement_options[] = {
{"none", LOGSTMT_NONE, false},
{"ddl", LOGSTMT_DDL, false},
@@ -531,6 +558,7 @@ int log_temp_files = -1;
double log_statement_sample_rate = 1.0;
double log_xact_sample_rate = 0;
char *backtrace_functions;
+int backtrace_min_level = ERROR;
int temp_file_limit = -1;
@@ -4724,6 +4752,18 @@ struct config_enum ConfigureNamesEnum[] =
NULL, NULL, NULL
},
+ {
+ {"backtrace_min_level", PGC_SUSET, DEVELOPER_OPTIONS,
+ gettext_noop("Sets the message levels that create backtraces when log_backtrace is configured."),
+ gettext_noop("Each level includes all the levels that follow it. The later"
+ " the level, the fewer backtraces are created."),
+ GUC_NOT_IN_SAMPLE
+ },
+ &backtrace_min_level,
+ ERROR, backtrace_level_options,
+ NULL, NULL, NULL
+ },
+
{
{"bytea_output", PGC_USERSET, CLIENT_CONN_STATEMENT,
gettext_noop("Sets the output format for bytea."),
@@ -4820,6 +4860,16 @@ struct config_enum ConfigureNamesEnum[] =
NULL, NULL, NULL
},
+ {
+ {"log_backtrace", PGC_SUSET, LOGGING_WHAT,
+ gettext_noop("Sets if logs should include a backtrace."),
+ NULL
+ },
+ &log_backtrace,
+ LOGBACKTRACE_NONE, log_backtrace_options,
+ NULL, NULL, NULL
+ },
+
{
{"log_error_verbosity", PGC_SUSET, LOGGING_WHAT,
gettext_noop("Sets the verbosity of logged messages."),
diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample
index e0567de2190..33bde793cdc 100644
--- a/src/backend/utils/misc/postgresql.conf.sample
+++ b/src/backend/utils/misc/postgresql.conf.sample
@@ -575,6 +575,7 @@
# their durations, > 0 logs only
# actions running at least this number
# of milliseconds.
+#log_backtrace = 'none'
#log_checkpoints = on
#log_connections = off
#log_disconnections = off
diff --git a/src/include/utils/elog.h b/src/include/utils/elog.h
index da1a7469fa5..c6796cf0265 100644
--- a/src/include/utils/elog.h
+++ b/src/include/utils/elog.h
@@ -495,9 +495,17 @@ typedef enum
PGERROR_VERBOSE, /* all the facts, ma'am */
} PGErrorVerbosity;
+typedef enum
+{
+ LOGBACKTRACE_NONE, /* no backtrace */
+ LOGBACKTRACE_INTERNAL_ERROR, /* backtrace for internal error code */
+ LOGBACKTRACE_ALL, /* backtrace for all logs */
+} LogBacktraceVerbosity;
+
extern PGDLLIMPORT int Log_error_verbosity;
extern PGDLLIMPORT char *Log_line_prefix;
extern PGDLLIMPORT int Log_destination;
+extern PGDLLIMPORT int log_backtrace;
extern PGDLLIMPORT char *Log_destination_string;
extern PGDLLIMPORT bool syslog_sequence_numbers;
extern PGDLLIMPORT bool syslog_split_messages;
diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h
index ff506bf48d9..8417f203891 100644
--- a/src/include/utils/guc.h
+++ b/src/include/utils/guc.h
@@ -267,6 +267,7 @@ extern PGDLLIMPORT int log_temp_files;
extern PGDLLIMPORT double log_statement_sample_rate;
extern PGDLLIMPORT double log_xact_sample_rate;
extern PGDLLIMPORT char *backtrace_functions;
+extern PGDLLIMPORT int backtrace_min_level;
extern PGDLLIMPORT int temp_file_limit;
diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list
index 67ec5408a98..15c596e33a7 100644
--- a/src/tools/pgindent/typedefs.list
+++ b/src/tools/pgindent/typedefs.list
@@ -1531,6 +1531,7 @@ LockTupleMode
LockViewRecurse_context
LockWaitPolicy
LockingClause
+LogBacktraceVerbosity
LogOpts
LogStmtLevel
LogicalDecodeBeginCB
--
2.34.1
On Thu, 27 Jun 2024 at 12:43, Jelte Fennema-Nio <me@jeltef.nl> wrote:
Attached is a rebased patchset of my previous proposal, including a
few changes that Michael preferred:
Rebased again. (got notified because of the new commitfest rebase emails)
The first patch should be trivial to commit at least as it's just cleanup.
Attachments:
v11-0001-Add-PGErrorVerbosity-to-typedefs.list.patchtext/x-patch; charset=US-ASCII; name=v11-0001-Add-PGErrorVerbosity-to-typedefs.list.patchDownload
From bfc9c9741898e033e3eb117a85c06564120ce898 Mon Sep 17 00:00:00 2001
From: Jelte Fennema-Nio <jelte.fennema@microsoft.com>
Date: Thu, 21 Mar 2024 13:05:35 +0100
Subject: [PATCH v11 1/2] Add PGErrorVerbosity to typedefs.list
This one was missing, resulting in some strange alignment.
---
src/include/utils/elog.h | 2 +-
src/tools/pgindent/typedefs.list | 1 +
2 files changed, 2 insertions(+), 1 deletion(-)
diff --git a/src/include/utils/elog.h b/src/include/utils/elog.h
index 7161f5c6ad6..a0244bff1fc 100644
--- a/src/include/utils/elog.h
+++ b/src/include/utils/elog.h
@@ -494,7 +494,7 @@ typedef enum
PGERROR_TERSE, /* single-line error messages */
PGERROR_DEFAULT, /* recommended style */
PGERROR_VERBOSE, /* all the facts, ma'am */
-} PGErrorVerbosity;
+} PGErrorVerbosity;
extern PGDLLIMPORT int Log_error_verbosity;
extern PGDLLIMPORT char *Log_line_prefix;
diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list
index bce4214503d..80aa50d55a4 100644
--- a/src/tools/pgindent/typedefs.list
+++ b/src/tools/pgindent/typedefs.list
@@ -1792,6 +1792,7 @@ PGAsyncStatusType
PGCALL2
PGChecksummablePage
PGContextVisibility
+PGErrorVerbosity
PGEvent
PGEventConnDestroy
PGEventConnReset
base-commit: 217919dd0954f54402e8d0a38cd203a740754077
--
2.43.0
v11-0002-Allow-logging-backtraces-in-more-cases.patchtext/x-patch; charset=US-ASCII; name=v11-0002-Allow-logging-backtraces-in-more-cases.patchDownload
From 0cb321f0a570116a89afa1b1f78a3adcad3fe6e4 Mon Sep 17 00:00:00 2001
From: Jelte Fennema-Nio <jelte.fennema@microsoft.com>
Date: Thu, 27 Jun 2024 10:56:10 +0200
Subject: [PATCH v11 2/2] Allow logging backtraces in more cases
We previously only had the backtrace_functions GUC to control when
backtraces were logged. Based on mailinglist discussion there were two
common cases that people wanted backtraces that were not covered by this
GUC though:
1. Logging backtraces for all internal errors
2. Logging backtraces for all errors
To support those two usecases, as well as to allow users to continue to
log backtraces for specific warnings using `backtrace_functions`, this
modifies the GUCs in the following way:
1. Adds a `log_backtrace` GUC, which can be set to `none` (default),
`internal_error` and `all` to log different types of backtraces.
2. Change `backtrace_functions` to behave as an additional filter on top
of `log_backtrace`. The empty string (the default) is now interpreted
as doing no filtering based on function name.
3. Add a `backtrace_min_level` GUC, which limits for which log entries
backtraces are written, based on their log level. This defaults to
ERROR.
This does mean that setting `backtrace_functions=some_func` alone is not
enough to get backtraces for some_func. You now need to combine that
with `log_backtrace_mode=all` and if you want to get backtraces for
non-errors (which you previously got), you also need to change
backtrace_min_level to whichever level you want backtraces for.
---
doc/src/sgml/config.sgml | 82 +++++++++++++++++--
src/backend/utils/error/elog.c | 30 ++++++-
src/backend/utils/misc/guc_tables.c | 50 +++++++++++
src/backend/utils/misc/postgresql.conf.sample | 1 +
src/include/utils/elog.h | 8 ++
src/include/utils/guc.h | 1 +
src/tools/pgindent/typedefs.list | 1 +
7 files changed, 162 insertions(+), 11 deletions(-)
diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
index 336630ce417..257a1e4006a 100644
--- a/doc/src/sgml/config.sgml
+++ b/doc/src/sgml/config.sgml
@@ -7231,6 +7231,44 @@ local0.* /var/log/postgresql
</listitem>
</varlistentry>
+ <varlistentry id="guc-log-backtrace-mode" xreflabel="log_backtrace_mode">
+ <term><varname>log_backtrace_mode</varname> (<type>boolean</type>)
+ <indexterm>
+ <primary><varname>log_backtrace_mode</varname> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ If this parameter is set to <literal>all</literal> then for all log
+ entries a backtrace is written to the server log together with the log
+ message. If this parameter is set to <literal>internal_error</literal> then
+ such a backtrace is only written for logs with error code XX000
+ (internal error; see also <xref linkend="errcodes-appendix"/>).
+ This can be used to debug such internal errors (which should normally
+ not happen in production). Finally, if this parameter is set to
+ <literal>none</literal> (the default), no backtraces are ever written
+ to the server log.
+ </para>
+
+ <para>
+ The logs for which a backtrace is written can be further restricted
+ using <xref linkend="guc-backtrace-min-level"/> (default:
+ <literal>ERROR</literal>) and <xref linkend="guc-backtrace-functions"/>
+ (default: empty string, meaning all).
+ </para>
+
+ <para>
+ Backtrace support is not available on all platforms, and the quality
+ of the backtraces depends on compilation options.
+ </para>
+
+ <para>
+ Only superusers and users with the appropriate <literal>SET</literal>
+ privilege can change this setting.
+ </para>
+ </listitem>
+ </varlistentry>
+
<varlistentry id="guc-log-checkpoints" xreflabel="log_checkpoints">
<term><varname>log_checkpoints</varname> (<type>boolean</type>)
<indexterm>
@@ -11671,16 +11709,45 @@ dynamic_library_path = 'C:\tools\postgresql;H:\my_project\lib;$libdir'
</term>
<listitem>
<para>
- This parameter contains a comma-separated list of C function names.
- If an error is raised and the name of the internal C function where
- the error happens matches a value in the list, then a backtrace is
- written to the server log together with the error message. This can
- be used to debug specific areas of the source code.
+ This parameter can contain a comma-separated list of C function names,
+ which can be used to filter for which logs a backtrace is written to
+ the server log.
+ If a log entry is raised and the name of the
+ internal C function where the error happens does not match any of the
+ values in the list, then no backtrace is written to the server log.
+ This can be used to only debug specific areas of the source code.
</para>
<para>
- Backtrace support is not available on all platforms, and the quality
- of the backtraces depends on compilation options.
+ The empty string (the default) disables any such filtering. So for any
+ logs that match both <xref linkend="guc-log-backtrace-mode"/> and
+ <xref linkend="guc-backtrace-min-level"/> a backtrace is
+ written to the server log.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id="guc-backtrace-min-level" xreflabel="backtrace_min_level">
+ <term><varname>backtrace_min_level</varname> (<type>string</type>)
+ <indexterm>
+ <primary><varname>backtrace_min_level</varname> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Controls which <link linkend="runtime-config-severity-levels">message
+ levels</link> cause backtraces to be written to the log, for log
+ messages that match both <xref linkend="guc-log-backtrace-mode"/> and
+ <xref linkend="guc-backtrace-functions"/>.
+ Valid values are <literal>DEBUG5</literal>, <literal>DEBUG4</literal>,
+ <literal>DEBUG3</literal>, <literal>DEBUG2</literal>, <literal>DEBUG1</literal>,
+ <literal>LOG</literal>, <literal>INFO</literal>, <literal>NOTICE</literal>,
+ <literal>WARNING</literal>, <literal>ERROR</literal>, <literal>FATAL</literal>,
+ and <literal>PANIC</literal>. Each level includes all the levels that
+ follow it. The later the level, the fewer messages result in a
+ backtrace. The default is <literal>ERROR</literal>. Note that
+ <literal>LOG</literal> has a different rank here than in
+ <xref linkend="guc-log-min-messages"/>.
</para>
<para>
@@ -11713,6 +11780,7 @@ dynamic_library_path = 'C:\tools\postgresql;H:\my_project\lib;$libdir'
</listitem>
</varlistentry>
+
<varlistentry id="guc-debug-discard-caches" xreflabel="debug_discard_caches">
<term><varname>debug_discard_caches</varname> (<type>integer</type>)
<indexterm>
diff --git a/src/backend/utils/error/elog.c b/src/backend/utils/error/elog.c
index 860bbd40d42..d5501f68313 100644
--- a/src/backend/utils/error/elog.c
+++ b/src/backend/utils/error/elog.c
@@ -109,6 +109,7 @@ int Log_error_verbosity = PGERROR_DEFAULT;
char *Log_line_prefix = NULL; /* format for extra log line info */
int Log_destination = LOG_DESTINATION_STDERR;
char *Log_destination_string = NULL;
+int log_backtrace = LOGBACKTRACE_NONE;
bool syslog_sequence_numbers = true;
bool syslog_split_messages = true;
@@ -177,6 +178,7 @@ static void set_stack_entry_domain(ErrorData *edata, const char *domain);
static void set_stack_entry_location(ErrorData *edata,
const char *filename, int lineno,
const char *funcname);
+static bool matches_backtrace_gucs(ErrorData *edata);
static bool matches_backtrace_functions(const char *funcname);
static pg_noinline void set_backtrace(ErrorData *edata, int num_skip);
static void set_errdata_field(MemoryContextData *cxt, char **ptr, const char *str);
@@ -492,10 +494,7 @@ errfinish(const char *filename, int lineno, const char *funcname)
oldcontext = MemoryContextSwitchTo(ErrorContext);
/* Collect backtrace, if enabled and we didn't already */
- if (!edata->backtrace &&
- edata->funcname &&
- backtrace_functions &&
- matches_backtrace_functions(edata->funcname))
+ if (!edata->backtrace && matches_backtrace_gucs(edata))
set_backtrace(edata, 2);
/*
@@ -815,6 +814,26 @@ set_stack_entry_location(ErrorData *edata,
edata->funcname = funcname;
}
+/*
+ * matches_backtrace_gucs --- checks whether the log entry matches
+ * log_backtrace_mode, backtrace_min_level and backtrace_functions.
+ */
+static bool
+matches_backtrace_gucs(ErrorData *edata)
+{
+ if (log_backtrace == LOGBACKTRACE_NONE)
+ return false;
+
+ if (log_backtrace == LOGBACKTRACE_INTERNAL_ERROR &&
+ edata->sqlerrcode != ERRCODE_INTERNAL_ERROR)
+ return false;
+
+ if (backtrace_min_level > edata->elevel)
+ return false;
+
+ return matches_backtrace_functions(edata->funcname);
+}
+
/*
* matches_backtrace_functions --- checks whether the given funcname matches
* backtrace_functions
@@ -826,6 +845,9 @@ matches_backtrace_functions(const char *funcname)
{
const char *p;
+ if (!backtrace_functions || backtrace_functions[0] == '\0')
+ return true;
+
if (!backtrace_function_list || funcname == NULL || funcname[0] == '\0')
return false;
diff --git a/src/backend/utils/misc/guc_tables.c b/src/backend/utils/misc/guc_tables.c
index cce73314609..052b9d16aa6 100644
--- a/src/backend/utils/misc/guc_tables.c
+++ b/src/backend/utils/misc/guc_tables.c
@@ -154,6 +154,23 @@ static const struct config_enum_entry server_message_level_options[] = {
{NULL, 0, false}
};
+static const struct config_enum_entry backtrace_level_options[] = {
+ {"debug5", DEBUG5, false},
+ {"debug4", DEBUG4, false},
+ {"debug3", DEBUG3, false},
+ {"debug2", DEBUG2, false},
+ {"debug1", DEBUG1, false},
+ {"debug", DEBUG2, true},
+ {"log", LOG, false},
+ {"info", INFO, true},
+ {"notice", NOTICE, false},
+ {"warning", WARNING, false},
+ {"error", ERROR, false},
+ {"fatal", FATAL, false},
+ {"panic", PANIC, false},
+ {NULL, 0, false}
+};
+
static const struct config_enum_entry intervalstyle_options[] = {
{"postgres", INTSTYLE_POSTGRES, false},
{"postgres_verbose", INTSTYLE_POSTGRES_VERBOSE, false},
@@ -191,6 +208,16 @@ static const struct config_enum_entry log_error_verbosity_options[] = {
StaticAssertDecl(lengthof(log_error_verbosity_options) == (PGERROR_VERBOSE + 2),
"array length mismatch");
+static const struct config_enum_entry log_backtrace_options[] = {
+ {"none", LOGBACKTRACE_NONE, false},
+ {"internal_error", LOGBACKTRACE_INTERNAL_ERROR, false},
+ {"all", LOGBACKTRACE_ALL, false},
+ {NULL, 0, false}
+};
+
+StaticAssertDecl(lengthof(log_backtrace_options) == (LOGBACKTRACE_ALL + 2),
+ "array length mismatch");
+
static const struct config_enum_entry log_statement_options[] = {
{"none", LOGSTMT_NONE, false},
{"ddl", LOGSTMT_DDL, false},
@@ -529,6 +556,7 @@ int log_temp_files = -1;
double log_statement_sample_rate = 1.0;
double log_xact_sample_rate = 0;
char *backtrace_functions;
+int backtrace_min_level = ERROR;
int temp_file_limit = -1;
@@ -4880,6 +4908,18 @@ struct config_enum ConfigureNamesEnum[] =
NULL, NULL, NULL
},
+ {
+ {"backtrace_min_level", PGC_SUSET, DEVELOPER_OPTIONS,
+ gettext_noop("Sets the message levels that create backtraces when log_backtrace is configured."),
+ gettext_noop("Each level includes all the levels that follow it. The later"
+ " the level, the fewer backtraces are created."),
+ GUC_NOT_IN_SAMPLE
+ },
+ &backtrace_min_level,
+ ERROR, backtrace_level_options,
+ NULL, NULL, NULL
+ },
+
{
{"bytea_output", PGC_USERSET, CLIENT_CONN_STATEMENT,
gettext_noop("Sets the output format for bytea."),
@@ -4976,6 +5016,16 @@ struct config_enum ConfigureNamesEnum[] =
NULL, NULL, NULL
},
+ {
+ {"log_backtrace", PGC_SUSET, LOGGING_WHAT,
+ gettext_noop("Sets if logs should include a backtrace."),
+ NULL
+ },
+ &log_backtrace,
+ LOGBACKTRACE_NONE, log_backtrace_options,
+ NULL, NULL, NULL
+ },
+
{
{"log_error_verbosity", PGC_SUSET, LOGGING_WHAT,
gettext_noop("Sets the verbosity of logged messages."),
diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample
index d472987ed46..5736e02cc47 100644
--- a/src/backend/utils/misc/postgresql.conf.sample
+++ b/src/backend/utils/misc/postgresql.conf.sample
@@ -573,6 +573,7 @@
# their durations, > 0 logs only
# actions running at least this number
# of milliseconds.
+#log_backtrace = 'none'
#log_checkpoints = on
#log_connections = off
#log_disconnections = off
diff --git a/src/include/utils/elog.h b/src/include/utils/elog.h
index a0244bff1fc..f065c3951ea 100644
--- a/src/include/utils/elog.h
+++ b/src/include/utils/elog.h
@@ -496,9 +496,17 @@ typedef enum
PGERROR_VERBOSE, /* all the facts, ma'am */
} PGErrorVerbosity;
+typedef enum
+{
+ LOGBACKTRACE_NONE, /* no backtrace */
+ LOGBACKTRACE_INTERNAL_ERROR, /* backtrace for internal error code */
+ LOGBACKTRACE_ALL, /* backtrace for all logs */
+} LogBacktraceVerbosity;
+
extern PGDLLIMPORT int Log_error_verbosity;
extern PGDLLIMPORT char *Log_line_prefix;
extern PGDLLIMPORT int Log_destination;
+extern PGDLLIMPORT int log_backtrace;
extern PGDLLIMPORT char *Log_destination_string;
extern PGDLLIMPORT bool syslog_sequence_numbers;
extern PGDLLIMPORT bool syslog_split_messages;
diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h
index 1233e07d7da..f9f9ad710d1 100644
--- a/src/include/utils/guc.h
+++ b/src/include/utils/guc.h
@@ -279,6 +279,7 @@ extern PGDLLIMPORT int log_temp_files;
extern PGDLLIMPORT double log_statement_sample_rate;
extern PGDLLIMPORT double log_xact_sample_rate;
extern PGDLLIMPORT char *backtrace_functions;
+extern PGDLLIMPORT int backtrace_min_level;
extern PGDLLIMPORT int temp_file_limit;
diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list
index 80aa50d55a4..25a636969ee 100644
--- a/src/tools/pgindent/typedefs.list
+++ b/src/tools/pgindent/typedefs.list
@@ -1544,6 +1544,7 @@ LockTupleMode
LockViewRecurse_context
LockWaitPolicy
LockingClause
+LogBacktraceVerbosity
LogOpts
LogStmtLevel
LogicalDecodeBeginCB
--
2.43.0
On 18 Feb 2025, at 09:34, Jelte Fennema-Nio <postgres@jeltef.nl> wrote:
On Thu, 27 Jun 2024 at 12:43, Jelte Fennema-Nio <me@jeltef.nl> wrote:
Attached is a rebased patchset of my previous proposal, including a
few changes that Michael preferred:Rebased again. (got notified because of the new commitfest rebase emails)
We typically avoid having intra-depencies between multiple GUCs to control a
single behavior like this. I'm not sure having three is the right move here
but I need to do some more review and testing.
The first patch should be trivial to commit at least as it's just cleanup.
Agreed, I've applied that to keep it from getting lost in here.
--
Daniel Gustafsson
On 18.02.25 09:34, Jelte Fennema-Nio wrote:
On Thu, 27 Jun 2024 at 12:43, Jelte Fennema-Nio <me@jeltef.nl> wrote:
Attached is a rebased patchset of my previous proposal, including a
few changes that Michael preferred:Rebased again. (got notified because of the new commitfest rebase emails)
The first patch should be trivial to commit at least as it's just cleanup.
I think the additions to typedefs.list are useless. Since nothing
actually uses these types, the collection on the buildfarm won't find
any uses of them and thus won't include it in its list, and then the
next update from the buildfarm will overwrite your changes.
You might as well just remove the type definitions (but keep the enum
declarations).
Peter Eisentraut <peter@eisentraut.org> writes:
I think the additions to typedefs.list are useless. Since nothing
actually uses these types, the collection on the buildfarm won't find
any uses of them and thus won't include it in its list, and then the
next update from the buildfarm will overwrite your changes.
It's not quite that simple. Lately, at least, we haven't just blindly
replaced typedefs.list with the buildfarm's list. When I do it I do
a sanity check on the additions and removals, partly by seeing what
indentation changes result. A manually-added typedef that happened
not to be in the buildfarm's list would probably survive, if removing
it resulted in any ugly changes.
Still, it is better to make sure the typedef is actually used to
declare some variables, so that you're not so dependent on the
amount of manual curation that happens. If there's no place where
that can plausibly be done, maybe you don't need the typedef after
all?
regards, tom lane
On Wed, 26 Feb 2025 at 16:40, Tom Lane <tgl@sss.pgh.pa.us> wrote:
If there's no place where
that can plausibly be done, maybe you don't need the typedef after
all?
Makes sense, I removed the unused LogBacktraceVerbosity typedef now.
It caused a rebase conflict just now, so this also solves that.
Attachments:
v12-0001-Allow-logging-backtraces-in-more-cases.patchtext/x-patch; charset=US-ASCII; name=v12-0001-Allow-logging-backtraces-in-more-cases.patchDownload
From 579ac166ab91f5b5e7c2d79d2c9a7f5e4a52fc6e Mon Sep 17 00:00:00 2001
From: Jelte Fennema-Nio <github-tech@jeltef.nl>
Date: Tue, 18 Mar 2025 01:31:57 +0100
Subject: [PATCH v12] Allow logging backtraces in more cases
We previously only had the backtrace_functions GUC to control when
backtraces were logged. Based on mailinglist discussion there were two
common cases that people wanted backtraces that were not covered by this
GUC though:
1. Logging backtraces for all internal errors
2. Logging backtraces for all errors
To support those two usecases, as well as to allow users to continue to
log backtraces for specific warnings using `backtrace_functions`, this
modifies the GUCs in the following way:
1. Adds a `log_backtrace` GUC, which can be set to `none` (default),
`internal_error` and `all` to log different types of backtraces.
2. Change `backtrace_functions` to behave as an additional filter on top
of `log_backtrace`. The empty string (the default) is now interpreted
as doing no filtering based on function name.
3. Add a `backtrace_min_level` GUC, which limits for which log entries
backtraces are written, based on their log level. This defaults to
ERROR.
This does mean that setting `backtrace_functions=some_func` alone is not
enough to get backtraces for some_func. You now need to combine that
with `log_backtrace_mode=all` and if you want to get backtraces for
non-errors (which you previously got), you also need to change
backtrace_min_level to whichever level you want backtraces for.
---
doc/src/sgml/config.sgml | 82 +++++++++++++++++--
src/backend/utils/error/elog.c | 30 ++++++-
src/backend/utils/misc/guc_tables.c | 50 +++++++++++
src/backend/utils/misc/postgresql.conf.sample | 1 +
src/include/utils/elog.h | 8 ++
src/include/utils/guc.h | 1 +
6 files changed, 161 insertions(+), 11 deletions(-)
diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
index 3d62c8bd274..da8cbb09d69 100644
--- a/doc/src/sgml/config.sgml
+++ b/doc/src/sgml/config.sgml
@@ -7291,6 +7291,44 @@ local0.* /var/log/postgresql
</listitem>
</varlistentry>
+ <varlistentry id="guc-log-backtrace-mode" xreflabel="log_backtrace_mode">
+ <term><varname>log_backtrace_mode</varname> (<type>boolean</type>)
+ <indexterm>
+ <primary><varname>log_backtrace_mode</varname> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ If this parameter is set to <literal>all</literal> then for all log
+ entries a backtrace is written to the server log together with the log
+ message. If this parameter is set to <literal>internal_error</literal> then
+ such a backtrace is only written for logs with error code XX000
+ (internal error; see also <xref linkend="errcodes-appendix"/>).
+ This can be used to debug such internal errors (which should normally
+ not happen in production). Finally, if this parameter is set to
+ <literal>none</literal> (the default), no backtraces are ever written
+ to the server log.
+ </para>
+
+ <para>
+ The logs for which a backtrace is written can be further restricted
+ using <xref linkend="guc-backtrace-min-level"/> (default:
+ <literal>ERROR</literal>) and <xref linkend="guc-backtrace-functions"/>
+ (default: empty string, meaning all).
+ </para>
+
+ <para>
+ Backtrace support is not available on all platforms, and the quality
+ of the backtraces depends on compilation options.
+ </para>
+
+ <para>
+ Only superusers and users with the appropriate <literal>SET</literal>
+ privilege can change this setting.
+ </para>
+ </listitem>
+ </varlistentry>
+
<varlistentry id="guc-log-checkpoints" xreflabel="log_checkpoints">
<term><varname>log_checkpoints</varname> (<type>boolean</type>)
<indexterm>
@@ -11841,16 +11879,45 @@ dynamic_library_path = 'C:\tools\postgresql;H:\my_project\lib;$libdir'
</term>
<listitem>
<para>
- This parameter contains a comma-separated list of C function names.
- If an error is raised and the name of the internal C function where
- the error happens matches a value in the list, then a backtrace is
- written to the server log together with the error message. This can
- be used to debug specific areas of the source code.
+ This parameter can contain a comma-separated list of C function names,
+ which can be used to filter for which logs a backtrace is written to
+ the server log.
+ If a log entry is raised and the name of the
+ internal C function where the error happens does not match any of the
+ values in the list, then no backtrace is written to the server log.
+ This can be used to only debug specific areas of the source code.
</para>
<para>
- Backtrace support is not available on all platforms, and the quality
- of the backtraces depends on compilation options.
+ The empty string (the default) disables any such filtering. So for any
+ logs that match both <xref linkend="guc-log-backtrace-mode"/> and
+ <xref linkend="guc-backtrace-min-level"/> a backtrace is
+ written to the server log.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id="guc-backtrace-min-level" xreflabel="backtrace_min_level">
+ <term><varname>backtrace_min_level</varname> (<type>string</type>)
+ <indexterm>
+ <primary><varname>backtrace_min_level</varname> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Controls which <link linkend="runtime-config-severity-levels">message
+ levels</link> cause backtraces to be written to the log, for log
+ messages that match both <xref linkend="guc-log-backtrace-mode"/> and
+ <xref linkend="guc-backtrace-functions"/>.
+ Valid values are <literal>DEBUG5</literal>, <literal>DEBUG4</literal>,
+ <literal>DEBUG3</literal>, <literal>DEBUG2</literal>, <literal>DEBUG1</literal>,
+ <literal>LOG</literal>, <literal>INFO</literal>, <literal>NOTICE</literal>,
+ <literal>WARNING</literal>, <literal>ERROR</literal>, <literal>FATAL</literal>,
+ and <literal>PANIC</literal>. Each level includes all the levels that
+ follow it. The later the level, the fewer messages result in a
+ backtrace. The default is <literal>ERROR</literal>. Note that
+ <literal>LOG</literal> has a different rank here than in
+ <xref linkend="guc-log-min-messages"/>.
</para>
<para>
@@ -11883,6 +11950,7 @@ dynamic_library_path = 'C:\tools\postgresql;H:\my_project\lib;$libdir'
</listitem>
</varlistentry>
+
<varlistentry id="guc-debug-discard-caches" xreflabel="debug_discard_caches">
<term><varname>debug_discard_caches</varname> (<type>integer</type>)
<indexterm>
diff --git a/src/backend/utils/error/elog.c b/src/backend/utils/error/elog.c
index 860bbd40d42..d5501f68313 100644
--- a/src/backend/utils/error/elog.c
+++ b/src/backend/utils/error/elog.c
@@ -109,6 +109,7 @@ int Log_error_verbosity = PGERROR_DEFAULT;
char *Log_line_prefix = NULL; /* format for extra log line info */
int Log_destination = LOG_DESTINATION_STDERR;
char *Log_destination_string = NULL;
+int log_backtrace = LOGBACKTRACE_NONE;
bool syslog_sequence_numbers = true;
bool syslog_split_messages = true;
@@ -177,6 +178,7 @@ static void set_stack_entry_domain(ErrorData *edata, const char *domain);
static void set_stack_entry_location(ErrorData *edata,
const char *filename, int lineno,
const char *funcname);
+static bool matches_backtrace_gucs(ErrorData *edata);
static bool matches_backtrace_functions(const char *funcname);
static pg_noinline void set_backtrace(ErrorData *edata, int num_skip);
static void set_errdata_field(MemoryContextData *cxt, char **ptr, const char *str);
@@ -492,10 +494,7 @@ errfinish(const char *filename, int lineno, const char *funcname)
oldcontext = MemoryContextSwitchTo(ErrorContext);
/* Collect backtrace, if enabled and we didn't already */
- if (!edata->backtrace &&
- edata->funcname &&
- backtrace_functions &&
- matches_backtrace_functions(edata->funcname))
+ if (!edata->backtrace && matches_backtrace_gucs(edata))
set_backtrace(edata, 2);
/*
@@ -815,6 +814,26 @@ set_stack_entry_location(ErrorData *edata,
edata->funcname = funcname;
}
+/*
+ * matches_backtrace_gucs --- checks whether the log entry matches
+ * log_backtrace_mode, backtrace_min_level and backtrace_functions.
+ */
+static bool
+matches_backtrace_gucs(ErrorData *edata)
+{
+ if (log_backtrace == LOGBACKTRACE_NONE)
+ return false;
+
+ if (log_backtrace == LOGBACKTRACE_INTERNAL_ERROR &&
+ edata->sqlerrcode != ERRCODE_INTERNAL_ERROR)
+ return false;
+
+ if (backtrace_min_level > edata->elevel)
+ return false;
+
+ return matches_backtrace_functions(edata->funcname);
+}
+
/*
* matches_backtrace_functions --- checks whether the given funcname matches
* backtrace_functions
@@ -826,6 +845,9 @@ matches_backtrace_functions(const char *funcname)
{
const char *p;
+ if (!backtrace_functions || backtrace_functions[0] == '\0')
+ return true;
+
if (!backtrace_function_list || funcname == NULL || funcname[0] == '\0')
return false;
diff --git a/src/backend/utils/misc/guc_tables.c b/src/backend/utils/misc/guc_tables.c
index 9c0b10ad4dc..b97a551a35a 100644
--- a/src/backend/utils/misc/guc_tables.c
+++ b/src/backend/utils/misc/guc_tables.c
@@ -156,6 +156,23 @@ static const struct config_enum_entry server_message_level_options[] = {
{NULL, 0, false}
};
+static const struct config_enum_entry backtrace_level_options[] = {
+ {"debug5", DEBUG5, false},
+ {"debug4", DEBUG4, false},
+ {"debug3", DEBUG3, false},
+ {"debug2", DEBUG2, false},
+ {"debug1", DEBUG1, false},
+ {"debug", DEBUG2, true},
+ {"log", LOG, false},
+ {"info", INFO, true},
+ {"notice", NOTICE, false},
+ {"warning", WARNING, false},
+ {"error", ERROR, false},
+ {"fatal", FATAL, false},
+ {"panic", PANIC, false},
+ {NULL, 0, false}
+};
+
static const struct config_enum_entry intervalstyle_options[] = {
{"postgres", INTSTYLE_POSTGRES, false},
{"postgres_verbose", INTSTYLE_POSTGRES_VERBOSE, false},
@@ -193,6 +210,16 @@ static const struct config_enum_entry log_error_verbosity_options[] = {
StaticAssertDecl(lengthof(log_error_verbosity_options) == (PGERROR_VERBOSE + 2),
"array length mismatch");
+static const struct config_enum_entry log_backtrace_options[] = {
+ {"none", LOGBACKTRACE_NONE, false},
+ {"internal_error", LOGBACKTRACE_INTERNAL_ERROR, false},
+ {"all", LOGBACKTRACE_ALL, false},
+ {NULL, 0, false}
+};
+
+StaticAssertDecl(lengthof(log_backtrace_options) == (LOGBACKTRACE_ALL + 2),
+ "array length mismatch");
+
static const struct config_enum_entry log_statement_options[] = {
{"none", LOGSTMT_NONE, false},
{"ddl", LOGSTMT_DDL, false},
@@ -531,6 +558,7 @@ int log_temp_files = -1;
double log_statement_sample_rate = 1.0;
double log_xact_sample_rate = 0;
char *backtrace_functions;
+int backtrace_min_level = ERROR;
int temp_file_limit = -1;
@@ -4917,6 +4945,18 @@ struct config_enum ConfigureNamesEnum[] =
NULL, NULL, NULL
},
+ {
+ {"backtrace_min_level", PGC_SUSET, DEVELOPER_OPTIONS,
+ gettext_noop("Sets the message levels that create backtraces when log_backtrace is configured."),
+ gettext_noop("Each level includes all the levels that follow it. The later"
+ " the level, the fewer backtraces are created."),
+ GUC_NOT_IN_SAMPLE
+ },
+ &backtrace_min_level,
+ ERROR, backtrace_level_options,
+ NULL, NULL, NULL
+ },
+
{
{"bytea_output", PGC_USERSET, CLIENT_CONN_STATEMENT,
gettext_noop("Sets the output format for bytea."),
@@ -5013,6 +5053,16 @@ struct config_enum ConfigureNamesEnum[] =
NULL, NULL, NULL
},
+ {
+ {"log_backtrace", PGC_SUSET, LOGGING_WHAT,
+ gettext_noop("Sets if logs should include a backtrace."),
+ NULL
+ },
+ &log_backtrace,
+ LOGBACKTRACE_NONE, log_backtrace_options,
+ NULL, NULL, NULL
+ },
+
{
{"log_error_verbosity", PGC_SUSET, LOGGING_WHAT,
gettext_noop("Sets the verbosity of logged messages."),
diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample
index 8de86e0c945..baa9bc63360 100644
--- a/src/backend/utils/misc/postgresql.conf.sample
+++ b/src/backend/utils/misc/postgresql.conf.sample
@@ -577,6 +577,7 @@
# their durations, > 0 logs only
# actions running at least this number
# of milliseconds.
+#log_backtrace = 'none'
#log_checkpoints = on
#log_connections = '' # log aspects of connection setup
# options include receipt, authentication, authorization,
diff --git a/src/include/utils/elog.h b/src/include/utils/elog.h
index 855c147325b..6e0e86c8ee0 100644
--- a/src/include/utils/elog.h
+++ b/src/include/utils/elog.h
@@ -487,9 +487,17 @@ typedef enum
PGERROR_VERBOSE, /* all the facts, ma'am */
} PGErrorVerbosity;
+enum
+{
+ LOGBACKTRACE_NONE, /* no backtrace */
+ LOGBACKTRACE_INTERNAL_ERROR, /* backtrace for internal error code */
+ LOGBACKTRACE_ALL, /* backtrace for all logs */
+};
+
extern PGDLLIMPORT int Log_error_verbosity;
extern PGDLLIMPORT char *Log_line_prefix;
extern PGDLLIMPORT int Log_destination;
+extern PGDLLIMPORT int log_backtrace;
extern PGDLLIMPORT char *Log_destination_string;
extern PGDLLIMPORT bool syslog_sequence_numbers;
extern PGDLLIMPORT bool syslog_split_messages;
diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h
index 24444cbc365..de20db170ae 100644
--- a/src/include/utils/guc.h
+++ b/src/include/utils/guc.h
@@ -279,6 +279,7 @@ extern PGDLLIMPORT int log_temp_files;
extern PGDLLIMPORT double log_statement_sample_rate;
extern PGDLLIMPORT double log_xact_sample_rate;
extern PGDLLIMPORT char *backtrace_functions;
+extern PGDLLIMPORT int backtrace_min_level;
extern PGDLLIMPORT int temp_file_limit;
base-commit: 65db3963ae7154b8f01e4d73dc6b1ffd81c70e1e
--
2.43.0