Patch: Allow formatting in log_line_prefix

Started by David Rowleyover 12 years ago3 messages
#1David Rowley
dgrowleyml@gmail.com
1 attachment(s)

Heikki wrote that it might be useful to allow formatting in the
log_line_prefix here
/messages/by-id/5187CADB.50306@vmware.com

I thought I'd take a bash at implementing space padding part on
log_line_prefix options.

It's been a while since I worked with the PostgreSQL source, so please
forgive me if my coding style is a bit off or the patch is not quite in the
correct format.

It's a little rough around the edges at the moment and likely the
documentation needs more work, but I'm at the stage of wanting to know if
this is even wanted or needed by people.

If you apply this patch you can do things like have %10u %-10d in your
log_line_prefix which will include spaces to give the option the number you
specify as the minimum width. Left and right aligning is supported.

Let this be the thread to collect consensus to whether this needed and
useful.

Regards

David Rowley

Attachments:

log_line_formatting_v0.1.patchapplication/octet-stream; name=log_line_formatting_v0.1.patchDownload
diff -u -r b/doc/src/sgml/config.sgml a/doc/src/sgml/config.sgml
--- b/doc/src/sgml/config.sgml	2013-08-25 07:14:17.000000000 +1200
+++ a/doc/src/sgml/config.sgml	2013-08-26 00:33:31.158147304 +1200
@@ -3942,7 +3942,13 @@
          Unrecognized escapes are ignored. Other
          characters are copied straight to the log line. Some escapes are
          only recognized by session processes, and are ignored by
-         background processes such as the main server process.
+         background processes such as the main server process. Status
+         information may be aligned either left or right by specifying a
+         numeric literal after the % and before the option. A negative
+         padding will cause the status information to be padded on the
+         right with spaces to give it a minimum width. Whereas a positive
+         padding will pad on the left. Padding can be useful keep log 
+         files more human readable.
          This parameter can only be set in the <filename>postgresql.conf</>
          file or on the server command line. The default is an empty string.
 
Only in a/doc/src/sgml: config.sgml~
Only in a/doc/src/sgml: html
Only in a: .git
Only in a/src/backend/bootstrap: bootparse.c
Only in a/src/backend/bootstrap: bootscanner.c
Only in a/src/backend/catalog: postgres.bki
Only in a/src/backend/catalog: postgres.description
Only in a/src/backend/catalog: postgres.shdescription
Only in a/src/backend/catalog: schemapg.h
Only in a/src/backend/parser: gram.c
Only in a/src/backend/parser: gram.h
Only in a/src/backend/parser: scan.c
Only in a/src/backend/replication: repl_gram.c
Only in a/src/backend/replication: repl_scanner.c
Only in a/src/backend/utils: errcodes.h
diff -u -r b/src/backend/utils/error/elog.c a/src/backend/utils/error/elog.c
--- b/src/backend/utils/error/elog.c	2013-08-25 07:14:17.000000000 +1200
+++ a/src/backend/utils/error/elog.c	2013-08-27 00:18:50.852641499 +1200
@@ -167,6 +167,7 @@
 	} while (0)
 
 
+static const char *process_log_prefix_padding(const char *p, int *padding);
 static void log_line_prefix(StringInfo buf, ErrorData *edata);
 static void send_message_to_server_log(ErrorData *edata);
 static void send_message_to_frontend(ErrorData *edata);
@@ -2120,6 +2121,41 @@
 }
 
 /*
+ * helper function for processing the format string in
+ * log_line_prefix()
+ */
+static const char
+*process_log_prefix_padding(const char *p, int *ppadding)
+{
+	int	paddingsign = 1;
+	int	padding = 0;	
+	
+	if (*p == '-')
+	{
+		p++;
+
+		if (*p == '\0')		/* Did the buf end in %- ? */
+			return NULL;
+		paddingsign = -1;
+	}
+	
+
+	/* generate an int version of the numerical string */
+	while (*p >= '0' && *p <= '9')
+		padding = padding * 10 + (*p++ - '0');
+
+	/* Format is invalid if it ends with the padding number */
+	if (*p == '\0')
+		return NULL;
+
+	padding *= paddingsign;
+	*ppadding = padding;
+	return p;
+
+}
+
+
+/*
  * Format tag info for log lines; append to the provided buffer.
  */
 static void
@@ -2129,10 +2165,9 @@
 	static long log_line_number = 0;
 
 	/* has counter been reset in current process? */
-	static int	log_my_pid = 0;
-
-	int			format_len;
-	int			i;
+	static int		log_my_pid = 0;
+	int			padding;
+	const char		*p;	
 
 	/*
 	 * This is one of the few places where we'd rather not inherit a static
@@ -2151,23 +2186,43 @@
 	if (Log_line_prefix == NULL)
 		return;					/* in case guc hasn't run yet */
 
-	format_len = strlen(Log_line_prefix);
-
-	for (i = 0; i < format_len; i++)
+	/*
+	 * The Log_line_prefix also supports optional space padding similar
+	 * to printf(). e.g. %-10u will pad the right side of the username
+	 * to make it at least 10 chars wide. %10u would pad the left side.
+	 */
+	for (p = Log_line_prefix; *p != '\0'; p++)
 	{
-		if (Log_line_prefix[i] != '%')
+		if (*p != '%')
 		{
 			/* literal char, just copy */
-			appendStringInfoChar(buf, Log_line_prefix[i]);
+			appendStringInfoChar(buf, *p);
 			continue;
 		}
-		/* go to char after '%' */
-		i++;
-		if (i >= format_len)
+
+		/* must be a '%', so skip to the next char */
+		p++;
+		if (*p == '\0')
 			break;				/* format error - ignore it */
+		else if (*p == '%')
+		{
+			/* string contains %% */
+			appendStringInfoChar(buf, '%');
+			continue;
+		}
+
+
+		/*
+		 * Process any formatting which may exist after the '%'.
+		 * Note that this moves p passed the padding number
+		 * if it exists.
+		 */
+		if ((p = process_log_prefix_padding(p, &padding)) == NULL)
+			break;
+
 
 		/* process the option */
-		switch (Log_line_prefix[i])
+		switch (*p)
 		{
 			case 'a':
 				if (MyProcPort)
@@ -2176,8 +2231,13 @@
 
 					if (appname == NULL || *appname == '\0')
 						appname = _("[unknown]");
-					appendStringInfoString(buf, appname);
+					appendStringInfo(buf, "%*s", padding, appname);
+				}
+				else 
+				{
+					appendStringInfoSpaces(buf, padding);
 				}
+
 				break;
 			case 'u':
 				if (MyProcPort)
@@ -2186,7 +2246,11 @@
 
 					if (username == NULL || *username == '\0')
 						username = _("[unknown]");
-					appendStringInfoString(buf, username);
+					appendStringInfo(buf, "%*s", padding, username);
+				}
+				else 
+				{
+					appendStringInfoSpaces(buf, padding);
 				}
 				break;
 			case 'd':
@@ -2196,21 +2260,30 @@
 
 					if (dbname == NULL || *dbname == '\0')
 						dbname = _("[unknown]");
-					appendStringInfoString(buf, dbname);
+					appendStringInfo(buf, "%*s", padding, dbname);
+				}
+				else 
+				{
+					appendStringInfoSpaces(buf, padding);
 				}
 				break;
 			case 'c':
-				appendStringInfo(buf, "%lx.%x", (long) (MyStartTime), MyProcPid);
+				{
+					char strfbuf[128];
+					snprintf(strfbuf, sizeof(strfbuf) - 1, "%lx.%x", 
+						(long) (MyStartTime), MyProcPid);
+					appendStringInfo(buf, "%*s", padding, strfbuf);
+				}
 				break;
 			case 'p':
-				appendStringInfo(buf, "%d", MyProcPid);
+				appendStringInfo(buf, "%*d", padding, MyProcPid);
 				break;
 			case 'l':
-				appendStringInfo(buf, "%ld", log_line_number);
+				appendStringInfo(buf, "%*ld", padding, log_line_number);
 				break;
 			case 'm':
 				setup_formatted_log_time();
-				appendStringInfoString(buf, formatted_log_time);
+				appendStringInfo(buf, "%*s", padding, formatted_log_time);
 				break;
 			case 't':
 				{
@@ -2220,13 +2293,13 @@
 					pg_strftime(strfbuf, sizeof(strfbuf),
 								"%Y-%m-%d %H:%M:%S %Z",
 								pg_localtime(&stamp_time, log_timezone));
-					appendStringInfoString(buf, strfbuf);
+					appendStringInfo(buf, "%*s", padding, strfbuf);
 				}
 				break;
 			case 's':
 				if (formatted_start_time[0] == '\0')
 					setup_formatted_start_time();
-				appendStringInfoString(buf, formatted_start_time);
+				appendStringInfo(buf, "%*s", padding, formatted_start_time);
 				break;
 			case 'i':
 				if (MyProcPort)
@@ -2235,43 +2308,70 @@
 					int			displen;
 
 					psdisp = get_ps_display(&displen);
-					appendBinaryStringInfo(buf, psdisp, displen);
+					appendStringInfo(buf, "%*s", padding, psdisp);
+				}
+				else 
+				{
+					appendStringInfoSpaces(buf, padding);
 				}
 				break;
 			case 'r':
 				if (MyProcPort && MyProcPort->remote_host)
 				{
-					appendStringInfoString(buf, MyProcPort->remote_host);
-					if (MyProcPort->remote_port &&
-						MyProcPort->remote_port[0] != '\0')
-						appendStringInfo(buf, "(%s)",
-										 MyProcPort->remote_port);
+					if (MyProcPort->remote_port && MyProcPort->remote_port[0] != '\0')
+					{
+						/* 
+						 * This option is slightly special as the port number
+	 					 * may be appended onto the end. Here we need to build
+						 * 1 string which contains the remote_host and optionally
+						 * the remote_port (if set) so we can properly align the
+						 * string.
+						 */
+
+						char *hostport;
+						int alloclen = strlen(MyProcPort->remote_host) +
+							 strlen(MyProcPort->remote_port) + 3; 
+						hostport = palloc(alloclen);
+						sprintf(hostport, "%s(%s)", MyProcPort->remote_host, MyProcPort->remote_port);
+						appendStringInfo(buf, "%*s", padding, hostport);
+						pfree(hostport);
+						
+					}
+					else
+					{
+						appendStringInfo(buf, "%*s", padding, MyProcPort->remote_host);
+					}
+				}
+				else 
+				{
+					appendStringInfoSpaces(buf, padding);
 				}
 				break;
 			case 'h':
 				if (MyProcPort && MyProcPort->remote_host)
-					appendStringInfoString(buf, MyProcPort->remote_host);
+					appendStringInfo(buf, "%*s", padding, MyProcPort->remote_host);
+				else
+					appendStringInfoSpaces(buf, padding);
 				break;
 			case 'q':
 				/* in postmaster and friends, stop if %q is seen */
 				/* in a backend, just ignore */
 				if (MyProcPort == NULL)
-					i = format_len;
+					return;
 				break;
 			case 'v':
 				/* keep VXID format in sync with lockfuncs.c */
 				if (MyProc != NULL && MyProc->backendId != InvalidBackendId)
 					appendStringInfo(buf, "%d/%u",
 									 MyProc->backendId, MyProc->lxid);
+				else
+					appendStringInfoSpaces(buf, padding);
 				break;
 			case 'x':
-				appendStringInfo(buf, "%u", GetTopTransactionIdIfAny());
+				appendStringInfo(buf, "%*u", padding, GetTopTransactionIdIfAny());
 				break;
 			case 'e':
-				appendStringInfoString(buf, unpack_sql_state(edata->sqlerrcode));
-				break;
-			case '%':
-				appendStringInfoChar(buf, '%');
+				appendStringInfo(buf, "%*s", padding, unpack_sql_state(edata->sqlerrcode));
 				break;
 			default:
 				/* format error - ignore it */
Only in a/src/backend/utils/error: elog.c~
Only in a/src/backend/utils: fmgroids.h
Only in a/src/backend/utils: fmgrtab.c
Only in a/src/backend/utils/misc: guc-file.c
Only in a/src/backend/utils/sort: qsort_tuple.c
Only in a/src/bin/psql: psqlscan.c
Only in a/src/bin/psql: sql_help.c
Only in a/src/bin/psql: sql_help.h
Only in a/src/interfaces/ecpg/preproc: pgc.c
Only in a/src/interfaces/ecpg/preproc: preproc.c
Only in a/src/interfaces/ecpg/preproc: preproc.h
Only in a/src/interfaces/ecpg/preproc: preproc.y
Only in a/src/pl/plpgsql/src: plerrcodes.h
Only in a/src/pl/plpgsql/src: pl_gram.c
Only in a/src/pl/plpgsql/src: pl_gram.h
Only in a/src/tools/entab: entab
Only in a/src/tools/entab: entab.o
Only in a/src/tools/pgindent: log_line_formatting.patch
#2Vik Fearing
vik.fearing@dalibo.com
In reply to: David Rowley (#1)
1 attachment(s)
Re: Patch: Allow formatting in log_line_prefix

On 08/27/2013 05:06 AM, David Rowley wrote:

Heikki wrote that it might be useful to allow formatting in the
log_line_prefix here
/messages/by-id/5187CADB.50306@vmware.com

I thought I'd take a bash at implementing space padding part on
log_line_prefix options.

It's been a while since I worked with the PostgreSQL source, so please
forgive me if my coding style is a bit off or the patch is not quite
in the correct format.

It's a little rough around the edges at the moment and likely the
documentation needs more work, but I'm at the stage of wanting to know
if this is even wanted or needed by people.

If you apply this patch you can do things like have %10u %-10d in your
log_line_prefix which will include spaces to give the option the
number you specify as the minimum width. Left and right aligning is
supported.

Let this be the thread to collect consensus to whether this needed and
useful.

I was just working on this last week! I didn't get a chance to post it
because I was still polishing it. I first took the same approach as you
but decided it reduced the clarity of the code so I re-did it a
different way. I'll attach it here along with yours to see which way
others like it.

Did you test performance? You should add your patch to the next commitfest.

--
Vik

Attachments:

llp_formatting.v2.patchtext/x-patch; name=llp_formatting.v2.patchDownload
*** a/doc/src/sgml/config.sgml
--- b/doc/src/sgml/config.sgml
***************
*** 4046,4052 **** local0.*    /var/log/postgresql
--- 4046,4062 ----
             </tbody>
            </tgroup>
           </informaltable>
+          </para>
+ 
+          <para>
+          Between the <literal>%</> and the escape letter can be added a
+          minimum field width.  If the value is shorter than the specified
+          width, it is left-padded with spaces.  If the value is larger then
+          it takes the space it needs; it is not truncated.  A negative width
+          will cause the value to be right-padded.
+          </para>
  
+          <para>
           The <literal>%c</> escape prints a quasi-unique session identifier,
           consisting of two 4-byte hexadecimal numbers (without leading zeros)
           separated by a dot.  The numbers are the process start time and the
*** a/src/backend/utils/error/elog.c
--- b/src/backend/utils/error/elog.c
***************
*** 2131,2139 **** log_line_prefix(StringInfo buf, ErrorData *edata)
--- 2131,2145 ----
  	/* has counter been reset in current process? */
  	static int	log_my_pid = 0;
  
+ 	StringInfoData	workbuf;		/* we put the fields in here for later formatting */
+ 	int			field_width;
+ 	bool		left_justify;
+ 
  	int			format_len;
  	int			i;
  
+ 	initStringInfo(&workbuf);
+ 
  	/*
  	 * This is one of the few places where we'd rather not inherit a static
  	 * variable's value from the postmaster.  But since we will, reset it when
***************
*** 2163,2171 **** log_line_prefix(StringInfo buf, ErrorData *edata)
  		}
  		/* go to char after '%' */
  		i++;
! 		if (i >= format_len)
  			break;				/* format error - ignore it */
  
  		/* process the option */
  		switch (Log_line_prefix[i])
  		{
--- 2169,2198 ----
  		}
  		/* go to char after '%' */
  		i++;
! 
! 		/* process the field width modifier, if present */
! 		left_justify = i < format_len && Log_line_prefix[i] == '-';
! 		if (left_justify)
! 				i++;
! 
! 		field_width = 0;
! 		while (i < format_len && Log_line_prefix[i] >= '0' && Log_line_prefix[i] <= '9')
! 		{
! 			field_width = 10 * field_width + (Log_line_prefix[i] - '0');
! 			if (field_width < 0)
! 					break;		/* integer out of range - consider it a format error */
! 			i++;
! 		}
! 
! 		if (i >= format_len || field_width < 0 || (left_justify && field_width == 0))
  			break;				/* format error - ignore it */
  
+ 		if (left_justify)
+ 				field_width = -field_width;
+ 
+ 		/* get the working buffer ready */
+ 		resetStringInfo(&workbuf);
+ 
  		/* process the option */
  		switch (Log_line_prefix[i])
  		{
***************
*** 2176,2182 **** log_line_prefix(StringInfo buf, ErrorData *edata)
  
  					if (appname == NULL || *appname == '\0')
  						appname = _("[unknown]");
! 					appendStringInfoString(buf, appname);
  				}
  				break;
  			case 'u':
--- 2203,2209 ----
  
  					if (appname == NULL || *appname == '\0')
  						appname = _("[unknown]");
! 					appendStringInfoString(&workbuf, appname);
  				}
  				break;
  			case 'u':
***************
*** 2186,2192 **** log_line_prefix(StringInfo buf, ErrorData *edata)
  
  					if (username == NULL || *username == '\0')
  						username = _("[unknown]");
! 					appendStringInfoString(buf, username);
  				}
  				break;
  			case 'd':
--- 2213,2219 ----
  
  					if (username == NULL || *username == '\0')
  						username = _("[unknown]");
! 					appendStringInfoString(&workbuf, username);
  				}
  				break;
  			case 'd':
***************
*** 2196,2216 **** log_line_prefix(StringInfo buf, ErrorData *edata)
  
  					if (dbname == NULL || *dbname == '\0')
  						dbname = _("[unknown]");
! 					appendStringInfoString(buf, dbname);
  				}
  				break;
  			case 'c':
! 				appendStringInfo(buf, "%lx.%x", (long) (MyStartTime), MyProcPid);
  				break;
  			case 'p':
! 				appendStringInfo(buf, "%d", MyProcPid);
  				break;
  			case 'l':
! 				appendStringInfo(buf, "%ld", log_line_number);
  				break;
  			case 'm':
  				setup_formatted_log_time();
! 				appendStringInfoString(buf, formatted_log_time);
  				break;
  			case 't':
  				{
--- 2223,2243 ----
  
  					if (dbname == NULL || *dbname == '\0')
  						dbname = _("[unknown]");
! 					appendStringInfoString(&workbuf, dbname);
  				}
  				break;
  			case 'c':
! 				appendStringInfo(&workbuf, "%lx.%x", (long) (MyStartTime), MyProcPid);
  				break;
  			case 'p':
! 				appendStringInfo(&workbuf, "%d", MyProcPid);
  				break;
  			case 'l':
! 				appendStringInfo(&workbuf, "%ld", log_line_number);
  				break;
  			case 'm':
  				setup_formatted_log_time();
! 				appendStringInfoString(&workbuf, formatted_log_time);
  				break;
  			case 't':
  				{
***************
*** 2220,2232 **** log_line_prefix(StringInfo buf, ErrorData *edata)
  					pg_strftime(strfbuf, sizeof(strfbuf),
  								"%Y-%m-%d %H:%M:%S %Z",
  								pg_localtime(&stamp_time, log_timezone));
! 					appendStringInfoString(buf, strfbuf);
  				}
  				break;
  			case 's':
  				if (formatted_start_time[0] == '\0')
  					setup_formatted_start_time();
! 				appendStringInfoString(buf, formatted_start_time);
  				break;
  			case 'i':
  				if (MyProcPort)
--- 2247,2259 ----
  					pg_strftime(strfbuf, sizeof(strfbuf),
  								"%Y-%m-%d %H:%M:%S %Z",
  								pg_localtime(&stamp_time, log_timezone));
! 					appendStringInfoString(&workbuf, strfbuf);
  				}
  				break;
  			case 's':
  				if (formatted_start_time[0] == '\0')
  					setup_formatted_start_time();
! 				appendStringInfoString(&workbuf, formatted_start_time);
  				break;
  			case 'i':
  				if (MyProcPort)
***************
*** 2235,2256 **** log_line_prefix(StringInfo buf, ErrorData *edata)
  					int			displen;
  
  					psdisp = get_ps_display(&displen);
! 					appendBinaryStringInfo(buf, psdisp, displen);
  				}
  				break;
  			case 'r':
  				if (MyProcPort && MyProcPort->remote_host)
  				{
! 					appendStringInfoString(buf, MyProcPort->remote_host);
  					if (MyProcPort->remote_port &&
  						MyProcPort->remote_port[0] != '\0')
! 						appendStringInfo(buf, "(%s)",
  										 MyProcPort->remote_port);
  				}
  				break;
  			case 'h':
  				if (MyProcPort && MyProcPort->remote_host)
! 					appendStringInfoString(buf, MyProcPort->remote_host);
  				break;
  			case 'q':
  				/* in postmaster and friends, stop if %q is seen */
--- 2262,2283 ----
  					int			displen;
  
  					psdisp = get_ps_display(&displen);
! 					appendBinaryStringInfo(&workbuf, psdisp, displen);
  				}
  				break;
  			case 'r':
  				if (MyProcPort && MyProcPort->remote_host)
  				{
! 					appendStringInfoString(&workbuf, MyProcPort->remote_host);
  					if (MyProcPort->remote_port &&
  						MyProcPort->remote_port[0] != '\0')
! 						appendStringInfo(&workbuf, "(%s)",
  										 MyProcPort->remote_port);
  				}
  				break;
  			case 'h':
  				if (MyProcPort && MyProcPort->remote_host)
! 					appendStringInfoString(&workbuf, MyProcPort->remote_host);
  				break;
  			case 'q':
  				/* in postmaster and friends, stop if %q is seen */
***************
*** 2261,2283 **** log_line_prefix(StringInfo buf, ErrorData *edata)
  			case 'v':
  				/* keep VXID format in sync with lockfuncs.c */
  				if (MyProc != NULL && MyProc->backendId != InvalidBackendId)
! 					appendStringInfo(buf, "%d/%u",
  									 MyProc->backendId, MyProc->lxid);
  				break;
  			case 'x':
! 				appendStringInfo(buf, "%u", GetTopTransactionIdIfAny());
  				break;
  			case 'e':
! 				appendStringInfoString(buf, unpack_sql_state(edata->sqlerrcode));
  				break;
  			case '%':
! 				appendStringInfoChar(buf, '%');
  				break;
  			default:
  				/* format error - ignore it */
  				break;
  		}
  	}
  }
  
  /*
--- 2288,2317 ----
  			case 'v':
  				/* keep VXID format in sync with lockfuncs.c */
  				if (MyProc != NULL && MyProc->backendId != InvalidBackendId)
! 					appendStringInfo(&workbuf, "%d/%u",
  									 MyProc->backendId, MyProc->lxid);
  				break;
  			case 'x':
! 				appendStringInfo(&workbuf, "%u", GetTopTransactionIdIfAny());
  				break;
  			case 'e':
! 				appendStringInfoString(&workbuf, unpack_sql_state(edata->sqlerrcode));
  				break;
  			case '%':
! 				appendStringInfoChar(&workbuf, '%');
  				break;
  			default:
  				/* format error - ignore it */
  				break;
  		}
+ 
+ 		if (field_width == 0)
+ 				appendStringInfoString(buf, workbuf.data);	/* fast path */
+ 		else
+ 				appendStringInfo(buf, "%*s", field_width, workbuf.data);
  	}
+ 
+ 	pfree(workbuf.data);
  }
  
  /*
#3David Rowley
dgrowleyml@gmail.com
In reply to: Vik Fearing (#2)
Re: Patch: Allow formatting in log_line_prefix

On Tue, Aug 27, 2013 at 7:55 PM, Vik Fearing <vik.fearing@dalibo.com> wrote:

On 08/27/2013 05:06 AM, David Rowley wrote:

Heikki wrote that it might be useful to allow formatting in the
log_line_prefix here
/messages/by-id/5187CADB.50306@vmware.com

I thought I'd take a bash at implementing space padding part on
log_line_prefix options.

It's been a while since I worked with the PostgreSQL source, so please
forgive me if my coding style is a bit off or the patch is not quite
in the correct format.

It's a little rough around the edges at the moment and likely the
documentation needs more work, but I'm at the stage of wanting to know
if this is even wanted or needed by people.

If you apply this patch you can do things like have %10u %-10d in your
log_line_prefix which will include spaces to give the option the
number you specify as the minimum width. Left and right aligning is
supported.

Let this be the thread to collect consensus to whether this needed and
useful.

I was just working on this last week! I didn't get a chance to post it
because I was still polishing it. I first took the same approach as you
but decided it reduced the clarity of the code so I re-did it a
different way. I'll attach it here along with yours to see which way
others like it.

I guess it's not too surprising someone else took this up too.
I was not too happy either at having to edit code for each option, even
more so with the temp buffers I had to create in 2 places where 2 variables
we used in the formatting.
I did not do any performance testing yet. I didn't think the regression
would be very big with my patch as I'm only doing extra copying for %c and
%r. I had also removed the strlen() before the loop starts, which I thought
might actually speed the whole thing up a bit.

I've not tested applying your patch yet and I'm not the best at reading
context diffs to tell, but I get the impression that we both decided to pad
even when the variable is not valid, e.g. the host and database being empty
during start-up.

Did you test performance? You should add your patch to the next
commitfest.

--
Vik

I could add it, but I'm just thinking it's a bit strange to have 2 patches
in a commitfest which do the same thing, but saying that we both went about
it quite differently, I don't see a way to take the best out of both and
make one. For me it looks like a bit of a choice between performance and
more compact and cleaner code. I didn't think processing the
log_line_prefix would be too big a hotspot, but I know performance
regression is normally avoided at great cost, if necessary. Perhaps someone
else can chime in here with some advice about preferences.

I could perhaps run a few benchmarks to test performance of the 2 of
someone thought it was a good idea.

Regards

David