Re: libpq debug log - Mailing list pgsql-hackers

From Kyotaro Horiguchi
Subject Re: libpq debug log
Date
Msg-id 20210209.172610.1363545530770133087.horikyota.ntt@gmail.com
Whole thread Raw
In response to RE: libpq debug log  ("iwata.aya@fujitsu.com" <iwata.aya@fujitsu.com>)
Responses RE: libpq debug log  ("iwata.aya@fujitsu.com" <iwata.aya@fujitsu.com>)
List pgsql-hackers
At Mon, 8 Feb 2021 14:57:47 +0000, "iwata.aya@fujitsu.com" <iwata.aya@fujitsu.com> wrote in 
> I update the patch.
> I modified code according to review comments of Tsunakawa san and Horiguchi san.
> 
> And I fixed some bugs.

Thanks for the new version.

+typedef enum
+{
+    MSGDIR_FROM_BACKEND,
+    MSGDIR_FROM_FRONTEND
+} PGCommSource;

This is halfly exposed to other part of libpq. Specifically only
MSGDIR_FROM_BACKEND is used in fe-misc.c and only for
pgLogMessageString and pqLogMessagenchar. I would suggest to hide this
enum from fe-misc.c.

Looking into pqLogMessageString,

+pqLogMessageString(PGconn *conn, const char *v, int length, PGCommSource source)
+{
+    if (source == MSGDIR_FROM_BACKEND && conn->be_msg->state != LOG_CONTENTS)
+    {
+        pqLogInvalidProtocol(conn, MSGDIR_FROM_BACKEND);
+        return;    /* XXX ??? */
+    }
+
+    fprintf(conn->Pfdebug, "\"%s\"", v);
+    if (source == MSGDIR_FROM_BACKEND)
+        pqTraceMaybeBreakLine(length, conn);
+}

The only part that shared by both be and fe is the fprintf().  I think
it can be naturally split into separate functions for backend and
frontend messages.

Looking into pqLogMessagenchar,

+/*
+ * pqLogMessagenchar: output a string of exactly len bytes message to the log
+ */
+void
+pqLogMessagenchar(PGconn *conn, const char *v, int len, PGCommSource commsource)
+{
+    fprintf(conn->Pfdebug, "\'");
+    pqLogBinaryMsg(conn, v, len, commsource);
+    fprintf(conn->Pfdebug, "\'");
+    pqTraceMaybeBreakLine(len, conn);
+}

+static void
+pqLogBinaryMsg(PGconn *conn, const char *v, int length, PGCommSource source)
+{
+    int            i,
+                pin;
+
+    if (source == MSGDIR_FROM_BACKEND && conn->be_msg->state != LOG_CONTENTS)
+    {
+        pqLogInvalidProtocol(conn, MSGDIR_FROM_BACKEND);
+        return;    /* XXX ??? */

# What is this???

+    }
    .. shared part
+}

pqLogMessagenchar is the sole caller of pqLogBinaryMsg. So we can
refactor the two functions and have pqLogMessagenchar_for_be and
_for_fe without a fear of the side effect to other callers.  (The
names are discussed below.)


+typedef enum PGLogState
+{

This is libpq-logging.c internal type. It is not needed to be exposed.



+extern void pqTraceForcelyBreakLine(int size, PGconn *conn);
+extern void pqStoreFrontendMsg(PGconn *conn, PGLogMsgDataType type, int length)+extern void pqStoreFeMsgStart(PGconn
*conn,char type);
 
+extern void pqLogFrontendMsg(PGconn *conn, int msgLen);
+extern void pqLogMessageByte1(PGconn *conn, char v);
+extern void pqLogMessageInt(PGconn *conn, int v, int length);
+extern void pqLogMessageString(PGconn *conn, const char *v, int length,
+                               PGCommSource commsource);
+extern void pqLogMessagenchar(PGconn *conn, const char *v, int length,
+                              PGCommSource commsource);

The API functions looks like randomly/inconsistently named and
designed.  I think that API should be in more structurally designed.

The comments about individual function names follow.

+/*
+ * pqTraceForcelyBreakLine:
+ *         If message is not completed, print a line break and reset.
+ */
+void
+pqTraceForcelyBreakLine(int size, PGconn *conn)
+{
+    fprintf(conn->Pfdebug, "\n");
+    pqTraceResetBeMsg(conn);
+}

Differently from the comment, this function doesn't work in a
conditional way nor in a forceful way. It is just putting a new line
and resetting the backend message variables.  I would name this as
pqTrace(Finish|Close)BeMsgLog().

+/*
+ * pqStoreFrontendMsg
+ *        Keep track of a from-frontend message that was just written to the
+ *        output buffer.
+ *
+ * Frontend messages are constructed piece by piece, and the message length
+ * is determined at the end, but sent to the server first; so for tracing
+ * purposes we store everything in memory and print to the trace file when
+ * the message is complete.
+ */
+void
+pqStoreFrontendMsg(PGconn *conn, PGLogMsgDataType type, int length)
+{

I would name this as pqTrace(Store/Append)FeMsg().


+void
+pqStoreFeMsgStart(PGconn *conn, char type)
+{
+    conn->fe_msg->msg_type = type;
+}

The name says that "stores the message "start"". But it actually
stores the message type. I would name this as
pqTraceSetFeMsgType(). Or in contrast to pqTraceFinishBeMsgLog, this
can be named as pqTrace(Start|Begin|Init)BeMsgLog().


+ * pqLogFrontendMsg
+ *        Print accumulated frontend message pieces to the trace file.
+ */
+void
+pqLogFrontendMsg(PGconn *conn, int msgLen)

I would name this as pqTraceEmitFeMsgLog().


+ * pqLogMessageByte1: output 1 char from-backend message to the log
+ * pqLogMessageInt: output a 2- or 4-byte integer from-backend msg to the log

I would name this as pqTraceEmitBeByteLog(), pqTraceEmitBeIntLog()
respectively.

+ * pqLogMessageString: output a null-terminated string to the log

This function is used for both directions. pqTraceEmitStringLog(). If it is split into fe and be parts, they would be
pqTraceEmit(Be|Fe)StringLog().


+ * pqLogMessagenchar: output a string of exactly len bytes message to the log

This logs a byte sequence in hexadecimals. I would name that as
pqTraceEmitBytesLog(). Or pqTraceEmit(Be|Fe)BytesLog().



...I finish once here.

Is there any thoughts? Optinions on the namings?

regards.

-- 
Kyotaro Horiguchi
NTT Open Source Software Center



pgsql-hackers by date:

Previous
From: "Andrey V. Lepikhov"
Date:
Subject: Re: [POC] Fast COPY FROM command for the table with foreign partitions
Next
From: Kyotaro Horiguchi
Date:
Subject: Re: libpq debug log