} 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);
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.
*/
/* 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
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)
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)
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)
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':
{
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)
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 */