From 9c5907b11e5f20f9424757f474f8b9cb8c3b4266 Mon Sep 17 00:00:00 2001
From: Seongjun Shin <shinsj4653@gmail.com>
Date: Fri, 29 May 2026 14:45:23 +0900
Subject: [PATCH v1 1/2] Add wait events for server logging destination writes

When a backend writes to the syslogger pipe in write_pipe_chunks() or
to stderr in write_console(), the underlying write(2) can block once
the pipe buffer fills up or the output device is slow.  These blocking
syscalls were not instrumented, so pg_stat_activity reported
wait_event IS NULL during that time.  Many monitoring tools interpret
NULL as on-CPU work, which made heavy-logging stalls hard to
attribute.

Add two new WaitEventIO events and report them around the relevant
write(2) calls:

  IO / SysloggerWrite - write(2) to the syslogger pipe inside
                        write_pipe_chunks().
  IO / StderrWrite    - write(2) to stderr inside write_console().

The instrumentation is limited to the leaf write call.  It uses only
the existing pgstat_report_wait_start()/end() inline helpers, which
are allocation-free and safe to call before MyProc is set up, so this
remains safe to invoke from within error reporting paths.
---
 src/backend/utils/activity/wait_event_names.txt | 2 ++
 src/backend/utils/error/elog.c                  | 6 ++++++
 2 files changed, 8 insertions(+)

diff --git a/src/backend/utils/activity/wait_event_names.txt b/src/backend/utils/activity/wait_event_names.txt
index 5537a2d2530..ce33807c3fe 100644
--- a/src/backend/utils/activity/wait_event_names.txt
+++ b/src/backend/utils/activity/wait_event_names.txt
@@ -253,6 +253,8 @@ SLRU_WRITE	"Waiting for a write of an SLRU page."
 SNAPBUILD_READ	"Waiting for a read of a serialized historical catalog snapshot."
 SNAPBUILD_SYNC	"Waiting for a serialized historical catalog snapshot to reach durable storage."
 SNAPBUILD_WRITE	"Waiting for a write of a serialized historical catalog snapshot."
+STDERR_WRITE	"Waiting for a write to the server's standard error stream."
+SYSLOGGER_WRITE	"Waiting for a write to the syslogger pipe."
 TIMELINE_HISTORY_FILE_SYNC	"Waiting for a timeline history file received via streaming replication to reach durable storage."
 TIMELINE_HISTORY_FILE_WRITE	"Waiting for a write of a timeline history file received via streaming replication."
 TIMELINE_HISTORY_READ	"Waiting for a read of a timeline history file."
diff --git a/src/backend/utils/error/elog.c b/src/backend/utils/error/elog.c
index aa530d3685e..fa38d6c6df8 100644
--- a/src/backend/utils/error/elog.c
+++ b/src/backend/utils/error/elog.c
@@ -2662,7 +2662,9 @@ write_console(const char *line, int len)
 	 * We ignore any error from write() here.  We have no useful way to report
 	 * it ... certainly whining on stderr isn't likely to be productive.
 	 */
+	pgstat_report_wait_start(WAIT_EVENT_STDERR_WRITE);
 	rc = write(fileno(stderr), line, len);
+	pgstat_report_wait_end();
 	(void) rc;
 }
 
@@ -3503,7 +3505,9 @@ write_pipe_chunks(char *data, int len, int dest)
 		/* no need to set PIPE_PROTO_IS_LAST yet */
 		p.proto.len = PIPE_MAX_PAYLOAD;
 		memcpy(p.proto.data, data, PIPE_MAX_PAYLOAD);
+		pgstat_report_wait_start(WAIT_EVENT_SYSLOGGER_WRITE);
 		rc = write(fd, &p, PIPE_HEADER_SIZE + PIPE_MAX_PAYLOAD);
+		pgstat_report_wait_end();
 		(void) rc;
 		data += PIPE_MAX_PAYLOAD;
 		len -= PIPE_MAX_PAYLOAD;
@@ -3513,7 +3517,9 @@ write_pipe_chunks(char *data, int len, int dest)
 	p.proto.flags |= PIPE_PROTO_IS_LAST;
 	p.proto.len = len;
 	memcpy(p.proto.data, data, len);
+	pgstat_report_wait_start(WAIT_EVENT_SYSLOGGER_WRITE);
 	rc = write(fd, &p, PIPE_HEADER_SIZE + len);
+	pgstat_report_wait_end();
 	(void) rc;
 }
 
-- 
2.50.1 (Apple Git-155)

