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;