Re: Exec statement logging

Поиск
Список
Период
Сортировка
От Bruce Momjian
Тема Re: Exec statement logging
Дата
Msg-id 200505161924.j4GJORS11092@candle.pha.pa.us
обсуждение исходный текст
Ответ на Re: Exec statement logging  (Simon Riggs <simon@2ndquadrant.com>)
Ответы Re: Exec statement logging
Список 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 по дате отправления:

Предыдущее
От: Tom Lane
Дата:
Сообщение: Re: updated GiST patch
Следующее
От: Tom Lane
Дата:
Сообщение: Re: Exec statement logging