Index: doc/src/sgml/runtime.sgml
===================================================================
RCS file: /cvsroot/pgsql-server/doc/src/sgml/runtime.sgml,v
retrieving revision 1.245
diff -c -c -r1.245 runtime.sgml
*** doc/src/sgml/runtime.sgml	7 Mar 2004 01:02:55 -0000	1.245
--- doc/src/sgml/runtime.sgml	9 Mar 2004 04:33:24 -0000
***************
*** 1973,1978 ****
--- 1973,2070 ----
       
       
       
+       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)
        
         
Index: src/backend/postmaster/postmaster.c
===================================================================
RCS file: /cvsroot/pgsql-server/src/backend/postmaster/postmaster.c,v
retrieving revision 1.370
diff -c -c -r1.370 postmaster.c
*** src/backend/postmaster/postmaster.c	5 Mar 2004 01:11:04 -0000	1.370
--- src/backend/postmaster/postmaster.c	9 Mar 2004 04:33:28 -0000
***************
*** 2437,2442 ****
--- 2437,2443 ----
  	/* 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,2495 ****
  		/* modify remote_host for use in ps status */
  		char		tmphost[NI_MAXHOST];
  
! 		snprintf(tmphost, sizeof(tmphost), "%s:%s", remote_host, remote_port);
  		StrNCpy(remote_host, tmphost, sizeof(remote_host));
  	}
  
--- 2490,2496 ----
  		/* modify remote_host for use in ps status */
  		char		tmphost[NI_MAXHOST];
  
! 		snprintf(tmphost, sizeof(tmphost), "%s(%s)", remote_host, remote_port);
  		StrNCpy(remote_host, tmphost, sizeof(remote_host));
  	}
  
Index: src/backend/tcop/postgres.c
===================================================================
RCS file: /cvsroot/pgsql-server/src/backend/tcop/postgres.c,v
retrieving revision 1.393
diff -c -c -r1.393 postgres.c
*** src/backend/tcop/postgres.c	21 Feb 2004 06:29:58 -0000	1.393
--- src/backend/tcop/postgres.c	9 Mar 2004 04:33:30 -0000
***************
*** 3198,3204 ****
  static void 
  log_disconnections(int code, Datum arg)
  {
! 	Port * port = MyProcPort;
  	struct timeval end;
  	int  hours, minutes, seconds;
  
--- 3198,3204 ----
  static void 
  log_disconnections(int code, Datum arg)
  {
! 	Port *port = MyProcPort;
  	struct timeval end;
  	int  hours, minutes, seconds;
  
Index: src/backend/utils/error/elog.c
===================================================================
RCS file: /cvsroot/pgsql-server/src/backend/utils/error/elog.c,v
retrieving revision 1.126
diff -c -c -r1.126 elog.c
*** src/backend/utils/error/elog.c	29 Nov 2003 19:52:01 -0000	1.126
--- src/backend/utils/error/elog.c	9 Mar 2004 04:33:31 -0000
***************
*** 72,77 ****
--- 72,78 ----
  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,152 ****
  static const char *print_timestamp(void);
  static const char *print_pid(void);
  static void append_with_tabs(StringInfo buf, const char *str);
! 
  
  /*
   * errstart --- begin an error-reporting cycle
--- 147,153 ----
  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,1027 ****
--- 1023,1160 ----
  }
  #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,1039 ****
  
  	initStringInfo(&buf);
  
! 	appendStringInfo(&buf, "%s:  ", error_severity(edata->elevel));
  
  	if (Log_error_verbosity >= PGERROR_VERBOSE)
  	{
--- 1166,1173 ----
  
  	initStringInfo(&buf);
  
! 	appendStringInfo(&buf, "%s%s:  ", 
! 					 log_line_prefix(), error_severity(edata->elevel));
  
  	if (Log_error_verbosity >= PGERROR_VERBOSE)
  	{
***************
*** 1066,1083 ****
--- 1200,1220 ----
  	{
  		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,1096 ****
  		{
  			/* assume no newlines in funcname or filename... */
  			if (edata->funcname && edata->filename)
! 				appendStringInfo(&buf, gettext("LOCATION:  %s, %s:%d\n"),
  								 edata->funcname, edata->filename,
  								 edata->lineno);
  			else if (edata->filename)
! 				appendStringInfo(&buf, gettext("LOCATION:  %s:%d\n"),
  								 edata->filename, edata->lineno);
  		}
  	}
--- 1223,1235 ----
  		{
  			/* assume no newlines in funcname or filename... */
  			if (edata->funcname && edata->filename)
! 				appendStringInfo(&buf, gettext("%sLOCATION:  %s, %s:%d\n"),
! 								 log_line_prefix(),
  								 edata->funcname, edata->filename,
  								 edata->lineno);
  			else if (edata->filename)
! 				appendStringInfo(&buf, gettext("%sLOCATION:  %s:%d\n"),
! 								 log_line_prefix(),
  								 edata->filename, edata->lineno);
  		}
  	}
***************
*** 1100,1105 ****
--- 1239,1245 ----
  	 */
  	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');
Index: src/backend/utils/misc/guc.c
===================================================================
RCS file: /cvsroot/pgsql-server/src/backend/utils/misc/guc.c,v
retrieving revision 1.188
diff -c -c -r1.188 guc.c
*** src/backend/utils/misc/guc.c	23 Feb 2004 20:45:59 -0000	1.188
--- src/backend/utils/misc/guc.c	9 Mar 2004 04:33:35 -0000
***************
*** 1496,1501 ****
--- 1496,1511 ----
  	},
  
  	{
+ 		{"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."),
  			gettext_noop("Also controls interpretation of ambiguous "
Index: src/backend/utils/misc/postgresql.conf.sample
===================================================================
RCS file: /cvsroot/pgsql-server/src/backend/utils/misc/postgresql.conf.sample,v
retrieving revision 1.106
diff -c -c -r1.106 postgresql.conf.sample
*** src/backend/utils/misc/postgresql.conf.sample	17 Feb 2004 03:54:57 -0000	1.106
--- src/backend/utils/misc/postgresql.conf.sample	9 Mar 2004 04:33:35 -0000
***************
*** 185,190 ****
--- 185,198 ----
  #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
Index: src/backend/utils/misc/ps_status.c
===================================================================
RCS file: /cvsroot/pgsql-server/src/backend/utils/misc/ps_status.c,v
retrieving revision 1.17
diff -c -c -r1.17 ps_status.c
*** src/backend/utils/misc/ps_status.c	22 Feb 2004 21:26:55 -0000	1.17
--- src/backend/utils/misc/ps_status.c	9 Mar 2004 04:33:35 -0000
***************
*** 26,31 ****
--- 26,32 ----
  #include 
  #endif
  
+ #include "libpq/libpq.h"
  #include "miscadmin.h"
  #include "utils/ps_status.h"
  
***************
*** 276,285 ****
  void
  set_ps_display(const char *activity)
  {
- #ifndef PS_USE_NONE
  	/* no ps display for stand-alone backend */
  	if (!IsUnderPostmaster)
  		return;
  
  #ifdef PS_USE_CLOBBER_ARGV
  	/* If ps_buffer is a pointer, it might still be null */
--- 277,291 ----
  void
  set_ps_display(const char *activity)
  {
  	/* 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 */
Index: src/include/libpq/libpq-be.h
===================================================================
RCS file: /cvsroot/pgsql-server/src/include/libpq/libpq-be.h,v
retrieving revision 1.41
diff -c -c -r1.41 libpq-be.h
*** src/include/libpq/libpq-be.h	21 Feb 2004 06:29:58 -0000	1.41
--- src/include/libpq/libpq-be.h	9 Mar 2004 04:33:36 -0000
***************
*** 50,55 ****
--- 50,56 ----
  	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 */
  
Index: src/include/utils/elog.h
===================================================================
RCS file: /cvsroot/pgsql-server/src/include/utils/elog.h,v
retrieving revision 1.64
diff -c -c -r1.64 elog.h
*** src/include/utils/elog.h	29 Nov 2003 22:41:15 -0000	1.64
--- src/include/utils/elog.h	9 Mar 2004 04:33:36 -0000
***************
*** 171,176 ****
--- 171,177 ----
  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;