Re: Exec statement logging - Mailing list pgsql-patches
| From | Bruce Momjian |
|---|---|
| Subject | Re: Exec statement logging |
| Date | |
| Msg-id | 200505161924.j4GJORS11092@candle.pha.pa.us Whole thread Raw |
| In response to | Re: Exec statement logging (Simon Riggs <simon@2ndquadrant.com>) |
| Responses |
Re: Exec statement logging
|
| List | pgsql-patches |
OK, new patch. I used portal->sourceText as Tom suggested, and checked
for NULL before printing. I put the original query in brackets in the
log output, patch attached.
I would like to also do this for server-side EXECUTE. I am have
attached a second version that does it by using the existing loop we use
to check for a match for log_statement patterns. The code checks for an
ExecuteStmt node, and saves the prepare string that matches the portal.
The system can't determine the actual prepare string, so I used the
debug_query_string for a server-side PREPARE --- previously it just had
a null for the prepare string. Also, rather than change the API for
pg_parse_query(), I use a global variable that I check after the
function call. Here is sample output with log_statement and
log_min_duration_statement enabled:
PREPARE xx AS SELECT 1;
LOG: statement: PREPARE xx AS SELECT 1;
LOG: duration: 1.102 ms statement: PREPARE xx AS SELECT 1;
PREPARE
EXECUTE xx;
LOG: statement: EXECUTE xx; [client PREPARE: PREPARE xx AS SELECT 1;]
LOG: duration: 0.990 ms statement: EXECUTE xx; [client PREPARE: PREPARE xx AS SELECT 1;]
?column?
----------
1
(1 row)
---------------------------------------------------------------------------
Simon Riggs wrote:
> On Sat, 2005-05-14 at 16:55 -0400, Bruce Momjian wrote:
> > Uh, I am confused by this. Your code test is:
> >
> > + if ((log_statement == LOGSTMT_ALL && save_log_duration) ||
> > + save_log_min_duration_statement)
> > + gettimeofday(&start_t, NULL);
> >
> > First, log_min_duration_statement == -1 turns off logging. Your test
> > would enable it for -1. Also, you added "log_statement == LOGSTMT_ALL",
> > but don't have a similar test lower down where gettimeofday is used, so
> > I don't understand its usage here, or why it would be used in this
> > place. The original test is:
> >
> > + if (save_log_duration || save_log_min_duration_statement != -1)
> > + gettimeofday(&start_t, NULL);
>
> Yes, that looks wrong. Thanks for your diligence. I'm sorry that you've
> had to both spot an error and recode for it, I was expecting to do that.
>
> > One thing you did was to log debug_query_string, but I don't see how
> > that could be the right value. I assume it would be empty in a
> > client-side execute, or be the previous query. I instead used "EXECUTE
> > portal_name" because that is what we are passed from the client.
>
> I used the debug_query_string because even in the EXEC case it is set,
> so that the SQL statement appears correctly in pg_stat_activity. It may
> look wrong, but it is there.
>
> That part, at least, is correct, since I have used the patch in tuning.
>
> Perhaps it is only there when stats_command_string is set?
>
> Setting the SQL string to be only EXECUTE portal_name makes the log
> output almost useless for query tuning, so please reconsider that.
> Perhaps you could include both the portal name and the SQL statement?
>
> Best Regards, Simon Riggs
>
--
Bruce Momjian | http://candle.pha.pa.us
pgman@candle.pha.pa.us | (610) 359-1001
+ If your life is a hard drive, | 13 Roberts Road
+ Christ can be your backup. | Newtown Square, Pennsylvania 19073
Index: src/backend/tcop/postgres.c
===================================================================
RCS file: /cvsroot/pgsql/src/backend/tcop/postgres.c,v
retrieving revision 1.443
diff -c -c -r1.443 postgres.c
*** src/backend/tcop/postgres.c 21 Apr 2005 19:18:13 -0000 1.443
--- src/backend/tcop/postgres.c 16 May 2005 03:40:00 -0000
***************
*** 1011,1017 ****
stop_t.tv_sec--;
stop_t.tv_usec += 1000000;
}
! usecs = (long) (stop_t.tv_sec - start_t.tv_sec) * 1000000 + (long) (stop_t.tv_usec - start_t.tv_usec);
/* Only print duration if we previously printed the statement. */
if (statement_logged && save_log_duration)
--- 1011,1018 ----
stop_t.tv_sec--;
stop_t.tv_usec += 1000000;
}
! usecs = (long) (stop_t.tv_sec - start_t.tv_sec) * 1000000 +
! (long) (stop_t.tv_usec - start_t.tv_usec);
/* Only print duration if we previously printed the statement. */
if (statement_logged && save_log_duration)
***************
*** 1579,1584 ****
--- 1580,1590 ----
bool is_trans_exit = false;
bool completed;
char completionTag[COMPLETION_TAG_BUFSIZE];
+ struct timeval start_t,
+ stop_t;
+ bool save_log_duration = log_duration;
+ int save_log_min_duration_statement = log_min_duration_statement;
+ bool save_log_statement_stats = log_statement_stats;
/* Adjust destination to tell printtup.c what to do */
dest = whereToSendOutput;
***************
*** 1615,1620 ****
--- 1621,1648 ----
set_ps_display(portal->commandTag);
+ /*
+ * We use save_log_* so "SET log_duration = true" and "SET
+ * log_min_duration_statement = true" don't report incorrect time
+ * because gettimeofday() wasn't called. Similarly,
+ * log_statement_stats has to be captured once.
+ */
+ if (save_log_duration || save_log_min_duration_statement != -1)
+ gettimeofday(&start_t, NULL);
+
+ if (save_log_statement_stats)
+ ResetUsage();
+
+ statement_logged = false;
+ if (log_statement == LOGSTMT_ALL)
+ {
+ /* We have the portal, so output the source query. */
+ ereport(LOG,
+ (errmsg("statement: EXECUTE %s [PREPARE: %s]", portal_name,
+ portal->sourceText ? portal->sourceText : "")));
+ statement_logged = true;
+ }
+
BeginCommand(portal->commandTag, dest);
/* Check for transaction-control commands */
***************
*** 1709,1714 ****
--- 1737,1786 ----
pq_putemptymessage('s');
}
+ /*
+ * Combine processing here as we need to calculate the query duration
+ * in both instances.
+ */
+ if (save_log_duration || save_log_min_duration_statement != -1)
+ {
+ long usecs;
+
+ gettimeofday(&stop_t, NULL);
+ if (stop_t.tv_usec < start_t.tv_usec)
+ {
+ stop_t.tv_sec--;
+ stop_t.tv_usec += 1000000;
+ }
+ usecs = (long) (stop_t.tv_sec - start_t.tv_sec) * 1000000 +
+ (long) (stop_t.tv_usec - start_t.tv_usec);
+
+ /* Only print duration if we previously printed the statement. */
+ if (statement_logged && save_log_duration)
+ ereport(LOG,
+ (errmsg("duration: %ld.%03ld ms",
+ (long) ((stop_t.tv_sec - start_t.tv_sec) * 1000 +
+ (stop_t.tv_usec - start_t.tv_usec) / 1000),
+ (long) (stop_t.tv_usec - start_t.tv_usec) % 1000)));
+
+ /*
+ * Output a duration_statement to the log if the query has
+ * exceeded the min duration, or if we are to print all durations.
+ */
+ if (save_log_min_duration_statement == 0 ||
+ (save_log_min_duration_statement > 0 &&
+ usecs >= save_log_min_duration_statement * 1000))
+ ereport(LOG,
+ (errmsg("duration: %ld.%03ld ms statement: EXECUTE %s [PREPARE: %s]",
+ (long) ((stop_t.tv_sec - start_t.tv_sec) * 1000 +
+ (stop_t.tv_usec - start_t.tv_usec) / 1000),
+ (long) (stop_t.tv_usec - start_t.tv_usec) % 1000,
+ portal_name,
+ portal->sourceText ? portal->sourceText : "")));
+ }
+
+ if (save_log_statement_stats)
+ ShowUsage("QUERY STATISTICS");
+
debug_query_string = NULL;
}
Index: src/backend/commands/prepare.c
===================================================================
RCS file: /cvsroot/pgsql/src/backend/commands/prepare.c,v
retrieving revision 1.36
diff -c -c -r1.36 prepare.c
*** src/backend/commands/prepare.c 1 Jan 2005 05:43:06 -0000 1.36
--- src/backend/commands/prepare.c 16 May 2005 18:00:52 -0000
***************
*** 104,112 ****
/* Generate plans for queries. Snapshot is already set. */
plan_list = pg_plan_queries(query_list, NULL, false);
! /* Save the results. */
StorePreparedStatement(stmt->name,
! NULL, /* text form not available */
commandTag,
query_list,
plan_list,
--- 104,115 ----
/* Generate plans for queries. Snapshot is already set. */
plan_list = pg_plan_queries(query_list, NULL, false);
! /*
! * Save the results. We don't have the query string for this PREPARE,
! * but we do have the string we got from the client, so use that.
! */
StorePreparedStatement(stmt->name,
! debug_query_string,
commandTag,
query_list,
plan_list,
Index: src/backend/tcop/postgres.c
===================================================================
RCS file: /cvsroot/pgsql/src/backend/tcop/postgres.c,v
retrieving revision 1.443
diff -c -c -r1.443 postgres.c
*** src/backend/tcop/postgres.c 21 Apr 2005 19:18:13 -0000 1.443
--- src/backend/tcop/postgres.c 16 May 2005 18:00:54 -0000
***************
*** 73,78 ****
--- 73,79 ----
*/
const char *debug_query_string; /* for pgmonitor and
* log_min_error_statement */
+ char *prepare_string = NULL; /* used for passing PREPARE source string */
/* Note: whereToSendOutput is initialized for the bootstrap/standalone case */
CommandDest whereToSendOutput = Debug;
***************
*** 467,504 ****
List *raw_parsetree_list;
ListCell *parsetree_item;
statement_logged = false;
- if (log_statement == LOGSTMT_ALL)
- {
- ereport(LOG,
- (errmsg("statement: %s", query_string)));
- statement_logged = true;
- }
if (log_parser_stats)
ResetUsage();
raw_parsetree_list = raw_parser(query_string);
! /* do log_statement tests for mod and ddl */
! if (log_statement == LOGSTMT_MOD ||
log_statement == LOGSTMT_DDL)
{
foreach(parsetree_item, raw_parsetree_list)
{
Node *parsetree = (Node *) lfirst(parsetree_item);
const char *commandTag;
!
if (IsA(parsetree, ExplainStmt) &&
((ExplainStmt *) parsetree)->analyze)
parsetree = (Node *) (((ExplainStmt *) parsetree)->query);
!
if (IsA(parsetree, PrepareStmt))
parsetree = (Node *) (((PrepareStmt *) parsetree)->query);
!
if (IsA(parsetree, SelectStmt))
continue; /* optimization for frequent command */
if (log_statement == LOGSTMT_MOD &&
(IsA(parsetree, InsertStmt) ||
IsA(parsetree, UpdateStmt) ||
--- 468,526 ----
List *raw_parsetree_list;
ListCell *parsetree_item;
+ /* reset prepare_string */
+ if (prepare_string != NULL)
+ pfree(prepare_string);
+ prepare_string = NULL;
+
statement_logged = false;
if (log_parser_stats)
ResetUsage();
raw_parsetree_list = raw_parser(query_string);
! if (log_statement == LOGSTMT_ALL ||
! log_statement == LOGSTMT_MOD ||
log_statement == LOGSTMT_DDL)
{
foreach(parsetree_item, raw_parsetree_list)
{
Node *parsetree = (Node *) lfirst(parsetree_item);
const char *commandTag;
!
if (IsA(parsetree, ExplainStmt) &&
((ExplainStmt *) parsetree)->analyze)
parsetree = (Node *) (((ExplainStmt *) parsetree)->query);
!
if (IsA(parsetree, PrepareStmt))
parsetree = (Node *) (((PrepareStmt *) parsetree)->query);
!
if (IsA(parsetree, SelectStmt))
continue; /* optimization for frequent command */
+
+ if (IsA(parsetree, ExecuteStmt))
+ {
+ ExecuteStmt *stmt = (ExecuteStmt *) parsetree;
+ PreparedStatement *entry;
+ /*
+ * For the first EXECUTE we find before printing the
+ * statement string, find the client statement that
+ * generated the PREPARE.
+ */
+ if ((entry = FetchPreparedStatement(stmt->name, false)) != NULL)
+ {
+ if (prepare_string == NULL && entry->query_string)
+ {
+ prepare_string = palloc(strlen(entry->query_string) +
+ strlen(" [client PREPARE: %s]") - 1);
+ sprintf(prepare_string, " [client PREPARE: %s]",
+ entry->query_string);
+ }
+ }
+ }
+
if (log_statement == LOGSTMT_MOD &&
(IsA(parsetree, InsertStmt) ||
IsA(parsetree, UpdateStmt) ||
***************
*** 508,531 ****
((CopyStmt *) parsetree)->is_from))) /* COPY FROM */
{
ereport(LOG,
! (errmsg("statement: %s", query_string)));
statement_logged = true;
break;
}
commandTag = CreateCommandTag(parsetree);
! if (strncmp(commandTag, "CREATE ", strlen("CREATE ")) == 0 ||
! strncmp(commandTag, "ALTER ", strlen("ALTER ")) == 0 ||
! strncmp(commandTag, "DROP ", strlen("DROP ")) == 0 ||
! IsA(parsetree, GrantStmt) || /* GRANT or REVOKE */
! IsA(parsetree, CommentStmt))
{
ereport(LOG,
! (errmsg("statement: %s", query_string)));
statement_logged = true;
break;
}
}
}
if (log_parser_stats)
ShowUsage("PARSER STATISTICS");
--- 530,565 ----
((CopyStmt *) parsetree)->is_from))) /* COPY FROM */
{
ereport(LOG,
! (errmsg("statement: %s%s", query_string,
! prepare_string ? prepare_string : "")));
statement_logged = true;
break;
}
commandTag = CreateCommandTag(parsetree);
! if ((log_statement == LOGSTMT_MOD ||
! log_statement == LOGSTMT_DDL) &&
! (strncmp(commandTag, "CREATE ", strlen("CREATE ")) == 0 ||
! strncmp(commandTag, "ALTER ", strlen("ALTER ")) == 0 ||
! strncmp(commandTag, "DROP ", strlen("DROP ")) == 0 ||
! IsA(parsetree, GrantStmt) || /* GRANT or REVOKE */
! IsA(parsetree, CommentStmt)))
{
ereport(LOG,
! (errmsg("statement: %s%s", query_string,
! prepare_string ? prepare_string : "")));
statement_logged = true;
break;
}
}
}
+
+ if (log_statement == LOGSTMT_ALL)
+ {
+ ereport(LOG,
+ (errmsg("statement: %s%s", query_string,
+ prepare_string ? prepare_string : "")));
+ statement_logged = true;
+ }
if (log_parser_stats)
ShowUsage("PARSER STATISTICS");
***************
*** 740,746 ****
bool save_log_duration = log_duration;
int save_log_min_duration_statement = log_min_duration_statement;
bool save_log_statement_stats = log_statement_stats;
!
/*
* Report query to various monitoring facilities.
*/
--- 774,781 ----
bool save_log_duration = log_duration;
int save_log_min_duration_statement = log_min_duration_statement;
bool save_log_statement_stats = log_statement_stats;
! char *my_prepare_string = NULL;
!
/*
* Report query to various monitoring facilities.
*/
***************
*** 796,801 ****
--- 831,840 ----
*/
parsetree_list = pg_parse_query(query_string);
+ /* If EXECUTE generated a PREPARE source, record it for later */
+ if (prepare_string != NULL)
+ my_prepare_string = pstrdup(prepare_string);
+
/*
* Switch back to transaction context to enter the loop.
*/
***************
*** 1029,1039 ****
(save_log_min_duration_statement > 0 &&
usecs >= save_log_min_duration_statement * 1000))
ereport(LOG,
! (errmsg("duration: %ld.%03ld ms statement: %s",
(long) ((stop_t.tv_sec - start_t.tv_sec) * 1000 +
(stop_t.tv_usec - start_t.tv_usec) / 1000),
(long) (stop_t.tv_usec - start_t.tv_usec) % 1000,
! query_string)));
}
if (save_log_statement_stats)
--- 1068,1079 ----
(save_log_min_duration_statement > 0 &&
usecs >= save_log_min_duration_statement * 1000))
ereport(LOG,
! (errmsg("duration: %ld.%03ld ms statement: %s%s",
(long) ((stop_t.tv_sec - start_t.tv_sec) * 1000 +
(stop_t.tv_usec - start_t.tv_usec) / 1000),
(long) (stop_t.tv_usec - start_t.tv_usec) % 1000,
! query_string,
! prepare_string ? prepare_string : "")));
}
if (save_log_statement_stats)
pgsql-patches by date: