diff --git a/doc/src/sgml/libpq.sgml b/doc/src/sgml/libpq.sgml
index d2e5b08..0d46d38 100644
--- a/doc/src/sgml/libpq.sgml
+++ b/doc/src/sgml/libpq.sgml
@@ -1589,6 +1589,28 @@ postgresql://%2Fvar%2Flib%2Fpostgresql/dbname
+
+
+ logdir
+
+
+ Path of directory where log file written. When both logdir
+ and logsize is set, logging is enabled.
+
+
+
+
+
+ logsize
+
+
+ Maximum log size. The unit is megabyte. When the log file size exceeds
+ to logsize, the log is output to another file.
+ When both logdir and logsize is set,
+ logging is enabled.
+
+
+
@@ -7472,6 +7494,26 @@ myEventProc(PGEventId evtId, void *evtInfo, void *passThrough)
linkend="libpq-connect-target-session-attrs"/> connection parameter.
+
+
+
+
+ PGLOGDIR
+
+ PGLOGDIR behaves the same as the connection parameter.
+
+
+
+
+
+
+ PGLOGSIZE
+
+ PGLOGSIZE behaves the same as the connection parameter.
+
+
@@ -8300,6 +8342,35 @@ int PQisthreadsafe();
+
+ Logging
+
+
+ trace log
+
+
+ logging
+
+
+
+ Libpq trace log can trace information about SQL queries which issued by
+ the libpq application. This output help determine whether the couse is
+ on backend side or application side and solve issues with the libpq Driver
+ when it use. The log without requiring recompile of the libpq application.
+
+
+
+ You can activate this log by setting both logdir and
+ logsize of the connection string, or by setting both
+ the environment variables PGLOGDIR and PGLOGSIZE.
+ The log trace file is written in a directory setting by PGLOGDIR
+ or logdir.
+ The file name is determined as libpq-%ProcessID-%Y-%m-%d_%H%M%S.log.
+ If the setting of the file path by the connection string or the environment variable is
+ incorrect, the log file is not created in the intended location.
+ The maximum log file size you set is output to the beginning of the file, so you can check it.
+
+
Building libpq Programs
diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index bc456fe..d6d16a0 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -325,6 +325,15 @@ static const internalPQconninfoOption PQconninfoOptions[] = {
"Target-Session-Attrs", "", 11, /* sizeof("read-write") = 11 */
offsetof(struct pg_conn, target_session_attrs)},
+ /* libpq trace log options */
+ {"logdir", "PGLOGDIR", NULL, NULL,
+ "Logdir", "", MAXPGPATH - 4,
+ offsetof(struct pg_conn, logdir)},
+
+ {"logsize", "PGLOGSIZE", NULL, NULL,
+ "Logsize", "", 5,
+ offsetof(struct pg_conn, logsize_str)},
+
/* Terminating entry --- MUST BE LAST */
{NULL, NULL, NULL, NULL,
NULL, NULL, 0}
@@ -1128,6 +1137,19 @@ connectOptions2(PGconn *conn)
}
/*
+ * If both size and directory of trace log was given,
+ * initialize a trace log.
+ */
+ if (conn->logsize_str && conn->logsize_str[0] != '\0')
+ conn->logsize = atoi(conn->logsize_str);
+
+ if (conn->logdir != NULL && conn->logsize > 0 && conn->logsize < 2048)
+ {
+ conn->logsize = conn->logsize * 1024 * 1024;
+ initTraceLog(conn);
+ }
+
+ /*
* If password was not given, try to look it up in password file. Note
* that the result might be different for each host/port pair.
*/
@@ -3716,6 +3738,14 @@ freePGconn(PGconn *conn)
termPQExpBuffer(&conn->errorMessage);
termPQExpBuffer(&conn->workBuffer);
+ /* clean up libpq trace log structures */
+ if (conn->logsize_str)
+ free(conn->logsize_str);
+ if (conn->logdir)
+ free(conn->logdir);
+ if (conn->traceDebug)
+ fclose(conn->traceDebug);
+
free(conn);
#ifdef WIN32
@@ -3751,6 +3781,8 @@ sendTerminateConn(PGconn *conn)
*/
if (conn->sock != PGINVALID_SOCKET && conn->status == CONNECTION_OK)
{
+ if (conn->traceDebug)
+ traceLog_fprintf(conn, true, "Send connection terminate message to backend: ");
/*
* Try to send "close connection" message to backend. Ignore any
* error.
@@ -4153,6 +4185,9 @@ int
pqPacketSend(PGconn *conn, char pack_type,
const void *buf, size_t buf_len)
{
+ if (conn->traceDebug)
+ traceLog_fprintf(conn, true, "Send connection start message to backend: ");
+
/* Start the message. */
if (pqPutMsgStart(pack_type, true, conn))
return STATUS_ERROR;
diff --git a/src/interfaces/libpq/fe-exec.c b/src/interfaces/libpq/fe-exec.c
index 6aed8c8..d45e795 100644
--- a/src/interfaces/libpq/fe-exec.c
+++ b/src/interfaces/libpq/fe-exec.c
@@ -879,7 +879,7 @@ pqInternalNotice(const PGNoticeHooks *hooks, const char *fmt,...)
res->errMsg = (char *) pqResultAlloc(res, strlen(msgBuf) + 2, false);
if (res->errMsg)
{
- sprintf(res->errMsg, "%s\n", msgBuf);
+ sprintf(res->errMsg, "NOTICE: %s\n", msgBuf);
/*
* Pass to receiver, then free it.
@@ -991,9 +991,9 @@ pqSaveParameterStatus(PGconn *conn, const char *name, const char *value)
pgParameterStatus *pstatus;
pgParameterStatus *prev;
- if (conn->Pfdebug)
- fprintf(conn->Pfdebug, "pqSaveParameterStatus: '%s' = '%s'\n",
- name, value);
+ if (conn->Pfdebug || conn->traceDebug)
+ traceLog_fprintf(conn, false, "pqSaveParameterStatus: '%s' = '%s'\n",
+ name, value);
/*
* Forget any old information about the parameter
@@ -1208,6 +1208,9 @@ fail:
int
PQsendQuery(PGconn *conn, const char *query)
{
+ if (conn->traceDebug)
+ traceLog_fprintf(conn, true, "PQsendQuery start :");
+
if (!PQsendQueryStart(conn))
return 0;
@@ -1219,6 +1222,9 @@ PQsendQuery(PGconn *conn, const char *query)
return 0;
}
+ if (conn->traceDebug)
+ traceLog_fprintf(conn, false, "Query: %s \n",query);
+
/* construct the outgoing Query message */
if (pqPutMsgStart('Q', false, conn) < 0 ||
pqPuts(query, conn) < 0 ||
@@ -1249,6 +1255,10 @@ PQsendQuery(PGconn *conn, const char *query)
/* OK, it's launched! */
conn->asyncStatus = PGASYNC_BUSY;
+
+ if (conn->traceDebug)
+ traceLog_fprintf(conn, true, "PQsendQuery end :");
+
return 1;
}
@@ -1266,6 +1276,9 @@ PQsendQueryParams(PGconn *conn,
const int *paramFormats,
int resultFormat)
{
+ if (conn->traceDebug)
+ traceLog_fprintf(conn, true, "PQsendQueryParams start :");
+
if (!PQsendQueryStart(conn))
return 0;
@@ -1283,6 +1296,9 @@ PQsendQueryParams(PGconn *conn,
return 0;
}
+ if (conn->traceDebug)
+ traceLog_fprintf(conn, true, "PQsendQueryParams end :");
+
return PQsendQueryGuts(conn,
command,
"", /* use unnamed statement */
@@ -1306,6 +1322,9 @@ PQsendPrepare(PGconn *conn,
const char *stmtName, const char *query,
int nParams, const Oid *paramTypes)
{
+ if (conn->traceDebug)
+ traceLog_fprintf(conn, true, "PQsendPrepare start :");
+
if (!PQsendQueryStart(conn))
return 0;
@@ -1337,6 +1356,9 @@ PQsendPrepare(PGconn *conn,
return 0;
}
+ if (conn->traceDebug)
+ traceLog_fprintf(conn, false, "Statement name: %s, Query: %s \n",stmtName, query);
+
/* construct the Parse message */
if (pqPutMsgStart('P', false, conn) < 0 ||
pqPuts(stmtName, conn) < 0 ||
@@ -1386,6 +1408,10 @@ PQsendPrepare(PGconn *conn,
/* OK, it's launched! */
conn->asyncStatus = PGASYNC_BUSY;
+
+ if (conn->traceDebug)
+ traceLog_fprintf(conn, true, "PQsendPrepare end :");
+
return 1;
sendFailed:
@@ -1492,6 +1518,9 @@ PQsendQueryGuts(PGconn *conn,
{
int i;
+ if (conn->traceDebug)
+ traceLog_fprintf(conn, true, "PQsendQueryGuts start :");
+
/* This isn't gonna work on a 2.0 server */
if (PG_PROTOCOL_MAJOR(conn->pversion) < 3)
{
@@ -1507,6 +1536,9 @@ PQsendQueryGuts(PGconn *conn,
if (command)
{
+ if (conn->traceDebug)
+ traceLog_fprintf(conn, false, "Statement name: %s, Command: %s \n",stmtName, command);
+
/* construct the Parse message */
if (pqPutMsgStart('P', false, conn) < 0 ||
pqPuts(stmtName, conn) < 0 ||
@@ -1638,6 +1670,10 @@ PQsendQueryGuts(PGconn *conn,
/* OK, it's launched! */
conn->asyncStatus = PGASYNC_BUSY;
+
+ if (conn->traceDebug)
+ traceLog_fprintf(conn, true, "PQsendQueryGuts end :");
+
return 1;
sendFailed:
@@ -1780,6 +1816,9 @@ PQgetResult(PGconn *conn)
{
PGresult *res;
+ if (conn->traceDebug)
+ traceLog_fprintf(conn, true, "PQgetResult start :");
+
if (!conn)
return NULL;
@@ -1820,6 +1859,7 @@ PQgetResult(PGconn *conn)
/* Parse it. */
parseInput(conn);
+
}
/* Return the appropriate thing. */
@@ -1874,6 +1914,9 @@ PQgetResult(PGconn *conn)
}
}
+ if (conn->traceDebug)
+ traceLog_fprintf(conn, true, "PQgetResult end :");
+
return res;
}
@@ -2203,6 +2246,9 @@ PQsendDescribePortal(PGconn *conn, const char *portal)
static int
PQsendDescribe(PGconn *conn, char desc_type, const char *desc_target)
{
+ if (conn->traceDebug)
+ traceLog_fprintf(conn, true, "PQsendDescribe start :");
+
/* Treat null desc_target as empty string */
if (!desc_target)
desc_target = "";
@@ -2218,6 +2264,9 @@ PQsendDescribe(PGconn *conn, char desc_type, const char *desc_target)
return 0;
}
+ if (conn->traceDebug)
+ traceLog_fprintf(conn, false, "Describe type: %c, target: %s \n",desc_type, desc_target);
+
/* construct the Describe message */
if (pqPutMsgStart('D', false, conn) < 0 ||
pqPutc(desc_type, conn) < 0 ||
@@ -2249,6 +2298,10 @@ PQsendDescribe(PGconn *conn, char desc_type, const char *desc_target)
/* OK, it's launched! */
conn->asyncStatus = PGASYNC_BUSY;
+
+ if (conn->traceDebug)
+ traceLog_fprintf(conn, true, "PQsendDescribe end :");
+
return 1;
sendFailed:
diff --git a/src/interfaces/libpq/fe-misc.c b/src/interfaces/libpq/fe-misc.c
index 46ece1a..75c5040 100644
--- a/src/interfaces/libpq/fe-misc.c
+++ b/src/interfaces/libpq/fe-misc.c
@@ -35,6 +35,7 @@
#ifdef WIN32
#include "win32.h"
+#include
#else
#include
#include
@@ -45,6 +46,7 @@
#endif
#ifdef HAVE_SYS_SELECT_H
#include
+#include
#endif
#include "libpq-fe.h"
@@ -60,6 +62,169 @@ static int pqSocketCheck(PGconn *conn, int forRead, int forWrite,
time_t end_time);
static int pqSocketPoll(int sock, int forRead, int forWrite, time_t end_time);
+static void getTraceLogFilename(PGconn *conn,char* filename);
+static void traceLog_fputnbytes(PGconn *conn, const char *head, const char *str, size_t n);
+static void fputnbytes(FILE *f, const char *str, size_t n);
+static void getCurrentTime(char* currenttime,int type);
+#define TRACELOG_TIME_SIZE 28
+
+/*
+ * getCurrentTime: get current time for trace log output
+ *
+ * type=0 currenttime formate %Y-%m-%d_%H%M%S
+ * type=1 currenttime formate %Y/%m/%d %H:%M:%S.%Milliseconds
+ */
+static void
+getCurrentTime(char* currenttime,int type)
+{
+#ifdef WIN32
+ SYSTEMTIME localTime;
+ GetLocalTime(&localTime);
+ if(type==0)
+ snprintf(currenttime,TRACELOG_TIME_SIZE,"%4d-%02d-%02d_%02d%02d%02d",
+ localTime.wYear,localTime.wMonth,localTime.wDay,
+ localTime.wHour,localTime.wMinute,localTime.wSecond);
+ else if(type==1)
+ snprintf(currenttime,TRACELOG_TIME_SIZE,"%4d/%02d/%02d %02d:%02d:%02d.%03d",
+ localTime.wYear,localTime.wMonth,localTime.wDay,
+ localTime.wHour,localTime.wMinute,localTime.wSecond,
+ localTime.wMilliseconds);
+#else
+ struct timeb localTime;
+ struct tm *tm;
+ ftime(&localTime);
+ tm = localtime(&localTime.time);
+ if(type == 0)
+ snprintf(currenttime, TRACELOG_TIME_SIZE,"%4d-%02d-%02d_%02d%02d%02d",
+ 1900+ tm->tm_year,1 + tm->tm_mon, tm->tm_mday,
+ tm->tm_hour, tm->tm_min, tm->tm_sec);
+ else if(type==1)
+ snprintf(currenttime, TRACELOG_TIME_SIZE,"%4d/%02d/%02d %02d:%02d:%02d.%03d",
+ 1900+ tm->tm_year,1 + tm->tm_mon, tm->tm_mday,
+ tm->tm_hour, tm->tm_min, tm->tm_sec, localTime.millitm);
+#endif
+}
+
+/*
+ * getTraceLogFilename: build trace log file name
+ * The name is libpq-%ProcessID-%Y-%m-%d_%H%M%S.log.
+ */
+static void
+getTraceLogFilename(PGconn *conn,char* filename)
+{
+ char currenttime[TRACELOG_TIME_SIZE]; /* %Y-%m-%d_%H%M%S */
+ getCurrentTime(currenttime,0);
+
+#ifdef WIN32
+ snprintf(filename, MAXPGPATH, "%s\\libpq-%d-%s.log", conn->logdir,getpid(),currenttime);
+#else
+ snprintf(filename, MAXPGPATH, "%s/libpq-%d-%s.log", conn->logdir,getpid(),currenttime);
+#endif
+}
+
+/*
+ * initTraceLog: initialize a trace log file
+ */
+void
+initTraceLog(PGconn *conn)
+{
+ char logfilename[MAXPGPATH];
+ getTraceLogFilename(conn,logfilename);
+ conn->traceDebug=fopen(logfilename,"w");
+ fprintf(conn->traceDebug, "Maximum log size is %d B.\n", conn->logsize);
+}
+
+/*
+ * traceLog_fprintf: output trace log to file
+ * If PQtrace() is called, PQtrace() is output followed by libpq trace log.
+ */
+void
+traceLog_fprintf(PGconn *conn, bool addTime, const char *fmt,...)
+{
+ char logfilename[MAXPGPATH];
+ char msgBuf[MAXPGPATH];
+ va_list args;
+ int ret;
+ char currenttime[TRACELOG_TIME_SIZE];
+
+ va_start(args, fmt);
+ vsnprintf(msgBuf, sizeof(msgBuf), fmt, args);
+ msgBuf[sizeof(msgBuf) - 1] = '\0';
+ va_end(args);
+
+ if(conn->Pfdebug)
+ {
+ fprintf(conn->Pfdebug, "%s", msgBuf);
+ }
+ else if(conn->traceDebug)
+ {
+ if((int)ftell(conn->traceDebug) >= conn->logsize)
+ {
+ fclose(conn->traceDebug);
+ getTraceLogFilename(conn,logfilename);
+ conn->traceDebug = fopen(logfilename,"w");
+ if(conn->traceDebug == NULL)
+ return;
+ }
+
+ /* Select trace log message style */
+ if(addTime)
+ {
+ getCurrentTime(currenttime,1);
+ ret = fprintf(conn->traceDebug, "%s %s\n", msgBuf, currenttime);
+ }
+ else
+ {
+ ret = fprintf(conn->traceDebug, "%s",msgBuf);
+ }
+
+ if(ret < 0)
+ {
+ fclose(conn->traceDebug);
+ conn->traceDebug = NULL;
+ return;
+ }
+ fflush(conn->traceDebug);
+ }
+}
+/*
+ * traceLog_fputnbytes: output trace log to file using fputnbytes()
+ */
+static void
+traceLog_fputnbytes(PGconn *conn,const char *head, const char *str, size_t n)
+{
+ char logfilename[MAXPGPATH];
+ int ret;
+
+ if (conn->Pfdebug)
+ {
+ fprintf(conn->Pfdebug, "%s", head);
+ fputnbytes(conn->Pfdebug,str, n);
+ fprintf(conn->Pfdebug, "\n");
+ }
+ else if(conn->traceDebug)
+ {
+ if((int)ftell(conn->traceDebug) >= conn->logsize)
+ {
+ fclose(conn->traceDebug);
+ getTraceLogFilename(conn,logfilename);
+ conn->traceDebug = fopen(logfilename,"w");
+ if(conn->traceDebug == NULL)
+ return;
+ }
+ ret = fprintf(conn->traceDebug, "%s", head);
+ if(ret < 0)
+ {
+ fclose(conn->traceDebug);
+ conn->traceDebug = NULL;
+ return;
+ }
+ fputnbytes(conn->traceDebug,str,n);
+ fprintf(conn->traceDebug,"\n");
+ fflush(conn->traceDebug);
+ }
+}
+
/*
* PQlibVersion: return the libpq version number
*/
@@ -98,8 +263,8 @@ pqGetc(char *result, PGconn *conn)
*result = conn->inBuffer[conn->inCursor++];
- if (conn->Pfdebug)
- fprintf(conn->Pfdebug, "From backend> %c\n", *result);
+ if(conn->Pfdebug||conn->traceDebug)
+ traceLog_fprintf(conn, false, "From backend> %c\n", *result);
return 0;
}
@@ -114,8 +279,8 @@ pqPutc(char c, PGconn *conn)
if (pqPutMsgBytes(&c, 1, conn))
return EOF;
- if (conn->Pfdebug)
- fprintf(conn->Pfdebug, "To backend> %c\n", c);
+ if(conn->Pfdebug||conn->traceDebug)
+ traceLog_fprintf(conn, false, "To backend> %c\n", c);
return 0;
}
@@ -152,9 +317,9 @@ pqGets_internal(PQExpBuffer buf, PGconn *conn, bool resetbuffer)
conn->inCursor = ++inCursor;
- if (conn->Pfdebug)
- fprintf(conn->Pfdebug, "From backend> \"%s\"\n",
- buf->data);
+ if(conn->Pfdebug||conn->traceDebug)
+ traceLog_fprintf(conn, false, "From backend> \"%s\"\n",
+ buf->data);
return 0;
}
@@ -181,8 +346,8 @@ pqPuts(const char *s, PGconn *conn)
if (pqPutMsgBytes(s, strlen(s) + 1, conn))
return EOF;
- if (conn->Pfdebug)
- fprintf(conn->Pfdebug, "To backend> \"%s\"\n", s);
+ if(conn->Pfdebug||conn->traceDebug)
+ traceLog_fprintf(conn, false, "To backend> \"%s\"\n", s);
return 0;
}
@@ -194,6 +359,7 @@ pqPuts(const char *s, PGconn *conn)
int
pqGetnchar(char *s, size_t len, PGconn *conn)
{
+ char buf[100];
if (len > (size_t) (conn->inEnd - conn->inCursor))
return EOF;
@@ -202,11 +368,10 @@ pqGetnchar(char *s, size_t len, PGconn *conn)
conn->inCursor += len;
- if (conn->Pfdebug)
+ if(conn->Pfdebug||conn->traceDebug)
{
- fprintf(conn->Pfdebug, "From backend (%lu)> ", (unsigned long) len);
- fputnbytes(conn->Pfdebug, s, len);
- fprintf(conn->Pfdebug, "\n");
+ sprintf(buf, "From backend (%lu)> ", (unsigned long) len);
+ traceLog_fputnbytes(conn,buf,s, len);
}
return 0;
@@ -223,14 +388,14 @@ pqGetnchar(char *s, size_t len, PGconn *conn)
int
pqSkipnchar(size_t len, PGconn *conn)
{
+ char buf[100];
if (len > (size_t) (conn->inEnd - conn->inCursor))
return EOF;
- if (conn->Pfdebug)
+ if (conn->Pfdebug||conn->traceDebug)
{
- fprintf(conn->Pfdebug, "From backend (%lu)> ", (unsigned long) len);
- fputnbytes(conn->Pfdebug, conn->inBuffer + conn->inCursor, len);
- fprintf(conn->Pfdebug, "\n");
+ sprintf(buf, "From backend (%lu)> ", (unsigned long) len);
+ traceLog_fputnbytes(conn,buf,conn->inBuffer + conn->inCursor, len);
}
conn->inCursor += len;
@@ -245,14 +410,14 @@ pqSkipnchar(size_t len, PGconn *conn)
int
pqPutnchar(const char *s, size_t len, PGconn *conn)
{
+ char buf[100];
if (pqPutMsgBytes(s, len, conn))
return EOF;
- if (conn->Pfdebug)
+ if(conn->Pfdebug||conn->traceDebug)
{
- fprintf(conn->Pfdebug, "To backend> ");
- fputnbytes(conn->Pfdebug, s, len);
- fprintf(conn->Pfdebug, "\n");
+ sprintf(buf,"To backend (%lu)> ", (unsigned long) len);
+ traceLog_fputnbytes(conn,buf,s,len);
}
return 0;
@@ -292,8 +457,8 @@ pqGetInt(int *result, size_t bytes, PGconn *conn)
return EOF;
}
- if (conn->Pfdebug)
- fprintf(conn->Pfdebug, "From backend (#%lu)> %d\n", (unsigned long) bytes, *result);
+ if(conn->Pfdebug||conn->traceDebug)
+ traceLog_fprintf(conn, false, "From backend (#%lu)> %d\n", (unsigned long) bytes, *result);
return 0;
}
@@ -328,8 +493,8 @@ pqPutInt(int value, size_t bytes, PGconn *conn)
return EOF;
}
- if (conn->Pfdebug)
- fprintf(conn->Pfdebug, "To backend (%lu#)> %d\n", (unsigned long) bytes, value);
+ if(conn->Pfdebug||conn->traceDebug)
+ traceLog_fprintf(conn, false, "To backend (%lu#)> %d\n", (unsigned long) bytes, value);
return 0;
}
@@ -548,9 +713,9 @@ pqPutMsgStart(char msg_type, bool force_len, PGconn *conn)
conn->outMsgEnd = endPos;
/* length word, if needed, will be filled in by pqPutMsgEnd */
- if (conn->Pfdebug)
- fprintf(conn->Pfdebug, "To backend> Msg %c\n",
- msg_type ? msg_type : ' ');
+ if(conn->Pfdebug||conn->traceDebug)
+ traceLog_fprintf(conn, false, "To backend> Msg %c\n",
+ msg_type ? msg_type : ' ');
return 0;
}
@@ -586,9 +751,9 @@ pqPutMsgBytes(const void *buf, size_t len, PGconn *conn)
int
pqPutMsgEnd(PGconn *conn)
{
- if (conn->Pfdebug)
- fprintf(conn->Pfdebug, "To backend> Msg complete, length %u\n",
- conn->outMsgEnd - conn->outCount);
+ if(conn->Pfdebug||conn->traceDebug)
+ traceLog_fprintf(conn, false, "To backend> Msg complete, length %u\n",
+ conn->outMsgEnd - conn->outCount);
/* Fill in length word if needed */
if (conn->outMsgStart >= 0)
@@ -677,9 +842,17 @@ pqReadData(PGconn *conn)
}
/* OK, try to read some data */
+
retry3:
+ if (conn->traceDebug)
+ traceLog_fprintf(conn, true, "Start receiving message from backend:");
+
nread = pqsecure_read(conn, conn->inBuffer + conn->inEnd,
conn->inBufSize - conn->inEnd);
+
+ if (conn->traceDebug)
+ traceLog_fprintf(conn, true, "End receiving message from backend:");
+
if (nread < 0)
{
if (SOCK_ERRNO == EINTR)
@@ -767,9 +940,16 @@ retry3:
* Still not sure that it's EOF, because some data could have just
* arrived.
*/
+
+ if (conn->traceDebug)
+ traceLog_fprintf(conn, true, "Start receiving message from backend:");
retry4:
nread = pqsecure_read(conn, conn->inBuffer + conn->inEnd,
conn->inBufSize - conn->inEnd);
+
+ if (conn->traceDebug)
+ traceLog_fprintf(conn, true, "End receiving message from backend:");
+
if (nread < 0)
{
if (SOCK_ERRNO == EINTR)
@@ -846,6 +1026,9 @@ pqSendSome(PGconn *conn, int len)
{
int sent;
+ if (conn->traceDebug)
+ traceLog_fprintf(conn, true, "Start sending message to backend:");
+
#ifndef WIN32
sent = pqsecure_write(conn, ptr, len);
#else
@@ -858,6 +1041,9 @@ pqSendSome(PGconn *conn, int len)
sent = pqsecure_write(conn, ptr, Min(len, 65536));
#endif
+ if (conn->traceDebug)
+ traceLog_fprintf(conn, true, "End sending message to backend:");
+
if (sent < 0)
{
/* Anything except EAGAIN/EWOULDBLOCK/EINTR is trouble */
@@ -963,6 +1149,9 @@ pqFlush(PGconn *conn)
if (conn->Pfdebug)
fflush(conn->Pfdebug);
+ if (conn->traceDebug)
+ fflush(conn->traceDebug);
+
if (conn->outCount > 0)
return pqSendSome(conn, conn->outCount);
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 66fd317..71d4329 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -500,6 +500,11 @@ struct pg_conn
/* Buffer for receiving various parts of messages */
PQExpBufferData workBuffer; /* expansible string */
+
+ char *logsize_str; /* Trace log maximum size (string) */
+ int logsize; /* Trace log maximum size */
+ char *logdir; /* Trace log directory to save log */
+ FILE *traceDebug; /* Trace log file to write trace info */
};
/* PGcancel stores all data necessary to cancel a connection. A copy of this
@@ -666,6 +671,10 @@ extern void pq_reset_sigpipe(sigset_t *osigset, bool sigpipe_pending,
bool got_epipe);
#endif
+/* libpq trace log */
+extern void initTraceLog(PGconn *conn);
+extern void traceLog_fprintf(PGconn *conn, bool addTime, const char *fmt,...) pg_attribute_printf(3, 4);
+
/* === SSL === */
/*