@@ -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)
21192120pg_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? */
21322169static 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)
21512187if (Log_line_prefix == NULL )
21522188return ;/* 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 );
21622196continue ;
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' )
21672202break ;/* 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{
21722233case 'a' :
21732234if (MyProcPort )
@@ -2176,8 +2237,15 @@ log_line_prefix(StringInfo buf, ErrorData *edata)
21762237
21772238if (appname == NULL || * appname == '\0' )
21782239appname = _ ("[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+
21812249break ;
21822250case 'u' :
21832251if (MyProcPort )
@@ -2186,8 +2254,14 @@ log_line_prefix(StringInfo buf, ErrorData *edata)
21862254
21872255if (username == NULL || * username == '\0' )
21882256username = _ ("[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 );
21912265break ;
21922266case 'd' :
21932267if (MyProcPort )
@@ -2196,21 +2270,44 @@ log_line_prefix(StringInfo buf, ErrorData *edata)
21962270
21972271if (dbname == NULL || * dbname == '\0' )
21982272dbname = _ ("[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 );
22012281break ;
22022282case '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 );
22042292break ;
22052293case 'p' :
2206- appendStringInfo (buf ,"%d" ,MyProcPid );
2294+ if (padding != 0 )
2295+ appendStringInfo (buf ,"%*d" ,padding ,MyProcPid );
2296+ else
2297+ appendStringInfo (buf ,"%d" ,MyProcPid );
22072298break ;
22082299case '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 );
22102304break ;
22112305case 'm' :
22122306setup_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 );
22142311break ;
22152312case 't' :
22162313{
@@ -2220,13 +2317,19 @@ log_line_prefix(StringInfo buf, ErrorData *edata)
22202317pg_strftime (strfbuf ,sizeof (strfbuf ),
22212318"%Y-%m-%d %H:%M:%S %Z" ,
22222319pg_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}
22252325break ;
22262326case 's' :
22272327if (formatted_start_time [0 ]== '\0' )
22282328setup_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 );
22302333break ;
22312334case 'i' :
22322335if (MyProcPort )
@@ -2235,43 +2338,105 @@ log_line_prefix(StringInfo buf, ErrorData *edata)
22352338int displen ;
22362339
22372340psdisp = 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 );
22402350break ;
22412351case 'r' :
22422352if (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 );
22502392break ;
22512393case '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 );
22542404break ;
22552405case 'q' :
22562406/* in postmaster and friends, stop if %q is seen */
22572407/* in a backend, just ignore */
22582408if (MyProcPort == NULL )
2259- i = format_len ;
2409+ return ;
22602410break ;
22612411case 'v' :
22622412/* keep VXID format in sync with lockfuncs.c */
22632413if (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 );
22662428break ;
22672429case 'x' :
2268- appendStringInfo (buf ,"%u" ,GetTopTransactionIdIfAny ());
2430+ if (padding != 0 )
2431+ appendStringInfo (buf ,"%*u" ,padding ,GetTopTransactionIdIfAny ());
2432+ else
2433+ appendStringInfo (buf ,"%u" ,GetTopTransactionIdIfAny ());
22692434break ;
22702435case '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 ) );
22752440break ;
22762441default :
22772442/* format error - ignore it */