diff --git a/doc/src/sgml/runtime.sgml b/doc/src/sgml/runtime.sgml index 5c67f70863..335a404f07 100644 --- a/doc/src/sgml/runtime.sgml +++ b/doc/src/sgml/runtime.sgml @@ -1,5 +1,5 @@ @@ -1972,6 +1972,98 @@ SET ENABLE_SEQSCAN TO OFF; + + log_line_prefix (string) + + + This is a printf-style string that is output at the + beginning of each log line. The default is an empty string. + Each recognized escape is replaced as outlined + below - anything else that looks like an escape is ignored. Other + characters are copied straight to the log line. Some escapes are + only recognised by session processes, and do not apply to + processes without controlling sessions. Syslog produces its own + timestamp and process ID information, so you probably do not want to + use those escapes if you are using syslog. + + + + + Escape + Effect + Session only + + + + + %u + User Name + Yes + + + %d + Database Name + Yes + + + %r + Remote Hostname or IP address, and Remote Port + Yes + + + %p + Process ID + No + + + %t + Timestamp + No + + + %i + Command Tag. This is the command which generated the log + line. + Yes + + + %c + Session ID. A unique identifier for each session. + It is 2 4-byte hexadecimal numbers separated by a dot. The numbers + are the Session Start Time and the Process ID, so this can also + be used as a space saving way of printing these items. + Yes + + + %l + Number of the log line for each process, + starting at 1 + No + + + %s + Session Start Timestamp + Yes + + + %x + Does not produce any output, but tells non-session + processes to stop at this point in the string. Ignored by + session backends. + No + + + %% + literal % + No + + + + + + + + log_pid (boolean) diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c index 3e35bf3939..9b4abc16eb 100644 --- a/src/backend/postmaster/postmaster.c +++ b/src/backend/postmaster/postmaster.c @@ -37,7 +37,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/postmaster/postmaster.c,v 1.370 2004/03/05 01:11:04 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/postmaster/postmaster.c,v 1.371 2004/03/09 04:43:06 momjian Exp $ * * NOTES * @@ -2437,6 +2437,7 @@ BackendInit(Port *port) /* set these to empty in case they are needed before we set them up */ port->remote_host = ""; port->remote_port = ""; + port->commandTag = ""; /* Save port etc. for ps status */ MyProcPort = port; @@ -2489,7 +2490,7 @@ BackendInit(Port *port) /* modify remote_host for use in ps status */ char tmphost[NI_MAXHOST]; - snprintf(tmphost, sizeof(tmphost), "%s:%s", remote_host, remote_port); + snprintf(tmphost, sizeof(tmphost), "%s(%s)", remote_host, remote_port); StrNCpy(remote_host, tmphost, sizeof(remote_host)); } diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index abb682686d..ef59e78fbd 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/tcop/postgres.c,v 1.393 2004/02/21 06:29:58 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/tcop/postgres.c,v 1.394 2004/03/09 04:43:07 momjian Exp $ * * NOTES * this is the "main" module of the postgres backend and @@ -3198,7 +3198,7 @@ ShowUsage(const char *title) static void log_disconnections(int code, Datum arg) { - Port * port = MyProcPort; + Port *port = MyProcPort; struct timeval end; int hours, minutes, seconds; diff --git a/src/backend/utils/error/elog.c b/src/backend/utils/error/elog.c index 22fcde31ed..d516d2d72e 100644 --- a/src/backend/utils/error/elog.c +++ b/src/backend/utils/error/elog.c @@ -37,7 +37,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/error/elog.c,v 1.126 2003/11/29 19:52:01 pgsql Exp $ + * $PostgreSQL: pgsql/src/backend/utils/error/elog.c,v 1.127 2004/03/09 04:43:07 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -72,6 +72,7 @@ PGErrorVerbosity Log_error_verbosity = PGERROR_VERBOSE; bool Log_timestamp = false; /* show timestamps in stderr * output */ bool Log_pid = false; /* show PIDs in stderr output */ +char *Log_line_prefix = ""; /* format for extra log line info */ #ifdef HAVE_SYSLOG /* @@ -146,7 +147,7 @@ static const char *error_severity(int elevel); static const char *print_timestamp(void); static const char *print_pid(void); static void append_with_tabs(StringInfo buf, const char *str); - +static const char *log_line_prefix(void); /* * errstart --- begin an error-reporting cycle @@ -1022,6 +1023,138 @@ write_syslog(int level, const char *line) } #endif /* HAVE_SYSLOG */ +/* + * Format tag info for log lines + */ +static const char * +log_line_prefix(void) +{ + + /* static accumulator for line numbers */ + static int log_line_number = 0; + + /* space for option string + one of each option, plus some room to spare */ + /* Note: if more identifiers are built in this will have to increase */ + static char *result = NULL; + int format_len = strlen(Log_line_prefix); + int result_len = 2*NAMEDATALEN + format_len +120 ; + + if (result == NULL) + result = malloc(result_len); + result[0] = '\0'; + + if (format_len > 0) + { + int i,j; + char * dbname = NULL; + char * username = NULL; + time_t stamp_time; + log_line_number++; + if (MyProcPort != NULL) + { + dbname = MyProcPort->database_name; + username = MyProcPort->user_name; + if (dbname == NULL || *dbname == '\0') + dbname = gettext("[unknown]"); + if (username == NULL || *username == '\0') + username = gettext("[unknown]"); + } + + /* + * invariant through each iteration of this loop: + * . j is the index of the trailing null on result + * . result_len - j is the number of chars we have room for + * including the trailing null + * . there is room to write at least one more non-null char plus the + * trailing null + */ + for (i = 0, j=0; i < format_len && j < result_len-1; i++) + { + if(Log_line_prefix[i] != '%') + { + /* literal char, just copy */ + result[j]=Log_line_prefix[i]; + j++; + result[j] = '\0'; + continue; + } + else if (i == format_len - 1) + { + /* format error - skip it */ + continue; + } + + /* go to char after '%' */ + i++; + + /* in postmaster and friends, skip non-applicable options, + * stop if %x is seen + */ + if (MyProcPort == NULL) + { + if (Log_line_prefix[i] == 'x') + break; + if (strchr("udcsir",Log_line_prefix[i]) != NULL) + continue; + } + + /* process the option */ + switch (Log_line_prefix[i]) + { + case 'u': + j += snprintf(result+j,result_len-j,"%s",username); + break; + case 'd': + j += snprintf(result+j,result_len-j,"%s",dbname); + break; + case 'c': + j += snprintf(result+j,result_len-j,"%lx.%lx", + (long)(MyProcPort->session_start.tv_sec), + (long)MyProcPid); + break; + case 'p': + j += snprintf(result+j,result_len-j,"%ld",(long)MyProcPid); + break; + case 'l': + j += snprintf(result+j,result_len-j,"%d",log_line_number); + break; + case 't': + stamp_time = time(NULL); + j += strftime(result+j, result_len-j, "%Y-%m-%d %H:%M:%S", + localtime(&stamp_time)); + break; + case 's': + j += strftime(result+j, result_len-j, "%Y-%m-%d %H:%M:%S", + localtime(&(MyProcPort->session_start.tv_sec))); + break; + case 'i': + j += snprintf(result+j,result_len-j,"%s", + MyProcPort->commandTag); + break; + case 'r': + j += snprintf(result+j,result_len-j,"%s", + MyProcPort->remote_host); + if (!LogSourcePort && strlen(MyProcPort->remote_port)) + j += snprintf(result+j,result_len-j,"(%s)", + MyProcPort->remote_port); + break; + case 'x': + /* non-postmaster case - just ignore */ + break; + case '%': + result[j] = '%'; + j++; + result[j] = '\0'; + break; + default: + /* format error - skip it */ + break; + } + } + } + return result; +} + /* * Write error report to server's log @@ -1033,7 +1166,8 @@ send_message_to_server_log(ErrorData *edata) initStringInfo(&buf); - appendStringInfo(&buf, "%s: ", error_severity(edata->elevel)); + appendStringInfo(&buf, "%s%s: ", + log_line_prefix(), error_severity(edata->elevel)); if (Log_error_verbosity >= PGERROR_VERBOSE) { @@ -1066,18 +1200,21 @@ send_message_to_server_log(ErrorData *edata) { if (edata->detail) { + appendStringInfoString(&buf, log_line_prefix() ); appendStringInfoString(&buf, gettext("DETAIL: ")); append_with_tabs(&buf, edata->detail); appendStringInfoChar(&buf, '\n'); } if (edata->hint) { + appendStringInfoString(&buf, log_line_prefix() ); appendStringInfoString(&buf, gettext("HINT: ")); append_with_tabs(&buf, edata->hint); appendStringInfoChar(&buf, '\n'); } if (edata->context) { + appendStringInfoString(&buf, log_line_prefix() ); appendStringInfoString(&buf, gettext("CONTEXT: ")); append_with_tabs(&buf, edata->context); appendStringInfoChar(&buf, '\n'); @@ -1086,11 +1223,13 @@ send_message_to_server_log(ErrorData *edata) { /* assume no newlines in funcname or filename... */ if (edata->funcname && edata->filename) - appendStringInfo(&buf, gettext("LOCATION: %s, %s:%d\n"), + appendStringInfo(&buf, gettext("%sLOCATION: %s, %s:%d\n"), + log_line_prefix(), edata->funcname, edata->filename, edata->lineno); else if (edata->filename) - appendStringInfo(&buf, gettext("LOCATION: %s:%d\n"), + appendStringInfo(&buf, gettext("%sLOCATION: %s:%d\n"), + log_line_prefix(), edata->filename, edata->lineno); } } @@ -1100,6 +1239,7 @@ send_message_to_server_log(ErrorData *edata) */ if (edata->elevel >= log_min_error_statement && debug_query_string != NULL) { + appendStringInfoString(&buf, log_line_prefix() ); appendStringInfoString(&buf, gettext("STATEMENT: ")); append_with_tabs(&buf, debug_query_string); appendStringInfoChar(&buf, '\n'); diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 85931e3ca8..e8a28aaa44 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -10,7 +10,7 @@ * Written by Peter Eisentraut . * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.188 2004/02/23 20:45:59 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.189 2004/03/09 04:43:07 momjian Exp $ * *-------------------------------------------------------------------- */ @@ -1495,6 +1495,16 @@ static struct config_string ConfigureNamesString[] = "panic", assign_min_error_statement, NULL }, + { + {"log_line_prefix", PGC_SIGHUP, LOGGING_WHAT, + gettext_noop("Controls information prefixed to each log line"), + gettext_noop("if blank no prefix is used") + }, + &Log_line_prefix, + "", NULL, NULL + }, + + { {"DateStyle", PGC_USERSET, CLIENT_CONN_LOCALE, gettext_noop("Sets the display format for date and time values."), diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample index 3d58e9783f..8830f822bc 100644 --- a/src/backend/utils/misc/postgresql.conf.sample +++ b/src/backend/utils/misc/postgresql.conf.sample @@ -185,6 +185,14 @@ #log_disconnections = false #log_duration = false #log_pid = false +#log_line_prefix = '' # e.g. '<%u%%%d> ' + # %u=user name %d=database name + # %r=remote host and port + # %p=PID %t=timestamp %i=command tag + # %c=session id %l=session line number + # %s=session start timestamp + # %x=stop here in non-session processes + # %%='%' #log_statement = false #log_timestamp = false #log_hostname = false diff --git a/src/backend/utils/misc/ps_status.c b/src/backend/utils/misc/ps_status.c index fcd236d001..770882cc8e 100644 --- a/src/backend/utils/misc/ps_status.c +++ b/src/backend/utils/misc/ps_status.c @@ -5,7 +5,7 @@ * to contain some useful information. Mechanism differs wildly across * platforms. * - * $PostgreSQL: pgsql/src/backend/utils/misc/ps_status.c,v 1.17 2004/02/22 21:26:55 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/utils/misc/ps_status.c,v 1.18 2004/03/09 04:43:07 momjian Exp $ * * Copyright (c) 2000-2003, PostgreSQL Global Development Group * various details abducted from various places @@ -26,6 +26,7 @@ #include #endif +#include "libpq/libpq.h" #include "miscadmin.h" #include "utils/ps_status.h" @@ -276,11 +277,16 @@ init_ps_display(const char *username, const char *dbname, void set_ps_display(const char *activity) { -#ifndef PS_USE_NONE /* no ps display for stand-alone backend */ if (!IsUnderPostmaster) return; + /* save it for logging context */ + if (MyProcPort) + MyProcPort->commandTag = (char *) activity; + +#ifndef PS_USE_NONE + #ifdef PS_USE_CLOBBER_ARGV /* If ps_buffer is a pointer, it might still be null */ if (!ps_buffer) diff --git a/src/include/libpq/libpq-be.h b/src/include/libpq/libpq-be.h index 9c6a474d7f..a077913a11 100644 --- a/src/include/libpq/libpq-be.h +++ b/src/include/libpq/libpq-be.h @@ -11,7 +11,7 @@ * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/libpq/libpq-be.h,v 1.41 2004/02/21 06:29:58 tgl Exp $ + * $PostgreSQL: pgsql/src/include/libpq/libpq-be.h,v 1.42 2004/03/09 04:43:07 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -50,6 +50,7 @@ typedef struct Port SockAddr raddr; /* remote addr (client) */ char *remote_host; /* name (or ip addr) of remote host */ char *remote_port; /* text rep of remote port */ + char *commandTag; /* command tag for display in log lines */ struct timeval session_start; /* for session duration logging */ CAC_state canAcceptConnections; /* postmaster connection status */ diff --git a/src/include/utils/elog.h b/src/include/utils/elog.h index 5b626fab0c..4a7629e90d 100644 --- a/src/include/utils/elog.h +++ b/src/include/utils/elog.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/utils/elog.h,v 1.64 2003/11/29 22:41:15 pgsql Exp $ + * $PostgreSQL: pgsql/src/include/utils/elog.h,v 1.65 2004/03/09 04:43:07 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -171,6 +171,7 @@ typedef enum extern PGErrorVerbosity Log_error_verbosity; extern bool Log_timestamp; extern bool Log_pid; +extern char *Log_line_prefix; #ifdef HAVE_SYSLOG extern int Use_syslog;