diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
index fd6e3e028907..930c4df65b92 100644
--- a/doc/src/sgml/config.sgml
+++ b/doc/src/sgml/config.sgml
@@ -7435,6 +7435,44 @@ local0.* /var/log/postgresql
+
+ log_backtrace_mode (boolean)
+
+ log_backtrace_mode configuration parameter
+
+
+
+
+ If this parameter is set to all then for all log
+ entries a backtrace is written to the server log together with the log
+ message. If this parameter is set to internal_error then
+ such a backtrace is only written for logs with error code XX000
+ (internal error; see also ).
+ This can be used to debug such internal errors (which should normally
+ not happen in production). Finally, if this parameter is set to
+ none (the default), no backtraces are ever written
+ to the server log.
+
+
+
+ The logs for which a backtrace is written can be further restricted
+ using (default:
+ ERROR) and
+ (default: empty string, meaning all).
+
+
+
+ Backtrace support is not available on all platforms, and the quality
+ of the backtraces depends on compilation options.
+
+
+
+ Only superusers and users with the appropriate SET
+ privilege can change this setting.
+
+
+
+
log_checkpoints (boolean)
@@ -12088,16 +12126,45 @@ dynamic_library_path = '/usr/local/lib/postgresql:$libdir'
- 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.
- 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 and
+ a backtrace is
+ written to the server log.
+
+
+
+
+
+ backtrace_min_level (string)
+
+ backtrace_min_level configuration parameter
+
+
+
+
+ Controls which message
+ levels cause backtraces to be written to the log, for log
+ messages that match both and
+ .
+ Valid values are DEBUG5, DEBUG4,
+ DEBUG3, DEBUG2, DEBUG1,
+ LOG, INFO, NOTICE,
+ WARNING, ERROR, FATAL,
+ and PANIC. Each level includes all the levels that
+ follow it. The later the level, the fewer messages result in a
+ backtrace. The default is ERROR. Note that
+ LOG has a different rank here than in
+ .
@@ -12130,6 +12197,7 @@ dynamic_library_path = '/usr/local/lib/postgresql:$libdir'
+
debug_discard_caches (integer)
diff --git a/src/backend/utils/error/elog.c b/src/backend/utils/error/elog.c
index 47af743990fe..58b721989e98 100644
--- a/src/backend/utils/error/elog.c
+++ b/src/backend/utils/error/elog.c
@@ -110,6 +110,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;
@@ -178,6 +179,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);
@@ -493,10 +495,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);
/*
@@ -816,6 +815,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
@@ -827,6 +846,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 2f8cbd867599..766b33a59253 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},
@@ -546,6 +573,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;
@@ -5004,6 +5032,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."),
@@ -5100,6 +5140,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 34826d01380b..3e5d20fe5023 100644
--- a/src/backend/utils/misc/postgresql.conf.sample
+++ b/src/backend/utils/misc/postgresql.conf.sample
@@ -594,6 +594,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 5eac0e16970c..522f8e1dfe89 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 f619100467df..2150328191b9 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;