On Tuesday, July 26, 2022 3:08:01 AM CEST Lukas Fittl wrote:
> On Mon, Jul 25, 2022 at 12:38 AM Pierre Ducroquet <p.p...@pinaraf.info>
> 
> wrote:
> > usecase by not showing the schema, one of them being log_line_prefix.
> > It is possible to work around this using the application_name, but a
> > mistake
> > on the application side would be fatal, while the search_path would still
> > indicate the real tables used in a query.
> 
> I'm assuming this is mostly referring to STATEMENT log lines and other
> situations where the original query is output (e.g. auto_explain).
> 
> +1 on the benefit of solving this (I've had this use case before), but I
> think we can keep this more specific than a general log_line_prefix option.
> The search_path isn't relevant to any log line that doesn't reference a
> query, since e.g. autovacuum log output fully qualifies its relation names,
> and many other common log lines have nothing to do with tables or queries.
> 
> What if we instead had something like this, as an extra CONTEXT (or DETAIL)
> log line:
> 
> LOG: duration: 4079.697 ms execute <unnamed>:
> SELECT * FROM x WHERE y = $1 LIMIT $2
> DETAIL: parameters: $1 = 'long string', $2 = '1'
> CONTEXT: settings: search_path = 'my_tenant_schema, "$user", public'
> 
> That way you could determine that the slow query was affecting the "x"
> table in "my_tenant_schema".
> 
> This log output would be controlled by a new GUC, e.g.
> "log_statement_search_path" with three settings: (1) never, (2)
> non_default, (3) always.
> 
> The default would be "never" (same as today). "non_default" would output
> the search path when a SET has modified it in the current session (and so
> we couldn't infer it from the config or the role/database overrides).
> "always" would always output the search path for statement-related log
> lines.
> 
> Thanks,
> Lukas

Hi

This is a good idea. I've hacked a first implementation of it (lacking 
documentation, and several logs are still missing) attached to this email.
The biggest issue I had was with knowing where the setting come from since no 
guc.h function expose that information. I worked around this a bit, but I'm 
sure it would be preferable to do it otherwise.

Thanks for your feedbacks

Regards

 Pierre
>From 11bbdec931481ffc02ce147db2c7c8b08e6503e4 Mon Sep 17 00:00:00 2001
From: Pierre Ducroquet <pducroq...@entrouvert.com>
Date: Tue, 26 Jul 2022 14:39:59 +0200
Subject: [PATCH] log the search_path of statements (configurable)

Introduce a new GUC, log_statement_search_path, to make it possible
to log the search_path of queries.
---
 src/backend/catalog/namespace.c |  4 ++++
 src/backend/tcop/postgres.c     | 34 ++++++++++++++++++++++++++++-----
 src/backend/utils/misc/guc.c    | 11 +++++++++++
 src/include/catalog/namespace.h |  2 ++
 src/include/tcop/tcopprot.h     |  8 ++++++++
 src/include/utils/guc.h         |  1 +
 6 files changed, 55 insertions(+), 5 deletions(-)

diff --git a/src/backend/catalog/namespace.c b/src/backend/catalog/namespace.c
index fafb9349cc..ec6c260f15 100644
--- a/src/backend/catalog/namespace.c
+++ b/src/backend/catalog/namespace.c
@@ -197,6 +197,7 @@ static SubTransactionId myTempNamespaceSubID = InvalidSubTransactionId;
  * of the GUC variable 'search_path'.
  */
 char	   *namespace_search_path = NULL;
+GucSource	namespace_search_path_source = 0;
 
 
 /* Local functions */
@@ -4348,6 +4349,9 @@ check_search_path(char **newval, void **extra, GucSource source)
 	pfree(rawname);
 	list_free(namelist);
 
+	/* Store the source */
+	namespace_search_path_source = source;
+
 	return true;
 }
 
diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
index d0bbd30d2b..4fa6260f63 100644
--- a/src/backend/tcop/postgres.c
+++ b/src/backend/tcop/postgres.c
@@ -39,6 +39,7 @@
 #include "access/parallel.h"
 #include "access/printtup.h"
 #include "access/xact.h"
+#include "catalog/namespace.h"
 #include "catalog/pg_type.h"
 #include "commands/async.h"
 #include "commands/prepare.h"
@@ -96,6 +97,15 @@ bool		Log_disconnections = false;
 
 int			log_statement = LOGSTMT_NONE;
 
+const struct config_enum_entry log_statement_search_path_options[] = {
+        {"never", LOG_STATEMENT_SEARCH_PATH_NEVER, false},
+        {"non_default", LOG_STATEMENT_SEARCH_PATH_NON_DEFAULT, false},
+        {"always", LOG_STATEMENT_SEARCH_PATH_ALWAYS, false},
+        {NULL, 0, false}
+};
+
+int			log_statement_search_path = LOG_STATEMENT_SEARCH_PATH_NEVER;
+
 /* GUC variable for maximum stack depth (measured in kilobytes) */
 int			max_stack_depth = 100;
 
@@ -1328,11 +1338,25 @@ exec_simple_query(const char *query_string)
 					 errhidestmt(true)));
 			break;
 		case 2:
-			ereport(LOG,
-					(errmsg("duration: %s ms  statement: %s",
-							msec_str, query_string),
-					 errhidestmt(true),
-					 errdetail_execute(parsetree_list)));
+			if ((log_statement_search_path > LOG_STATEMENT_SEARCH_PATH_NEVER)
+				&& (
+					namespace_search_path_source > PGC_S_INTERACTIVE
+					||
+					log_statement_search_path > LOG_STATEMENT_SEARCH_PATH_NON_DEFAULT
+				)) {
+				ereport(LOG,
+						(errmsg("duration: %s ms  statement: %s",
+								msec_str, query_string),
+						errhidestmt(true),
+						errdetail("search_path: %s", namespace_search_path),
+						errdetail_execute(parsetree_list)));
+			} else {
+				ereport(LOG,
+						(errmsg("duration: %s ms  statement: %s",
+								msec_str, query_string),
+						errhidestmt(true),
+						errdetail_execute(parsetree_list)));
+			}
 			break;
 	}
 
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index af4a1c3068..524d6befa6 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -604,6 +604,7 @@ extern const struct config_enum_entry archive_mode_options[];
 extern const struct config_enum_entry recovery_target_action_options[];
 extern const struct config_enum_entry sync_method_options[];
 extern const struct config_enum_entry dynamic_shared_memory_options[];
+extern const struct config_enum_entry log_statement_search_path_options[];
 
 /*
  * GUC option variables that are exported from this module
@@ -4836,6 +4837,16 @@ static struct config_enum ConfigureNamesEnum[] =
 		NULL, NULL, NULL
 	},
 
+	{
+		{"log_statement_search_path", PGC_SUSET, LOGGING_WHEN,
+			gettext_noop("Sets whether to log the search path of logged statements."),
+			NULL
+		},
+		&log_statement_search_path,
+		LOG_STATEMENT_SEARCH_PATH_NEVER, log_statement_search_path_options,
+		NULL, NULL, NULL
+	},
+
 	{
 		{"log_min_messages", PGC_SUSET, LOGGING_WHEN,
 			gettext_noop("Sets the message levels that are logged."),
diff --git a/src/include/catalog/namespace.h b/src/include/catalog/namespace.h
index 1bc55c01a5..903531b231 100644
--- a/src/include/catalog/namespace.h
+++ b/src/include/catalog/namespace.h
@@ -16,6 +16,7 @@
 
 #include "nodes/primnodes.h"
 #include "storage/lock.h"
+#include "utils/guc.h"
 
 
 /*
@@ -183,6 +184,7 @@ extern void AtEOSubXact_Namespace(bool isCommit, SubTransactionId mySubid,
 
 /* stuff for search_path GUC variable */
 extern PGDLLIMPORT char *namespace_search_path;
+extern PGDLLIMPORT GucSource namespace_search_path_source;
 
 extern List *fetch_search_path(bool includeImplicit);
 extern int	fetch_search_path_array(Oid *sarray, int sarray_len);
diff --git a/src/include/tcop/tcopprot.h b/src/include/tcop/tcopprot.h
index 70d9dab25b..0d3d7bf4e0 100644
--- a/src/include/tcop/tcopprot.h
+++ b/src/include/tcop/tcopprot.h
@@ -41,6 +41,14 @@ typedef enum
 	LOGSTMT_ALL					/* log all statements */
 } LogStmtLevel;
 
+typedef enum 
+{
+	LOG_STATEMENT_SEARCH_PATH_NEVER = 0,
+	LOG_STATEMENT_SEARCH_PATH_NON_DEFAULT,
+	LOG_STATEMENT_SEARCH_PATH_ALWAYS
+} LogStmtSearchPathOptions;
+
+
 extern PGDLLIMPORT int log_statement;
 
 extern List *pg_parse_query(const char *query_string);
diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h
index e734493a48..34b406092b 100644
--- a/src/include/utils/guc.h
+++ b/src/include/utils/guc.h
@@ -270,6 +270,7 @@ extern PGDLLIMPORT double log_statement_sample_rate;
 extern PGDLLIMPORT double log_xact_sample_rate;
 extern PGDLLIMPORT char *backtrace_functions;
 extern PGDLLIMPORT char *backtrace_symbol_list;
+extern PGDLLIMPORT int log_statement_search_path;
 
 extern PGDLLIMPORT int temp_file_limit;
 
-- 
2.35.1

Reply via email to