On Wed, Sep 08, 2021 at 08:46:44AM -0400, Andrew Dunstan wrote:
> Yeah. A very simple change would be to use two different values for json
> (say 'y' and 'n'). A slightly more principled scheme might use the top
> bit for the end marker and the bottom 3 bits for the dest type (so up to
> 8 types possible), with the rest available for future use.

I was thinking to track stderr as a case where no bits are set in the
flags for the area of the destinations, but that's a bit crazy if we
have a lot of margin in what can be stored.  I have looked at that and
finished with the attached which is an improvement IMO, especially
when it comes to the header validation.

FWIW, while looking at my own external module for the JSON logs, I
noticed that I used the chunk protocol when the log redirection is
enabled, but just enforced everything to be sent to stderr.
--
Michael
diff --git a/src/include/postmaster/syslogger.h 
b/src/include/postmaster/syslogger.h
index 1491eecb0f..c79dfbeba2 100644
--- a/src/include/postmaster/syslogger.h
+++ b/src/include/postmaster/syslogger.h
@@ -46,8 +46,7 @@ typedef struct
        char            nuls[2];                /* always \0\0 */
        uint16          len;                    /* size of this chunk (counts 
data only) */
        int32           pid;                    /* writer's pid */
-       char            is_last;                /* last chunk of message? 't' 
or 'f' ('T' or
-                                                                * 'F' for CSV 
case) */
+       bits8           flags;                  /* bitmask of PIPE_PROTO_* */
        char            data[FLEXIBLE_ARRAY_MEMBER];    /* data payload starts 
here */
 } PipeProtoHeader;
 
@@ -60,6 +59,11 @@ typedef union
 #define PIPE_HEADER_SIZE  offsetof(PipeProtoHeader, data)
 #define PIPE_MAX_PAYLOAD  ((int) (PIPE_CHUNK_SIZE - PIPE_HEADER_SIZE))
 
+/* flag bits for PipeProtoHeader->flags */
+#define PIPE_PROTO_IS_LAST     0x01    /* last chunk of message? */
+/* log destinations */
+#define PIPE_PROTO_DEST_STDERR 0x10
+#define PIPE_PROTO_DEST_CSVLOG 0x20
 
 /* GUC options */
 extern bool Logging_collector;
diff --git a/src/backend/postmaster/syslogger.c 
b/src/backend/postmaster/syslogger.c
index cad43bdef2..c00b2dc186 100644
--- a/src/backend/postmaster/syslogger.c
+++ b/src/backend/postmaster/syslogger.c
@@ -891,8 +891,7 @@ process_pipe_input(char *logbuffer, int *bytes_in_logbuffer)
                if (p.nuls[0] == '\0' && p.nuls[1] == '\0' &&
                        p.len > 0 && p.len <= PIPE_MAX_PAYLOAD &&
                        p.pid != 0 &&
-                       (p.is_last == 't' || p.is_last == 'f' ||
-                        p.is_last == 'T' || p.is_last == 'F'))
+                       (p.flags & (PIPE_PROTO_DEST_STDERR | 
PIPE_PROTO_DEST_CSVLOG)) != 0)
                {
                        List       *buffer_list;
                        ListCell   *cell;
@@ -906,8 +905,15 @@ process_pipe_input(char *logbuffer, int 
*bytes_in_logbuffer)
                        if (count < chunklen)
                                break;
 
-                       dest = (p.is_last == 'T' || p.is_last == 'F') ?
-                               LOG_DESTINATION_CSVLOG : LOG_DESTINATION_STDERR;
+                       if ((p.flags & PIPE_PROTO_DEST_STDERR) != 0)
+                               dest = LOG_DESTINATION_STDERR;
+                       else if ((p.flags & PIPE_PROTO_DEST_CSVLOG) != 0)
+                               dest = LOG_DESTINATION_CSVLOG;
+                       else
+                       {
+                               /* this should never happen as of the header 
validation */
+                               Assert(false);
+                       }
 
                        /* Locate any existing buffer for this source pid */
                        buffer_list = buffer_lists[p.pid % NBUFFER_LISTS];
@@ -924,7 +930,7 @@ process_pipe_input(char *logbuffer, int *bytes_in_logbuffer)
                                        free_slot = buf;
                        }
 
-                       if (p.is_last == 'f' || p.is_last == 'F')
+                       if ((p.flags & PIPE_PROTO_IS_LAST) == 0)
                        {
                                /*
                                 * Save a complete non-final chunk in a per-pid 
buffer
diff --git a/src/backend/utils/error/elog.c b/src/backend/utils/error/elog.c
index 816b071afa..2af87ee3bd 100644
--- a/src/backend/utils/error/elog.c
+++ b/src/backend/utils/error/elog.c
@@ -3250,11 +3250,16 @@ write_pipe_chunks(char *data, int len, int dest)
 
        p.proto.nuls[0] = p.proto.nuls[1] = '\0';
        p.proto.pid = MyProcPid;
+       p.proto.flags = 0;
+       if (dest == LOG_DESTINATION_STDERR)
+               p.proto.flags |= PIPE_PROTO_DEST_STDERR;
+       else if (dest == LOG_DESTINATION_CSVLOG)
+               p.proto.flags |= PIPE_PROTO_DEST_CSVLOG;
 
        /* write all but the last chunk */
        while (len > PIPE_MAX_PAYLOAD)
        {
-               p.proto.is_last = (dest == LOG_DESTINATION_CSVLOG ? 'F' : 'f');
+               /* no need to set PIPE_PROTO_IS_LAST yet */
                p.proto.len = PIPE_MAX_PAYLOAD;
                memcpy(p.proto.data, data, PIPE_MAX_PAYLOAD);
                rc = write(fd, &p, PIPE_HEADER_SIZE + PIPE_MAX_PAYLOAD);
@@ -3264,7 +3269,7 @@ write_pipe_chunks(char *data, int len, int dest)
        }
 
        /* write the last chunk */
-       p.proto.is_last = (dest == LOG_DESTINATION_CSVLOG ? 'T' : 't');
+       p.proto.flags |= PIPE_PROTO_IS_LAST;
        p.proto.len = len;
        memcpy(p.proto.data, data, len);
        rc = write(fd, &p, PIPE_HEADER_SIZE + len);

Attachment: signature.asc
Description: PGP signature

Reply via email to