On Wed, 16 Jul 2025 at 21:30, Fujii Masao <masao.fu...@oss.nttdata.com> wrote: > > > > On 2025/07/16 19:45, vignesh C wrote: > > If we don't trim the trailing newline, an extra blank line will appear > > after the message is printed, like this: > > 2025-07-16 12:44:20.076 IST [534376] LOG: logical replication table > > synchronization worker for subscription "sub1", table "t2" has started > > 2025-07-16 12:44:20.294 IST [534374] LOG: received message via > > replication: WARNING: could not remove directory > > "pg_replslot/pg_16396_sync_16384_7527574647116269356.tmp" > > > > 2025-07-16 12:44:20.294 IST [534374] LOG: logical replication table > > synchronization worker for subscription "sub1", table "t1" has > > finished > > > > This occurs because a newline is appended to the message in > > pqBuildErrorMessage3, which is called when the message is received in > > pqGetErrorNotice3: > > ... > > } > > appendPQExpBufferChar(msg, '\n'); > > if (verbosity != PQERRORS_TERSE) > > ... > > You're right, the message text passed to the notice processor includes > a trailing newline. I confirmed this is documented in the PQsetNoticeProcessor > docs [1], so I agree it's reasonable to trim the newline for cleaner log > output. > > > Regarding the current implementation: > + /* Trim trailing newline for cleaner logs */ > + size_t len = strlen(message); > + > + if (len > 0 && message[len - 1] == '\n') > + ereport(LOG, > + errmsg("received message via replication: > %.*s", > + (int) (len - 1), message)); > + else > + ereport(LOG, > + errmsg("received message via replication: > %s", message)); > > To avoid repeating ereport(), how about refactoring it like this? > I think it's simpler and easier to read: > > --------------------------------------- > /* > * Custom notice processor for replication connection. > */ > static void > notice_processor(void *arg, const char *message) > { > int len; > > /* > * Trim the trailing newline from the message text passed to the > notice > * processor, as it always includes one, to produce cleaner log > output. > */ > len = strlen(message); > if (len > 0 && message[len - 1] == '\n') > len--; > > ereport(LOG, > errmsg("received message via replication: %.*s", > len, message)); > } > ---------------------------------------
Looks good, modified > Also, I suggest adding the prototype for notice_processor() in > libpqwalreceiver.c: > > --------------------------------------- > /* Prototypes for private functions */ > static void notice_processor(void *arg, const char *message); > static char *stringlist_to_identifierstr(PGconn *conn, List *strings); > --------------------------------------- > > > Currently, notice_processor() is placed just before libpqrcv_connect(), > but I think it would be better to move it before > stringlist_to_identifierstr(), > since the libpqwalreceiver.c seems to follow a structure where private > functions come after the libpqrcv_* functions. Modified > > + PQsetNoticeProcessor(conn->streamConn, notice_processor, NULL); > > It might be helpful to add a comment explaining the purpose, such as: > > Set a custom notice processor so that notice, warning, and similar > messages > received via the replication connection are logged in our preferred > style, > instead of just being printed to stderr. Modified The attached v4 version patch has the changes for the same. Regards, Vignesh
From 2460fbd0a5c6a1be425cdaf92daa2800407e4fcb Mon Sep 17 00:00:00 2001 From: Vignesh C <vignes...@gmail.com> Date: Wed, 16 Jul 2025 15:26:12 +0530 Subject: [PATCH v4 1/3] Add custom PQsetNoticeProcessor handlers for replication connection This patch introduces a custom notice processor for libpq-based connections in replication connection. The notice processor captures messages and routes them through ereport(), making them visible in local logs with a prefix making it easy for diagnosis. --- .../libpqwalreceiver/libpqwalreceiver.c | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c b/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c index f7b5d093681..689333d7c52 100644 --- a/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c +++ b/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c @@ -114,6 +114,7 @@ static WalReceiverFunctionsType PQWalReceiverFunctions = { }; /* Prototypes for private functions */ +static void notice_processor(void *arg, const char *message); static char *stringlist_to_identifierstr(PGconn *conn, List *strings); /* @@ -232,6 +233,13 @@ libpqrcv_connect(const char *conninfo, bool replication, bool logical, errhint("Target server's authentication method must be changed, or set password_required=false in the subscription parameters."))); } + /* + * Set a custom notice processor so that NOTICEs, WARNINGs, and similar + * messages from the replication connection are reported via ereport(), + * instead of being printed to stderr. + */ + PQsetNoticeProcessor(conn->streamConn, notice_processor, NULL); + /* * Set always-secure search path for the cases where the connection is * used to run SQL queries, so malicious users can't get control. @@ -1195,6 +1203,26 @@ libpqrcv_exec(WalReceiverConn *conn, const char *query, return walres; } +/* + * Custom notice processor for replication connection. + */ +static void +notice_processor(void *arg, const char *message) +{ + int len; + + /* + * Trim the trailing newline from the message text passed to the notice + * processor, as it always includes one, to produce cleaner log output. + */ + len = strlen(message); + if (len > 0 && message[len - 1] == '\n') + len--; + + ereport(LOG, + errmsg("received message via replication: %.*s", len, message)); +} + /* * Given a List of strings, return it as single comma separated * string, quoting identifiers as needed. -- 2.43.0
From 9a0c0ce671d3860f1611c4ca1ec7cf55ab43e6e4 Mon Sep 17 00:00:00 2001 From: Vignesh C <vignes...@gmail.com> Date: Wed, 16 Jul 2025 15:31:54 +0530 Subject: [PATCH v4 2/3] Add custom PQsetNoticeProcessor handlers for dblink connection This patch introduces a custom notice processor for libpq-based connections in dblink connection. The notice processor captures messages and routes them through ereport(), making them visible in local logs with a prefix making it easy for diagnosis. --- contrib/dblink/dblink.c | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/contrib/dblink/dblink.c b/contrib/dblink/dblink.c index 8a0b112a7ff..30509f9ff32 100644 --- a/contrib/dblink/dblink.c +++ b/contrib/dblink/dblink.c @@ -137,6 +137,7 @@ static void appendSCRAMKeysInfo(StringInfo buf); static bool is_valid_dblink_fdw_option(const PQconninfoOption *options, const char *option, Oid context); static bool dblink_connstr_has_required_scram_options(const char *connstr); +static void notice_processor(void *arg, const char *message); /* Global */ static remoteConn *pconn = NULL; @@ -240,6 +241,14 @@ dblink_get_conn(char *conname_or_str, errmsg("could not establish connection"), errdetail_internal("%s", msg))); } + + /* + * Set a custom notice processor so that NOTICEs, WARNINGs, and + * similar messages from the remote server connection are reported via + * ereport(), instead of being printed to stderr. + */ + PQsetNoticeProcessor(conn, notice_processor, NULL); + dblink_security_check(conn, NULL, connstr); if (PQclientEncoding(conn) != GetDatabaseEncoding()) PQsetClientEncoding(conn, GetDatabaseEncodingName()); @@ -338,6 +347,8 @@ dblink_connect(PG_FUNCTION_ARGS) errdetail_internal("%s", msg))); } + PQsetNoticeProcessor(conn, notice_processor, NULL); + /* check password actually used if not superuser */ dblink_security_check(conn, connname, connstr); @@ -2670,6 +2681,26 @@ dblink_connstr_has_required_scram_options(const char *connstr) return (has_scram_keys && has_require_auth); } +/* + * Custom notice processor for remote server connection. + */ +static void +notice_processor(void *arg, const char *message) +{ + int len; + + /* + * Trim the trailing newline from the message text passed to the notice + * processor, as it always includes one, to produce cleaner log output. + */ + len = strlen(message); + if (len > 0 && message[len - 1] == '\n') + len--; + + ereport(LOG, + errmsg("received message from remote server: %.*s", len, message)); +} + /* * We need to make sure that the connection made used credentials * which were provided by the user, so check what credentials were -- 2.43.0
From 880d19658fdc3f9d4e31b1e6f1be670e1cb3dd46 Mon Sep 17 00:00:00 2001 From: Vignesh C <vignes...@gmail.com> Date: Wed, 16 Jul 2025 15:32:41 +0530 Subject: [PATCH v4 3/3] Add custom PQsetNoticeProcessor handlers for fdw connection This patch introduces a custom notice processor for libpq-based connections in fdw connection. The notice processor captures messages and routes them through ereport(), making them visible in local logs with a prefix making it easy for diagnosis. --- contrib/postgres_fdw/connection.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/contrib/postgres_fdw/connection.c b/contrib/postgres_fdw/connection.c index 304f3c20f83..53264ecbf93 100644 --- a/contrib/postgres_fdw/connection.c +++ b/contrib/postgres_fdw/connection.c @@ -472,6 +472,26 @@ pgfdw_security_check(const char **keywords, const char **values, UserMapping *us errhint("Target server's authentication method must be changed or password_required=false set in the user mapping attributes."))); } +/* + * Custom notice processor for remote server connection. + */ +static void +notice_processor(void *arg, const char *message) +{ + int len; + + /* + * Trim the trailing newline from the message text passed to the notice + * processor, as it always includes one, to produce cleaner log output. + */ + len = strlen(message); + if (len > 0 && message[len - 1] == '\n') + len--; + + ereport(LOG, + errmsg("received message from remote server: %.*s", len, message)); +} + /* * Connect to remote server using specified server and user mapping properties. */ @@ -625,6 +645,13 @@ connect_pg_server(ForeignServer *server, UserMapping *user) server->servername), errdetail_internal("%s", pchomp(PQerrorMessage(conn))))); + /* + * Set a custom notice processor so that NOTICEs, WARNINGs, and + * similar messages from the remote server connection are reported via + * ereport(), instead of being printed to stderr. + */ + PQsetNoticeProcessor(conn, notice_processor, NULL); + /* Perform post-connection security checks. */ pgfdw_security_check(keywords, values, user, conn); -- 2.43.0