@@ -167,6 +167,7 @@ static char formatted_log_time[FORMATTED_TS_LEN];
167167 } while (0)
168168
169169
170+ static const char * process_log_prefix_padding (const char * p , int * padding );
170171static void log_line_prefix (StringInfo buf , ErrorData * edata );
171172static void send_message_to_server_log (ErrorData * edata );
172173static void send_message_to_frontend (ErrorData * edata );
@@ -2119,6 +2120,42 @@ setup_formatted_start_time(void)
21192120 pg_localtime (& stamp_time , log_timezone ));
21202121}
21212122
2123+ /*
2124+ * process_log_prefix_padding --- helper function for processing the format
2125+ * string in log_line_prefix
2126+ *
2127+ * Note: This function returns NULL if it finds something which
2128+ * it deems invalid in the format string.
2129+ */
2130+ static const char *
2131+ process_log_prefix_padding (const char * p , int * ppadding )
2132+ {
2133+ int paddingsign = 1 ;
2134+ int padding = 0 ;
2135+
2136+ if (* p == '-' )
2137+ {
2138+ p ++ ;
2139+
2140+ if (* p == '\0' ) /* Did the buf end in %- ? */
2141+ return NULL ;
2142+ paddingsign = -1 ;
2143+ }
2144+
2145+
2146+ /* generate an int version of the numerical string */
2147+ while (* p >= '0' && * p <= '9' )
2148+ padding = padding * 10 + (* p ++ - '0' );
2149+
2150+ /* format is invalid if it ends with the padding number */
2151+ if (* p == '\0' )
2152+ return NULL ;
2153+
2154+ padding *= paddingsign ;
2155+ * ppadding = padding ;
2156+ return p ;
2157+ }
2158+
21222159/*
21232160 * Format tag info for log lines; append to the provided buffer.
21242161 */
@@ -2130,9 +2167,8 @@ log_line_prefix(StringInfo buf, ErrorData *edata)
21302167
21312168 /* has counter been reset in current process? */
21322169 static int log_my_pid = 0 ;
2133-
2134- int format_len ;
2135- int i ;
2170+ int padding ;
2171+ const char * p ;
21362172
21372173 /*
21382174 * This is one of the few places where we'd rather not inherit a static
@@ -2151,23 +2187,48 @@ log_line_prefix(StringInfo buf, ErrorData *edata)
21512187 if (Log_line_prefix == NULL )
21522188 return ; /* in case guc hasn't run yet */
21532189
2154- format_len = strlen (Log_line_prefix );
2155-
2156- for (i = 0 ; i < format_len ; i ++ )
2190+ for (p = Log_line_prefix ; * p != '\0' ; p ++ )
21572191 {
2158- if (Log_line_prefix [ i ] != '%' )
2192+ if (* p != '%' )
21592193 {
21602194 /* literal char, just copy */
2161- appendStringInfoChar (buf , Log_line_prefix [ i ] );
2195+ appendStringInfoChar (buf , * p );
21622196 continue ;
21632197 }
2164- /* go to char after '%' */
2165- i ++ ;
2166- if (i >= format_len )
2198+
2199+ /* must be a '%', so skip to the next char */
2200+ p ++ ;
2201+ if (* p == '\0' )
21672202 break ; /* format error - ignore it */
2203+ else if (* p == '%' )
2204+ {
2205+ /* string contains %% */
2206+ appendStringInfoChar (buf , '%' );
2207+ continue ;
2208+ }
2209+
2210+
2211+ /*
2212+ * Process any formatting which may exist after the '%'. Note that
2213+ * process_log_prefix_padding moves p past the padding number if it
2214+ * exists.
2215+ *
2216+ * Note: Since only '-', '0' to '9' are valid formatting characters
2217+ * we can do a quick check here to pre-check for formatting. If the
2218+ * char is not formatting then we can skip a useless function call.
2219+ *
2220+ * Further note: At least on some platforms, passing %*s rather than
2221+ * %s to appendStringInfo() is substantially slower, so many of the
2222+ * cases below avoid doing that unless non-zero padding is in fact
2223+ * specified.
2224+ */
2225+ if (* p > '9' )
2226+ padding = 0 ;
2227+ else if ((p = process_log_prefix_padding (p , & padding )) == NULL )
2228+ break ;
21682229
21692230 /* process the option */
2170- switch (Log_line_prefix [ i ] )
2231+ switch (* p )
21712232 {
21722233 case 'a' :
21732234 if (MyProcPort )
@@ -2176,8 +2237,15 @@ log_line_prefix(StringInfo buf, ErrorData *edata)
21762237
21772238 if (appname == NULL || * appname == '\0' )
21782239 appname = _ ("[unknown]" );
2179- appendStringInfoString (buf , appname );
2240+ if (padding != 0 )
2241+ appendStringInfo (buf , "%*s" , padding , appname );
2242+ else
2243+ appendStringInfoString (buf , appname );
21802244 }
2245+ else if (padding != 0 )
2246+ appendStringInfoSpaces (buf ,
2247+ padding > 0 ? padding : - padding );
2248+
21812249 break ;
21822250 case 'u' :
21832251 if (MyProcPort )
@@ -2186,8 +2254,14 @@ log_line_prefix(StringInfo buf, ErrorData *edata)
21862254
21872255 if (username == NULL || * username == '\0' )
21882256 username = _ ("[unknown]" );
2189- appendStringInfoString (buf , username );
2257+ if (padding != 0 )
2258+ appendStringInfo (buf , "%*s" , padding , username );
2259+ else
2260+ appendStringInfoString (buf , username );
21902261 }
2262+ else if (padding != 0 )
2263+ appendStringInfoSpaces (buf ,
2264+ padding > 0 ? padding : - padding );
21912265 break ;
21922266 case 'd' :
21932267 if (MyProcPort )
@@ -2196,21 +2270,44 @@ log_line_prefix(StringInfo buf, ErrorData *edata)
21962270
21972271 if (dbname == NULL || * dbname == '\0' )
21982272 dbname = _ ("[unknown]" );
2199- appendStringInfoString (buf , dbname );
2273+ if (padding != 0 )
2274+ appendStringInfo (buf , "%*s" , padding , dbname );
2275+ else
2276+ appendStringInfoString (buf , dbname );
22002277 }
2278+ else if (padding != 0 )
2279+ appendStringInfoSpaces (buf ,
2280+ padding > 0 ? padding : - padding );
22012281 break ;
22022282 case 'c' :
2203- appendStringInfo (buf , "%lx.%x" , (long ) (MyStartTime ), MyProcPid );
2283+ if (padding != 0 )
2284+ {
2285+ char strfbuf [128 ];
2286+ snprintf (strfbuf , sizeof (strfbuf ) - 1 , "%lx.%x" ,
2287+ (long ) (MyStartTime ), MyProcPid );
2288+ appendStringInfo (buf , "%*s" , padding , strfbuf );
2289+ }
2290+ else
2291+ appendStringInfo (buf , "%lx.%x" , (long ) (MyStartTime ), MyProcPid );
22042292 break ;
22052293 case 'p' :
2206- appendStringInfo (buf , "%d" , MyProcPid );
2294+ if (padding != 0 )
2295+ appendStringInfo (buf , "%*d" , padding , MyProcPid );
2296+ else
2297+ appendStringInfo (buf , "%d" , MyProcPid );
22072298 break ;
22082299 case 'l' :
2209- appendStringInfo (buf , "%ld" , log_line_number );
2300+ if (padding != 0 )
2301+ appendStringInfo (buf , "%*ld" , padding , log_line_number );
2302+ else
2303+ appendStringInfo (buf , "%ld" , log_line_number );
22102304 break ;
22112305 case 'm' :
22122306 setup_formatted_log_time ();
2213- appendStringInfoString (buf , formatted_log_time );
2307+ if (padding != 0 )
2308+ appendStringInfo (buf , "%*s" , padding , formatted_log_time );
2309+ else
2310+ appendStringInfoString (buf , formatted_log_time );
22142311 break ;
22152312 case 't' :
22162313 {
@@ -2220,13 +2317,19 @@ log_line_prefix(StringInfo buf, ErrorData *edata)
22202317 pg_strftime (strfbuf , sizeof (strfbuf ),
22212318 "%Y-%m-%d %H:%M:%S %Z" ,
22222319 pg_localtime (& stamp_time , log_timezone ));
2223- appendStringInfoString (buf , strfbuf );
2320+ if (padding != 0 )
2321+ appendStringInfo (buf , "%*s" , padding , strfbuf );
2322+ else
2323+ appendStringInfoString (buf , strfbuf );
22242324 }
22252325 break ;
22262326 case 's' :
22272327 if (formatted_start_time [0 ] == '\0' )
22282328 setup_formatted_start_time ();
2229- appendStringInfoString (buf , formatted_start_time );
2329+ if (padding != 0 )
2330+ appendStringInfo (buf , "%*s" , padding , formatted_start_time );
2331+ else
2332+ appendStringInfoString (buf , formatted_start_time );
22302333 break ;
22312334 case 'i' :
22322335 if (MyProcPort )
@@ -2235,43 +2338,105 @@ log_line_prefix(StringInfo buf, ErrorData *edata)
22352338 int displen ;
22362339
22372340 psdisp = get_ps_display (& displen );
2238- appendBinaryStringInfo (buf , psdisp , displen );
2341+ if (padding != 0 )
2342+ appendStringInfo (buf , "%*s" , padding , psdisp );
2343+ else
2344+ appendBinaryStringInfo (buf , psdisp , displen );
2345+
22392346 }
2347+ else if (padding != 0 )
2348+ appendStringInfoSpaces (buf ,
2349+ padding > 0 ? padding : - padding );
22402350 break ;
22412351 case 'r' :
22422352 if (MyProcPort && MyProcPort -> remote_host )
22432353 {
2244- appendStringInfoString (buf , MyProcPort -> remote_host );
2245- if (MyProcPort -> remote_port &&
2246- MyProcPort -> remote_port [0 ] != '\0' )
2247- appendStringInfo (buf , "(%s)" ,
2248- MyProcPort -> remote_port );
2354+ if (padding != 0 )
2355+ {
2356+ if (MyProcPort -> remote_port && MyProcPort -> remote_port [0 ] != '\0' )
2357+ {
2358+ /*
2359+ * This option is slightly special as the port number
2360+ * may be appended onto the end. Here we need to build
2361+ * 1 string which contains the remote_host and optionally
2362+ * the remote_port (if set) so we can properly align the
2363+ * string.
2364+ */
2365+
2366+ char * hostport ;
2367+ int alloclen = strlen (MyProcPort -> remote_host ) +
2368+ strlen (MyProcPort -> remote_port ) + 3 ;
2369+ hostport = palloc (alloclen );
2370+ sprintf (hostport , "%s(%s)" , MyProcPort -> remote_host , MyProcPort -> remote_port );
2371+ appendStringInfo (buf , "%*s" , padding , hostport );
2372+ pfree (hostport );
2373+ }
2374+ else
2375+ appendStringInfo (buf , "%*s" , padding , MyProcPort -> remote_host );
2376+
2377+ }
2378+ else
2379+ {
2380+ /* padding is 0, so we don't need a temp buffer */
2381+ appendStringInfoString (buf , MyProcPort -> remote_host );
2382+ if (MyProcPort -> remote_port &&
2383+ MyProcPort -> remote_port [0 ] != '\0' )
2384+ appendStringInfo (buf , "(%s)" ,
2385+ MyProcPort -> remote_port );
2386+ }
2387+
22492388 }
2389+ else if (padding != 0 )
2390+ appendStringInfoSpaces (buf ,
2391+ padding > 0 ? padding : - padding );
22502392 break ;
22512393 case 'h' :
2252- if (MyProcPort && MyProcPort -> remote_host )
2253- appendStringInfoString (buf , MyProcPort -> remote_host );
2394+ if (MyProcPort && MyProcPort -> remote_host )
2395+ {
2396+ if (padding != 0 )
2397+ appendStringInfo (buf , "%*s" , padding , MyProcPort -> remote_host );
2398+ else
2399+ appendStringInfoString (buf , MyProcPort -> remote_host );
2400+ }
2401+ else if (padding != 0 )
2402+ appendStringInfoSpaces (buf ,
2403+ padding > 0 ? padding : - padding );
22542404 break ;
22552405 case 'q' :
22562406 /* in postmaster and friends, stop if %q is seen */
22572407 /* in a backend, just ignore */
22582408 if (MyProcPort == NULL )
2259- i = format_len ;
2409+ return ;
22602410 break ;
22612411 case 'v' :
22622412 /* keep VXID format in sync with lockfuncs.c */
22632413 if (MyProc != NULL && MyProc -> backendId != InvalidBackendId )
2264- appendStringInfo (buf , "%d/%u" ,
2265- MyProc -> backendId , MyProc -> lxid );
2414+ {
2415+ if (padding != 0 )
2416+ {
2417+ char strfbuf [128 ];
2418+ snprintf (strfbuf , sizeof (strfbuf ) - 1 , "%d/%u" ,
2419+ MyProc -> backendId , MyProc -> lxid );
2420+ appendStringInfo (buf , "%*s" , padding , strfbuf );
2421+ }
2422+ else
2423+ appendStringInfo (buf , "%d/%u" , MyProc -> backendId , MyProc -> lxid );
2424+ }
2425+ else if (padding != 0 )
2426+ appendStringInfoSpaces (buf ,
2427+ padding > 0 ? padding : - padding );
22662428 break ;
22672429 case 'x' :
2268- appendStringInfo (buf , "%u" , GetTopTransactionIdIfAny ());
2430+ if (padding != 0 )
2431+ appendStringInfo (buf , "%*u" , padding , GetTopTransactionIdIfAny ());
2432+ else
2433+ appendStringInfo (buf , "%u" , GetTopTransactionIdIfAny ());
22692434 break ;
22702435 case 'e' :
2271- appendStringInfoString ( buf , unpack_sql_state ( edata -> sqlerrcode ));
2272- break ;
2273- case '%' :
2274- appendStringInfoChar (buf , '%' );
2436+ if ( padding != 0 )
2437+ appendStringInfo ( buf , "%*s" , padding , unpack_sql_state ( edata -> sqlerrcode )) ;
2438+ else
2439+ appendStringInfoString (buf , unpack_sql_state ( edata -> sqlerrcode ) );
22752440 break ;
22762441 default :
22772442 /* format error - ignore it */
0 commit comments