1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-30 11:03:19 +03:00

Allow printf-style padding specifications in log_line_prefix.

David Rowley, after a suggestion from Heikki Linnakangas.  Reviewed by
Albe Laurenz, and further edited by me.
This commit is contained in:
Robert Haas
2013-09-26 17:54:20 -04:00
parent d70f8d5f1b
commit 4334639f4b
2 changed files with 210 additions and 39 deletions

View File

@ -167,6 +167,7 @@ static char formatted_log_time[FORMATTED_TS_LEN];
} 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);
@ -2119,6 +2120,42 @@ setup_formatted_start_time(void)
pg_localtime(&stamp_time, log_timezone));
}
/*
* process_log_prefix_padding --- helper function for processing the format
* string in log_line_prefix
*
* Note: This function returns NULL if it finds something which
* it deems invalid in the format string.
*/
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.
*/
@ -2130,9 +2167,8 @@ log_line_prefix(StringInfo buf, ErrorData *edata)
/* has counter been reset in current process? */
static int log_my_pid = 0;
int format_len;
int i;
int padding;
const char *p;
/*
* 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)
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++)
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
* process_log_prefix_padding moves p past the padding number if it
* exists.
*
* Note: Since only '-', '0' to '9' are valid formatting characters
* we can do a quick check here to pre-check for formatting. If the
* char is not formatting then we can skip a useless function call.
*
* Further note: At least on some platforms, passing %*s rather than
* %s to appendStringInfo() is substantially slower, so many of the
* cases below avoid doing that unless non-zero padding is in fact
* specified.
*/
if (*p > '9')
padding = 0;
else 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 +2237,15 @@ log_line_prefix(StringInfo buf, ErrorData *edata)
if (appname == NULL || *appname == '\0')
appname = _("[unknown]");
appendStringInfoString(buf, appname);
if (padding != 0)
appendStringInfo(buf, "%*s", padding, appname);
else
appendStringInfoString(buf, appname);
}
else if (padding != 0)
appendStringInfoSpaces(buf,
padding > 0 ? padding : -padding);
break;
case 'u':
if (MyProcPort)
@ -2186,8 +2254,14 @@ log_line_prefix(StringInfo buf, ErrorData *edata)
if (username == NULL || *username == '\0')
username = _("[unknown]");
appendStringInfoString(buf, username);
if (padding != 0)
appendStringInfo(buf, "%*s", padding, username);
else
appendStringInfoString(buf, username);
}
else if (padding != 0)
appendStringInfoSpaces(buf,
padding > 0 ? padding : -padding);
break;
case 'd':
if (MyProcPort)
@ -2196,21 +2270,44 @@ log_line_prefix(StringInfo buf, ErrorData *edata)
if (dbname == NULL || *dbname == '\0')
dbname = _("[unknown]");
appendStringInfoString(buf, dbname);
if (padding != 0)
appendStringInfo(buf, "%*s", padding, dbname);
else
appendStringInfoString(buf, dbname);
}
else if (padding != 0)
appendStringInfoSpaces(buf,
padding > 0 ? padding : -padding);
break;
case 'c':
appendStringInfo(buf, "%lx.%x", (long) (MyStartTime), MyProcPid);
if (padding != 0)
{
char strfbuf[128];
snprintf(strfbuf, sizeof(strfbuf) - 1, "%lx.%x",
(long) (MyStartTime), MyProcPid);
appendStringInfo(buf, "%*s", padding, strfbuf);
}
else
appendStringInfo(buf, "%lx.%x", (long) (MyStartTime), MyProcPid);
break;
case 'p':
appendStringInfo(buf, "%d", MyProcPid);
if (padding != 0)
appendStringInfo(buf, "%*d", padding, MyProcPid);
else
appendStringInfo(buf, "%d", MyProcPid);
break;
case 'l':
appendStringInfo(buf, "%ld", log_line_number);
if (padding != 0)
appendStringInfo(buf, "%*ld", padding, log_line_number);
else
appendStringInfo(buf, "%ld", log_line_number);
break;
case 'm':
setup_formatted_log_time();
appendStringInfoString(buf, formatted_log_time);
if (padding != 0)
appendStringInfo(buf, "%*s", padding, formatted_log_time);
else
appendStringInfoString(buf, formatted_log_time);
break;
case 't':
{
@ -2220,13 +2317,19 @@ 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);
if (padding != 0)
appendStringInfo(buf, "%*s", padding, strfbuf);
else
appendStringInfoString(buf, strfbuf);
}
break;
case 's':
if (formatted_start_time[0] == '\0')
setup_formatted_start_time();
appendStringInfoString(buf, formatted_start_time);
if (padding != 0)
appendStringInfo(buf, "%*s", padding, formatted_start_time);
else
appendStringInfoString(buf, formatted_start_time);
break;
case 'i':
if (MyProcPort)
@ -2235,43 +2338,105 @@ log_line_prefix(StringInfo buf, ErrorData *edata)
int displen;
psdisp = get_ps_display(&displen);
appendBinaryStringInfo(buf, psdisp, displen);
if (padding != 0)
appendStringInfo(buf, "%*s", padding, psdisp);
else
appendBinaryStringInfo(buf, psdisp, displen);
}
else if (padding != 0)
appendStringInfoSpaces(buf,
padding > 0 ? padding : -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 (padding != 0)
{
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
{
/* padding is 0, so we don't need a temp buffer */
appendStringInfoString(buf, MyProcPort->remote_host);
if (MyProcPort->remote_port &&
MyProcPort->remote_port[0] != '\0')
appendStringInfo(buf, "(%s)",
MyProcPort->remote_port);
}
}
else if (padding != 0)
appendStringInfoSpaces(buf,
padding > 0 ? padding : -padding);
break;
case 'h':
if (MyProcPort && MyProcPort->remote_host)
appendStringInfoString(buf, MyProcPort->remote_host);
if (MyProcPort && MyProcPort->remote_host)
{
if (padding != 0)
appendStringInfo(buf, "%*s", padding, MyProcPort->remote_host);
else
appendStringInfoString(buf, MyProcPort->remote_host);
}
else if (padding != 0)
appendStringInfoSpaces(buf,
padding > 0 ? padding : -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);
{
if (padding != 0)
{
char strfbuf[128];
snprintf(strfbuf, sizeof(strfbuf) - 1, "%d/%u",
MyProc->backendId, MyProc->lxid);
appendStringInfo(buf, "%*s", padding, strfbuf);
}
else
appendStringInfo(buf, "%d/%u", MyProc->backendId, MyProc->lxid);
}
else if (padding != 0)
appendStringInfoSpaces(buf,
padding > 0 ? padding : -padding);
break;
case 'x':
appendStringInfo(buf, "%u", GetTopTransactionIdIfAny());
if (padding != 0)
appendStringInfo(buf, "%*u", padding, GetTopTransactionIdIfAny());
else
appendStringInfo(buf, "%u", GetTopTransactionIdIfAny());
break;
case 'e':
appendStringInfoString(buf, unpack_sql_state(edata->sqlerrcode));
break;
case '%':
appendStringInfoChar(buf, '%');
if (padding != 0)
appendStringInfo(buf, "%*s", padding, unpack_sql_state(edata->sqlerrcode));
else
appendStringInfoString(buf, unpack_sql_state(edata->sqlerrcode));
break;
default:
/* format error - ignore it */