Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1nw8YU-0008Mq-0A for pgsql-hackers@arkaria.postgresql.org; Tue, 31 May 2022 20:33:30 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.92) (envelope-from ) id 1nw8YS-0007SA-Oo for pgsql-hackers@arkaria.postgresql.org; Tue, 31 May 2022 20:33:28 +0000 Received: from magus.postgresql.org ([2a02:c0:301:0:ffff::29]) by malur.postgresql.org with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1nw8YR-0007S0-UX for pgsql-hackers@lists.postgresql.org; Tue, 31 May 2022 20:33:28 +0000 Received: from out3-smtp.messagingengine.com ([66.111.4.27]) by magus.postgresql.org with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1nw8YO-0004F8-Qe for pgsql-hackers@lists.postgresql.org; Tue, 31 May 2022 20:33:27 +0000 Received: from compute3.internal (compute3.nyi.internal [10.202.2.43]) by mailout.nyi.internal (Postfix) with ESMTP id 4C2B05C011A for ; Tue, 31 May 2022 16:33:22 -0400 (EDT) Received: from mailfrontend2 ([10.202.2.163]) by compute3.internal (MEProxy); Tue, 31 May 2022 16:33:22 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ilmari.org; h=cc :content-type:date:date:from:from:in-reply-to:message-id :mime-version:reply-to:sender:subject:subject:to:to; s=fm2; t= 1654029202; x=1654115602; bh=fuw8Ixlbe74Kr3HCpoDk+hF+aMMulRAoCKZ 3q8Tifb4=; b=LaRlEO4EG2qte/ewe5OOjlDaCOdi5mR/281NlSj4agOEp0ocJYo ed0QB26eZBvd2HcTGRXssDj+G2A3l5YP7P7kWCOiTvCzsNFHc1ny5otghs49qXOT EwCXs91ZeVp+Vd+HS3EYhkJtT0OYYw5TyU9rwJrNA/7UD0WtMHDYexie2qs1MpTt iJRk3rWKUbOz7bAQaCJEgPYXyLbJ1TrJrgvsRsDnjM+j1j/LGFQ/VF8IvPJ+IezK uZz1bAOPQWPmQjftQonB9aPe7n1IIxWWOj+xwVWeQKkl5y43pIn2Hnw+6X1t7AT2 W27/7epIYpsSv1azOfK+RSgHaT4qT2q41xQ== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:content-type:date:date:feedback-id :feedback-id:from:from:in-reply-to:message-id:mime-version :reply-to:sender:subject:subject:to:to:x-me-proxy:x-me-proxy :x-me-sender:x-me-sender:x-sasl-enc; s=fm1; t=1654029202; x= 1654115602; bh=fuw8Ixlbe74Kr3HCpoDk+hF+aMMulRAoCKZ3q8Tifb4=; b=V Bs+J8brJ694T4+ri2OBO3g2T4EHHIV0jovvlQI2cq35cCmWcprRtK+bIGc96p9T8 qCmSAq9rE79ek2MSWRlnlgnYUNV+9v+1bSrgHXw+hGcStrvxtmGG6iwuXkcwDhSj M/xujqoleczZZjHb9mN6vIr5kzisKj9uHvDxsl987I5tkmPRugbTmhPfgYErirlq 3P1bjmDCDs6XB1t/baLr342Dmq2IGpUg/BogrdRLe+VrZI+DeNyPHp1trGedlisL 4gIvtSirilK9P3Ihrl0GfvwK6d6rYuNJicOuznDfp8sT8z0+feyQ8T4oPU4KaXYc wH8D0NJKVZZVYoRrMrS7w== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedvfedrkeekgdduhedtucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucenucfjughrpefhvffufffkfgggtgesmhdtreertd erjeenucfhrhhomhepffgrghhfihhnnhgpkfhlmhgrrhhipgforghnnhhsnohkvghruceo ihhlmhgrrhhisehilhhmrghrihdrohhrgheqnecuggftrfgrthhtvghrnhepvddvvdevve fhvefgfeffvdfhheehkeeftdffffeftdejffduleevveegteetteeinecuvehluhhsthgv rhfuihiivgeptdenucfrrghrrghmpehmrghilhhfrhhomhepihhlmhgrrhhisehilhhmrg hrihdrohhrgh X-ME-Proxy: Feedback-ID: i1ff147bf:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA for ; Tue, 31 May 2022 16:33:21 -0400 (EDT) From: =?utf-8?Q?Dagfinn_Ilmari_Manns=C3=A5ker?= To: pgsql-hackers@lists.postgresql.org Subject: Logging query parmeters in auto_explain Date: Tue, 31 May 2022 21:33:20 +0100 Message-ID: <87ee09mohb.fsf@wibble.ilmari.org> User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/27.1 (gnu/linux) MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk --=-=-= Content-Type: text/plain Hi hackers, Inspired by a question on IRC, I noticed that while the core statement logging system gained the option to log statement parameters in PG 13, auto_explain was left out. Here's a patch that adds a corresponding auto_explain.log_parameter_max_length config setting, which controls the "Query Parameters" node in the logged plan. Just like in core, the default is -1, which logs the parameters in full, and 0 disables parameter logging, while any other value truncates each parameter to that many bytes. - ilmari --=-=-= Content-Type: text/x-diff Content-Disposition: inline; filename=0001-Log-query-parameters-in-auto_explain.patch From 24a31273475f26b3174a6e2178d0121f5e23b5f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dagfinn=20Ilmari=20Manns=C3=A5ker?= Date: Tue, 31 May 2022 21:12:12 +0100 Subject: [PATCH] Log query parameters in auto_explain Add an auto_explain.log_parameter_max_length config setting, similar to the corresponding core setting, that controls the inclusion of query parameters in the logged explain output. --- contrib/auto_explain/auto_explain.c | 15 +++++++++++++ contrib/auto_explain/t/001_auto_explain.pl | 25 ++++++++++++++++++++-- doc/src/sgml/auto-explain.sgml | 19 ++++++++++++++++ src/backend/commands/explain.c | 22 +++++++++++++++++++ src/include/commands/explain.h | 1 + 5 files changed, 80 insertions(+), 2 deletions(-) diff --git a/contrib/auto_explain/auto_explain.c b/contrib/auto_explain/auto_explain.c index c9a0d947c8..1ba7536879 100644 --- a/contrib/auto_explain/auto_explain.c +++ b/contrib/auto_explain/auto_explain.c @@ -19,12 +19,14 @@ #include "common/pg_prng.h" #include "executor/instrument.h" #include "jit/jit.h" +#include "nodes/params.h" #include "utils/guc.h" PG_MODULE_MAGIC; /* GUC variables */ static int auto_explain_log_min_duration = -1; /* msec or -1 */ +static int auto_explain_log_parameter_max_length = -1; /* bytes or -1 */ static bool auto_explain_log_analyze = false; static bool auto_explain_log_verbose = false; static bool auto_explain_log_buffers = false; @@ -105,6 +107,18 @@ _PG_init(void) NULL, NULL); + DefineCustomIntVariable("auto_explain.log_parameter_max_length", + "Sets the maximum length of query parameters to log.", + "Zero logs no query parameters, -1 logs them in full.", + &auto_explain_log_parameter_max_length, + -1, + -1, INT_MAX, + PGC_SUSET, + GUC_UNIT_BYTE, + NULL, + NULL, + NULL); + DefineCustomBoolVariable("auto_explain.log_analyze", "Use EXPLAIN ANALYZE for plan logging.", NULL, @@ -389,6 +403,7 @@ explain_ExecutorEnd(QueryDesc *queryDesc) ExplainBeginOutput(es); ExplainQueryText(es, queryDesc); + ExplainQueryParameters(es, queryDesc->params, auto_explain_log_parameter_max_length); ExplainPrintPlan(es, queryDesc); if (es->analyze && auto_explain_log_triggers) ExplainPrintTriggers(es, queryDesc); diff --git a/contrib/auto_explain/t/001_auto_explain.pl b/contrib/auto_explain/t/001_auto_explain.pl index 82e4d9d15c..ac57c8d6bf 100644 --- a/contrib/auto_explain/t/001_auto_explain.pl +++ b/contrib/auto_explain/t/001_auto_explain.pl @@ -13,20 +13,21 @@ $node->append_conf('postgresql.conf', "shared_preload_libraries = 'auto_explain'"); $node->append_conf('postgresql.conf', "auto_explain.log_min_duration = 0"); +$node->append_conf('postgresql.conf', "auto_explain.log_parameter_max_length = -1"); $node->append_conf('postgresql.conf', "auto_explain.log_analyze = on"); $node->start; # run a couple of queries $node->safe_psql("postgres", "SELECT * FROM pg_class;"); $node->safe_psql("postgres", - "SELECT * FROM pg_proc WHERE proname = 'int4pl';"); + q{PREPARE get_proc(name) AS SELECT * FROM pg_proc WHERE proname = $1; EXECUTE get_proc('int4pl');}); # emit some json too $node->append_conf('postgresql.conf', "auto_explain.log_format = json"); $node->reload; $node->safe_psql("postgres", "SELECT * FROM pg_proc;"); $node->safe_psql("postgres", - "SELECT * FROM pg_class WHERE relname = 'pg_class';"); + q{PREPARE get_class(name) AS SELECT * FROM pg_class WHERE relname = $1; EXECUTE get_class('pg_class');}); $node->stop('fast'); @@ -34,6 +35,16 @@ my $log_contents = slurp_file($log); +like( + $log_contents, + qr/Query Text: SELECT \* FROM pg_class;/, + "query text logged, text mode"); + +like( + $log_contents, + qr/Query Parameters: \$1 = 'int4pl'/, + "query parameters logged, text mode"); + like( $log_contents, qr/Seq Scan on pg_class/, @@ -44,6 +55,16 @@ qr/Index Scan using pg_proc_proname_args_nsp_index on pg_proc/, "index scan logged, text mode"); +like( + $log_contents, + qr/"Query Text": "SELECT \* FROM pg_proc;"/, + "query text logged, json mode"); + +like( + $log_contents, + qr/"Query Parameters": "\$1 = 'pg_class'"/, + "query parameters logged, json mode"); + like( $log_contents, qr/"Node Type": "Seq Scan"[^}]*"Relation Name": "pg_proc"/s, diff --git a/doc/src/sgml/auto-explain.sgml b/doc/src/sgml/auto-explain.sgml index 30e35a714a..a033c9c685 100644 --- a/doc/src/sgml/auto-explain.sgml +++ b/doc/src/sgml/auto-explain.sgml @@ -63,6 +63,25 @@ + + + auto_explain.log_parameter_max_length (integer) + + auto_explain.log_parameter_max_length configuration parameter + + + + + auto_explain.log_parameter_max_length controls the + logging of query parameter values. A value of-1 (the + default) logs the parameter values in full. 0 disables + logging of parameter values. A value greater than zero truncates each + parameter value to that many bytes. Only superusers can change this + setting. + + + + auto_explain.log_analyze (boolean) diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c index 5d1f7089da..8584e3585d 100644 --- a/src/backend/commands/explain.c +++ b/src/backend/commands/explain.c @@ -972,6 +972,28 @@ ExplainQueryText(ExplainState *es, QueryDesc *queryDesc) ExplainPropertyText("Query Text", queryDesc->sourceText, es); } +/* + * ExplainQueryParameters - + * add a "Query Parameters" node that describes the parameters of the query, + * if any + * + * The caller should have set up the options fields of *es, as well as + * initializing the output buffer es->str. + * + */ +void +ExplainQueryParameters(ExplainState *es, ParamListInfo params, int maxlen) +{ + char *str; + + if (params == NULL || params->numParams == 0 || maxlen == 0) + return; + + str = BuildParamLogString(params, NULL, maxlen); + if (str && str[0] != '\0') + ExplainPropertyText("Query Parameters", str, es); +} + /* * report_triggers - * report execution stats for a single relation's triggers diff --git a/src/include/commands/explain.h b/src/include/commands/explain.h index 666977fb1f..9ebde089ae 100644 --- a/src/include/commands/explain.h +++ b/src/include/commands/explain.h @@ -99,6 +99,7 @@ extern void ExplainPrintTriggers(ExplainState *es, QueryDesc *queryDesc); extern void ExplainPrintJITSummary(ExplainState *es, QueryDesc *queryDesc); extern void ExplainQueryText(ExplainState *es, QueryDesc *queryDesc); +extern void ExplainQueryParameters(ExplainState *es, ParamListInfo params, int maxlen); extern void ExplainBeginOutput(ExplainState *es); extern void ExplainEndOutput(ExplainState *es); -- 2.30.2 --=-=-=--