diff --git a/doc/src/sgml/libpq.sgml b/doc/src/sgml/libpq.sgml
index c1d1b6b..ee766fd 100644
--- a/doc/src/sgml/libpq.sgml
+++ b/doc/src/sgml/libpq.sgml
@@ -1589,6 +1589,42 @@ postgresql://%2Fvar%2Flib%2Fpostgresql/dbname
       </para>
       </listitem>
     </varlistentry>
+
+     <varlistentry id="libpq-connect-log-dir" xreflabel="logdir">
+      <term><literal>logdir</literal></term>
+      <listitem>
+       <para>
+        Path of directory where log file written. When both <literal>logdir</literal>
+        and <literal>logsize</literal> is set, logging is enabled.
+      </para>
+     </listitem>
+    </varlistentry>
+
+     <varlistentry id="libpq-connect-log-size" xreflabel="logsize">
+      <term><literal>logsize</literal></term>
+      <listitem>
+       <para>
+        Maximum log size. The unit is megabyte. When the log file size exceeds 
+        to <literal>logsize</literal>, the log is output to another file. 
+        When both <literal>logdir</literal> and <literal>logsize</literal> is set, 
+        logging is enabled.
+      </para>
+     </listitem>
+    </varlistentry>
+
+     <varlistentry id="libpq-connect-log-min-level" xreflabel="logminlevel">
+      <term><literal>logminlevel</literal></term>
+      <listitem>
+       <para>
+        Level of the log. <literal>level1</literal> and <literal>level2</literal> 
+        can be set, <literal>level1</literal> is the default. 
+        When this parameter is <literal>level1</literal>,it outputs the time 
+        in the function and connection time. <literal>level2</literal> outputs 
+        information on the protocol being exchanged in addition to 
+        <literal>level1</literal> information.
+      </para>
+     </listitem>
+    </varlistentry>
     </variablelist>
    </para>
   </sect2>
@@ -7472,6 +7508,36 @@ myEventProc(PGEventId evtId, void *evtInfo, void *passThrough)
       linkend="libpq-connect-target-session-attrs"/> connection parameter.
      </para>
     </listitem>
+
+    <listitem>
+     <para>
+      <indexterm>
+       <primary><envar>PGLOGDIR</envar></primary>
+      </indexterm>
+      <envar>PGLOGDIR</envar> behaves the same as the <xref
+      linkend="libpq-connect-log-dir"/> connection parameter.
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      <indexterm>
+       <primary><envar>PGLOGSIZE</envar></primary>
+      </indexterm>
+      <envar>PGLOGSIZE</envar> behaves the same as the <xref
+      linkend="libpq-connect-log-size"/> connection parameter.
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      <indexterm>
+       <primary><envar>PGLOGMINLEVEL</envar></primary>
+      </indexterm>
+      <envar>PGLOGMINLEVEL</envar> behaves the same as the <xref
+      linkend="libpq-connect-log-min-level"/> connection parameter.
+     </para>
+    </listitem>
    </itemizedlist>
   </para>
 
@@ -8300,6 +8366,38 @@ int PQisthreadsafe();
   </para>
  </sect1>
 
+ <sect1 id="libpq-logging">
+  <title>Logging</title>
+
+  <indexterm zone="libpq-logging">
+   <primary>trace log</primary>
+  </indexterm>
+  <indexterm zone="libpq-logging">
+   <primary>logging</primary>
+  </indexterm>
+
+  <para>
+   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.
+  </para>
+
+  <para>
+   You can activate this log by setting both <parameter>logdir</parameter> and 
+   <parameter>logsize</parameter> of the connection string, or by setting both 
+   the environment variables <envar>PGLOGDIR</envar> and <envar>PGLOGSIZE</envar>.
+   The log trace file is written in a directory setting by <envar>PGLOGDIR</envar> 
+   or <parameter>logdir</parameter>.
+   Information to be output to the log file can be controlled by setting 
+   <parameter>logminlevel</parameter> or <envar>PGLOGMINLEVEL</envar>.
+   The file name is determined as <filename>libpq-%ProcessID-%Y-%m-%d_%H%M%S.log</filename>.
+   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 and log level you set is output to the beginning of the file, 
+   so you can check it.
+  </para>
+ </sect1>
 
  <sect1 id="libpq-build">
   <title>Building <application>libpq</application> Programs</title>
diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index f29202d..c362339 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -129,6 +129,7 @@ static int ldapServiceLookup(const char *purl, PQconninfoOption *options,
 #else
 #define DefaultSSLMode	"disable"
 #endif
+#define DefaultLogMinLevel	"LEVEL1"
 
 /* ----------
  * Definition of the conninfo parameters and their fallback resources.
@@ -325,6 +326,19 @@ 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)},
+
+	{"logminlevel", "PGLOGMINLEVEL", DefaultLogMinLevel, NULL,
+		"LogMinlevel", "", 7,
+	offsetof(struct pg_conn, logminlevel_str)},
+
 	/* Terminating entry --- MUST BE LAST */
 	{NULL, NULL, NULL, NULL,
 	NULL, NULL, 0}
@@ -1128,6 +1142,26 @@ 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;
+
+		if(strcmp(conn->logminlevel_str, "level1") == 0)
+			conn->logminlevel = LEVEL1;
+
+		if(strcmp(conn->logminlevel_str, "level2") == 0)
+			conn->logminlevel = LEVEL2;
+
+		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 +3750,16 @@ 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->logminlevel_str)
+		free(conn->logminlevel_str);
+	if (conn->traceDebug)
+		fclose(conn->traceDebug);
+
 	free(conn);
 
 #ifdef WIN32
@@ -3751,6 +3795,7 @@ sendTerminateConn(PGconn *conn)
 	 */
 	if (conn->sock != PGINVALID_SOCKET && conn->status == CONNECTION_OK)
 	{
+		traceLog_fprintf(conn, LEVEL1, "Send connection terminate message to backend");
 		/*
 		 * Try to send "close connection" message to backend. Ignore any
 		 * error.
@@ -4153,6 +4198,8 @@ int
 pqPacketSend(PGconn *conn, char pack_type,
 			 const void *buf, size_t buf_len)
 {
+	traceLog_fprintf(conn, LEVEL1, "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 ac969e7..6ccd1de 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,8 @@ 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);
+	traceLog_fprintf(conn, LEVEL2, "pqSaveParameterStatus: '%s' = '%s'\n",
+						 name, value);
 
 	/*
 	 * Forget any old information about the parameter
@@ -1208,6 +1207,8 @@ fail:
 int
 PQsendQuery(PGconn *conn, const char *query)
 {
+	traceLog_fprintf(conn, LEVEL1, "PQsendQuery start");
+
 	if (!PQsendQueryStart(conn))
 		return 0;
 
@@ -1219,6 +1220,8 @@ PQsendQuery(PGconn *conn, const char *query)
 		return 0;
 	}
 
+	traceLog_fprintf(conn, LEVEL1, "Query: %s",query);
+
 	/* construct the outgoing Query message */
 	if (pqPutMsgStart('Q', false, conn) < 0 ||
 		pqPuts(query, conn) < 0 ||
@@ -1249,6 +1252,9 @@ PQsendQuery(PGconn *conn, const char *query)
 
 	/* OK, it's launched! */
 	conn->asyncStatus = PGASYNC_BUSY;
+
+	traceLog_fprintf(conn, LEVEL1, "PQsendQuery end");
+
 	return 1;
 }
 
@@ -1266,6 +1272,8 @@ PQsendQueryParams(PGconn *conn,
 				  const int *paramFormats,
 				  int resultFormat)
 {
+	traceLog_fprintf(conn, LEVEL1, "PQsendQueryParams start");
+
 	if (!PQsendQueryStart(conn))
 		return 0;
 
@@ -1283,6 +1291,8 @@ PQsendQueryParams(PGconn *conn,
 		return 0;
 	}
 
+	traceLog_fprintf(conn, LEVEL1, "PQsendQueryParams end");
+
 	return PQsendQueryGuts(conn,
 						   command,
 						   "",	/* use unnamed statement */
@@ -1306,6 +1316,8 @@ PQsendPrepare(PGconn *conn,
 			  const char *stmtName, const char *query,
 			  int nParams, const Oid *paramTypes)
 {
+	traceLog_fprintf(conn, LEVEL1, "PQsendPrepare start");
+
 	if (!PQsendQueryStart(conn))
 		return 0;
 
@@ -1337,6 +1349,8 @@ PQsendPrepare(PGconn *conn,
 		return 0;
 	}
 
+	traceLog_fprintf(conn, LEVEL1, "Statement name: %s, Query: %s ",stmtName, query);
+
 	/* construct the Parse message */
 	if (pqPutMsgStart('P', false, conn) < 0 ||
 		pqPuts(stmtName, conn) < 0 ||
@@ -1386,6 +1400,9 @@ PQsendPrepare(PGconn *conn,
 
 	/* OK, it's launched! */
 	conn->asyncStatus = PGASYNC_BUSY;
+
+	traceLog_fprintf(conn, LEVEL1, "PQsendPrepare end");
+
 	return 1;
 
 sendFailed:
@@ -1492,6 +1509,8 @@ PQsendQueryGuts(PGconn *conn,
 {
 	int			i;
 
+	traceLog_fprintf(conn, LEVEL1, "PQsendQueryGuts start");
+
 	/* This isn't gonna work on a 2.0 server */
 	if (PG_PROTOCOL_MAJOR(conn->pversion) < 3)
 	{
@@ -1507,6 +1526,8 @@ PQsendQueryGuts(PGconn *conn,
 
 	if (command)
 	{
+		traceLog_fprintf(conn, LEVEL1, "Statement name: %s, Command: %s \n",stmtName, command);
+
 		/* construct the Parse message */
 		if (pqPutMsgStart('P', false, conn) < 0 ||
 			pqPuts(stmtName, conn) < 0 ||
@@ -1638,6 +1659,9 @@ PQsendQueryGuts(PGconn *conn,
 
 	/* OK, it's launched! */
 	conn->asyncStatus = PGASYNC_BUSY;
+
+	traceLog_fprintf(conn, LEVEL1, "PQsendQueryGuts end");
+
 	return 1;
 
 sendFailed:
@@ -1780,6 +1804,8 @@ PQgetResult(PGconn *conn)
 {
 	PGresult   *res;
 
+	traceLog_fprintf(conn, LEVEL1, "PQgetResult start");
+
 	if (!conn)
 		return NULL;
 
@@ -1820,6 +1846,7 @@ PQgetResult(PGconn *conn)
 
 		/* Parse it. */
 		parseInput(conn);
+
 	}
 
 	/* Return the appropriate thing. */
@@ -1874,6 +1901,8 @@ PQgetResult(PGconn *conn)
 		}
 	}
 
+	traceLog_fprintf(conn, LEVEL1, "PQgetResult end");
+
 	return res;
 }
 
@@ -2203,6 +2232,8 @@ PQsendDescribePortal(PGconn *conn, const char *portal)
 static int
 PQsendDescribe(PGconn *conn, char desc_type, const char *desc_target)
 {
+	traceLog_fprintf(conn, LEVEL1, "PQsendDescribe start");
+
 	/* Treat null desc_target as empty string */
 	if (!desc_target)
 		desc_target = "";
@@ -2218,6 +2249,8 @@ PQsendDescribe(PGconn *conn, char desc_type, const char *desc_target)
 		return 0;
 	}
 
+	traceLog_fprintf(conn, LEVEL1, "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 +2282,9 @@ PQsendDescribe(PGconn *conn, char desc_type, const char *desc_target)
 
 	/* OK, it's launched! */
 	conn->asyncStatus = PGASYNC_BUSY;
+
+	traceLog_fprintf(conn, LEVEL1, "PQsendDescribe end");
+
 	return 1;
 
 sendFailed:
diff --git a/src/interfaces/libpq/fe-misc.c b/src/interfaces/libpq/fe-misc.c
index e5ef8d4..6a4d4db 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 <windows.h>
 #else
 #include <unistd.h>
 #include <sys/time.h>
@@ -45,6 +46,7 @@
 #endif
 #ifdef HAVE_SYS_SELECT_H
 #include <sys/select.h>
+#include <sys/timeb.h>
 #endif
 
 #include "libpq-fe.h"
@@ -60,6 +62,201 @@ 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, int loglevel ,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	33
+
+/*
+ * 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;
+	TIME_ZONE_INFORMATION TimezoneInfo;
+	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)
+	{
+		GetTimezoneInformation(&TimezoneInfo);
+		snprintf(currenttime,TRACELOG_TIME_SIZE,"%4d-%02d-%02d %02d:%02d:%02d.%03d %s ",
+				localTime.wYear,localTime.wMonth,localTime.wDay,
+				localTime.wHour,localTime.wMinute,localTime.wSecond,
+				localTime.wMilliseconds, TimezoneInfo.Bias);
+	}
+#else
+	struct timeb localTime;
+	struct tm *tm;
+	char timezone[100];
+	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)
+	{
+		strftime(timezone, sizeof(timezone), "%Z", tm);
+		snprintf(currenttime, TRACELOG_TIME_SIZE,"%4d-%02d-%02d %02d:%02d:%02d.%03d %s ",
+				1900+ tm->tm_year,1 + tm->tm_mon, tm->tm_mday,
+				tm->tm_hour, tm->tm_min, tm->tm_sec, localTime.millitm, timezone);
+	}
+#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, "The maximum size of this log is %s Bytes, the parameter 'logminlevel' is set to %s\n",
+						 conn->logsize_str, conn->logminlevel_str);
+}
+
+/*
+ * traceLog_fprintf: output trace log to file
+ * If PQtrace() is called, PQtrace() is output followed by libpq trace log.
+ */
+void
+traceLog_fprintf(PGconn *conn, PGTraceLogLevel loglevel, const char *fmt,...)
+{
+	char		logfilename[MAXPGPATH];
+	char		msgBuf[MAXPGPATH];
+	va_list		args;
+	int			ret = 0;
+	char		currenttime[TRACELOG_TIME_SIZE];
+	bool		output_tracelog = true;
+
+	va_start(args, fmt);
+	vsnprintf(msgBuf, sizeof(msgBuf), fmt, args);
+	msgBuf[sizeof(msgBuf) - 1] = '\0';
+	va_end(args);
+
+	/* Determin whether to output the log message to the file */
+	if(conn->logminlevel < loglevel)
+		output_tracelog = false;
+
+	if(conn->Pfdebug)
+	{
+		/* All protocol messages are set the log level to "LEVEL2". */
+		if(loglevel == LEVEL2)
+			fprintf(conn->Pfdebug, "%s", msgBuf);
+	}
+
+	if(conn->traceDebug && output_tracelog)
+	{
+		if((int)ftell(conn->traceDebug) >= conn->logsize)
+		{
+			fclose(conn->traceDebug);
+			getTraceLogFilename(conn,logfilename);
+			conn->traceDebug = fopen(logfilename,"w");
+			if(conn->traceDebug == NULL)
+				return;
+			fprintf(conn->traceDebug, "The maximum size of this log is %s Bytes, the parameter 'logminlevel' is set to %s\n",
+					  conn->logsize_str, conn->logminlevel_str);
+		}
+
+		/*
+		 * Select trace log message style. The output style of LEVEL1 or LEVEL2 is
+		 * always selected.
+		 */
+		if(loglevel == LEVEL1)
+		{
+			getCurrentTime(currenttime,1);
+			ret = fprintf(conn->traceDebug, "%s  %s\n", currenttime, msgBuf);
+		}
+
+		if(loglevel == LEVEL2)
+		{
+			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,int loglevel, const char *head, const char *str, size_t n)
+{
+	char		logfilename[MAXPGPATH];
+	int			ret;
+	bool		output_tracelog = true;
+
+	if(conn->logminlevel < loglevel)
+		output_tracelog = false;
+
+	if (conn->Pfdebug)
+	{
+		fprintf(conn->Pfdebug, "%s", head);
+		fputnbytes(conn->Pfdebug,str, n);
+		fprintf(conn->Pfdebug, "\n");
+	}
+	else if(conn->traceDebug && output_tracelog)
+	{
+		if(conn->logminlevel < loglevel)
+		{
+			return;
+		}
+
+		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 +295,7 @@ pqGetc(char *result, PGconn *conn)
 
 	*result = conn->inBuffer[conn->inCursor++];
 
-	if (conn->Pfdebug)
-		fprintf(conn->Pfdebug, "From backend> %c\n", *result);
+	traceLog_fprintf(conn, LEVEL2, "From backend> %c\n", *result);
 
 	return 0;
 }
@@ -114,8 +310,7 @@ pqPutc(char c, PGconn *conn)
 	if (pqPutMsgBytes(&c, 1, conn))
 		return EOF;
 
-	if (conn->Pfdebug)
-		fprintf(conn->Pfdebug, "To backend> %c\n", c);
+	traceLog_fprintf(conn, LEVEL2, "To backend> %c\n", c);
 
 	return 0;
 }
@@ -152,9 +347,8 @@ pqGets_internal(PQExpBuffer buf, PGconn *conn, bool resetbuffer)
 
 	conn->inCursor = ++inCursor;
 
-	if (conn->Pfdebug)
-		fprintf(conn->Pfdebug, "From backend> \"%s\"\n",
-				buf->data);
+	traceLog_fprintf(conn, LEVEL2, "From backend> \"%s\"\n",
+						buf->data);
 
 	return 0;
 }
@@ -181,8 +375,7 @@ 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);
+	traceLog_fprintf(conn, LEVEL2, "To backend> \"%s\"\n", s);
 
 	return 0;
 }
@@ -194,6 +387,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,12 +396,8 @@ pqGetnchar(char *s, size_t len, PGconn *conn)
 
 	conn->inCursor += len;
 
-	if (conn->Pfdebug)
-	{
-		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, LEVEL2, buf, s, len);
 
 	return 0;
 }
@@ -223,15 +413,12 @@ 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)
-	{
-		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, LEVEL2, buf, conn->inBuffer + conn->inCursor, len);
 
 	conn->inCursor += len;
 
@@ -245,15 +432,12 @@ 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)
-	{
-		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, LEVEL2, buf, s, len);
 
 	return 0;
 }
@@ -292,8 +476,7 @@ 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);
+	traceLog_fprintf(conn, LEVEL2, "From backend (#%lu)> %d\n", (unsigned long) bytes, *result);
 
 	return 0;
 }
@@ -328,8 +511,7 @@ 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);
+	traceLog_fprintf(conn, LEVEL2, "To backend (%lu#)> %d\n", (unsigned long) bytes, value);
 
 	return 0;
 }
@@ -548,9 +730,8 @@ 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 : ' ');
+	traceLog_fprintf(conn, LEVEL2, "To backend> Msg %c\n",
+						msg_type ? msg_type : ' ');
 
 	return 0;
 }
@@ -586,9 +767,8 @@ 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);
+	traceLog_fprintf(conn, LEVEL2, "To backend> Msg complete, length %u\n",
+						conn->outMsgEnd - conn->outCount);
 
 	/* Fill in length word if needed */
 	if (conn->outMsgStart >= 0)
@@ -677,9 +857,15 @@ pqReadData(PGconn *conn)
 	}
 
 	/* OK, try to read some data */
+
 retry3:
+	traceLog_fprintf(conn, LEVEL1, "Start receiving message from backend");
+
 	nread = pqsecure_read(conn, conn->inBuffer + conn->inEnd,
 						  conn->inBufSize - conn->inEnd);
+
+	traceLog_fprintf(conn, LEVEL1, "End receiving message from backend");
+
 	if (nread < 0)
 	{
 		if (SOCK_ERRNO == EINTR)
@@ -767,9 +953,14 @@ retry3:
 	 * Still not sure that it's EOF, because some data could have just
 	 * arrived.
 	 */
+
+	traceLog_fprintf(conn, LEVEL1, "Start receiving message from backend");
 retry4:
 	nread = pqsecure_read(conn, conn->inBuffer + conn->inEnd,
 						  conn->inBufSize - conn->inEnd);
+
+	traceLog_fprintf(conn, LEVEL1, "End receiving message from backend");
+
 	if (nread < 0)
 	{
 		if (SOCK_ERRNO == EINTR)
@@ -846,6 +1037,8 @@ pqSendSome(PGconn *conn, int len)
 	{
 		int			sent;
 
+	traceLog_fprintf(conn, LEVEL1, "Start sending message to backend");
+
 #ifndef WIN32
 		sent = pqsecure_write(conn, ptr, len);
 #else
@@ -858,6 +1051,8 @@ pqSendSome(PGconn *conn, int len)
 		sent = pqsecure_write(conn, ptr, Min(len, 65536));
 #endif
 
+	traceLog_fprintf(conn, LEVEL1, "End sending message to backend");
+
 		if (sent < 0)
 		{
 			/* Anything except EAGAIN/EWOULDBLOCK/EINTR is trouble */
@@ -963,6 +1158,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-fe.h b/src/interfaces/libpq/libpq-fe.h
index 97bc98b..b0e6124 100644
--- a/src/interfaces/libpq/libpq-fe.h
+++ b/src/interfaces/libpq/libpq-fe.h
@@ -134,6 +134,16 @@ typedef enum
 	PQPING_NO_ATTEMPT			/* connection not attempted (bad params) */
 } PGPing;
 
+/*
+ * libpq trce log level
+ */
+
+typedef enum
+{
+	LEVEL1,				 /* Time and process (by default) */
+	LEVEL2				 /* Server and Client exchange messages */
+} PGTraceLogLevel;
+
 /* PGconn encapsulates a connection to the backend.
  * The contents of this struct are not supposed to be known to applications.
  */
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 4a93d8e..1bf62d7 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -500,6 +500,13 @@ struct pg_conn
 
 	/* Buffer for receiving various parts of messages */
 	PQExpBufferData workBuffer; /* expansible string */
+
+	char	   *logdir;			/* Trace log directory to save log */
+	char	   *logsize_str;		/* Trace log maximum size (string) */
+	char	   *logminlevel_str;		/* Trace log level (string)*/
+	int			logsize;		/* Trace log maximum size */
+	PGTraceLogLevel logminlevel;              /* Trace log level( "level1"(default) or "level2") */
+	FILE	   *traceDebug;			/* Trace log file to write trace info */
 };
 
 /* PGcancel stores all data necessary to cancel a connection. A copy of this
@@ -666,6 +673,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, PGTraceLogLevel loglevel, const char *fmt,...) pg_attribute_printf(3, 4);
+
 /* === SSL === */
 
 /*
