* Robert Haas (robertmh...@gmail.com) wrote:
> Ah, so it does.  Sounds like you win.  Have we a patch implementing
> the sounds-like-its-agreed change, then?

Patch attached, rebased to current master.  Full git log:

        Thanks,

                Stephen

commit 47eebe20deb5da56ea6eb413ee80110887790440
Author: Stephen Frost <sfr...@snowman.net>
Date:   Wed Feb 16 21:42:14 2011 -0500

    Add current role to csvlog output
    
    This patch adds the current role to the csvlog output.  It also slightly
    changes the user_name column to return the session user, if it's been
    changed from the login user, instead of the original login user.
    This is only possible through SET SESSION AUTHORIZATION, which is only
    allowed for superusers.  These changes allow a clear view of what
    privileges commands are being run as.

commit 7456d4fc98e6207b562dd0325dc09bbb1c915ae9
Merge: c1b06c0 9301698
Author: Stephen Frost <sfr...@snowman.net>
Date:   Wed Feb 16 21:03:59 2011 -0500

    Merge branch 'master' of git://git.postgresql.org/git/postgresql into 
log_role_basic

commit c1b06c04af0c886c6ec27917368f3c674227ed2d
Author: Stephen Frost <sfr...@snowman.net>
Date:   Tue Feb 15 10:21:38 2011 -0500

    Add %U option to log_line_prefix
    
    This patch adds a %U option to log_line_prefix, to allow logging
    of the current role (previously not possible).  Also reworks %u
    a bit and adds documentation to clarify what each means.
*** a/doc/src/sgml/config.sgml
--- b/doc/src/sgml/config.sgml
***************
*** 3562,3568 **** local0.*    /var/log/postgresql
              </row>
              <row>
               <entry><literal>%u</literal></entry>
!              <entry>User name</entry>
               <entry>yes</entry>
              </row>
              <row>
--- 3562,3581 ----
              </row>
              <row>
               <entry><literal>%u</literal></entry>
!              <entry>Session user name, typically the user name which was used
!              to authenticate to <productname>PostgreSQL</productname> with,
!              but can be changed by a superuser, see <command>SET SESSION
!              AUTHORIZATION</></entry>
!              <entry>yes</entry>
!             </row>
!             <row>
!              <entry><literal>%U</literal></entry>
!              <entry>Current role name, when set with <command>SET ROLE</>;
!              the current role identifier is relevant for permission checking;
!              Returns 'none' if the current role matches the session user.
!              Note: Log messages from inside <literal>SECURITY DEFINER</>
!              functions will show the calling role, not the effective role
!              inside the <literal>SECURITY DEFINER</> function</entry>
               <entry>yes</entry>
              </row>
              <row>
***************
*** 3790,3795 **** FROM pg_stat_activity;
--- 3803,3809 ----
          with these columns:
          timestamp with milliseconds,
          user name,
+         current role name,
          database name,
          process ID,
          client host:port number,
***************
*** 3820,3825 **** CREATE TABLE postgres_log
--- 3834,3840 ----
  (
    log_time timestamp(3) with time zone,
    user_name text,
+   curr_role text,
    database_name text,
    process_id integer,
    connection_from text,
*** a/src/backend/commands/variable.c
--- b/src/backend/commands/variable.c
***************
*** 847,852 **** assign_session_authorization(const char *value, bool doit, GucSource source)
--- 847,857 ----
  	return result;
  }
  
+ /*
+  * function to return the stored session username, needed because we
+  * can't do catalog lookups when possibly being called after an error,
+  * eg: from elog.c or part of GUC handling.
+  */
  const char *
  show_session_authorization(void)
  {
***************
*** 972,977 **** assign_role(const char *value, bool doit, GucSource source)
--- 977,987 ----
  	return result;
  }
  
+ /*
+  * function to return the stored role username, needed because we
+  * can't do catalog lookups when possibly being called after an error,
+  * eg: from elog.c or part of GUC handling.
+  */
  const char *
  show_role(void)
  {
*** a/src/backend/utils/error/elog.c
--- b/src/backend/utils/error/elog.c
***************
*** 3,8 ****
--- 3,17 ----
   * elog.c
   *	  error logging and reporting
   *
+  * A few comments about situations where error processing is called:
+  *
+  * We need to be cautious of both a performance hit when logging, since
+  * log messages can be generated at a huge rate if every command is being
+  * logged and we also need to watch out for what can happen when we are
+  * trying to log from an aborted transaction.  Specifically, attempting to
+  * do SysCache lookups and possibly use other usually available backend
+  * systems will fail badly when logging from an aborted transaction.
+  *
   * Some notes about recursion and errors during error processing:
   *
   * We need to be robust about recursive-error scenarios --- for example,
***************
*** 59,64 ****
--- 68,74 ----
  
  #include "access/transam.h"
  #include "access/xact.h"
+ #include "commands/variable.h"
  #include "libpq/libpq.h"
  #include "libpq/pqformat.h"
  #include "mb/pg_wchar.h"
***************
*** 1817,1831 **** log_line_prefix(StringInfo buf, ErrorData *edata)
  				}
  				break;
  			case 'u':
- 				if (MyProcPort)
  				{
! 					const char *username = MyProcPort->user_name;
! 
! 					if (username == NULL || *username == '\0')
! 						username = _("[unknown]");
! 					appendStringInfoString(buf, username);
  				}
  				break;
  			case 'd':
  				if (MyProcPort)
  				{
--- 1827,1854 ----
  				}
  				break;
  			case 'u':
  				{
! 					const char *session_auth = show_session_authorization();
! 
! 					/*
! 					 * If show_session_authorization() just returns an empty
! 					 * string, then use user_name from MyProcPort
! 					 */
! 					if (*session_auth != '\0')
! 						appendStringInfoString(buf, session_auth);
! 					else if (MyProcPort)
! 					{
! 						const char *username = MyProcPort->user_name;
! 
! 						if (username == NULL || *username == '\0')
! 							username = _("[unknown]");
! 						appendStringInfoString(buf, username);
! 					}
  				}
  				break;
+ 			case 'U':
+ 				appendStringInfoString(buf, show_role());
+ 				break;
  			case 'd':
  				if (MyProcPort)
  				{
***************
*** 1961,1966 **** write_csvlog(ErrorData *edata)
--- 1984,1992 ----
  	/* has counter been reset in current process? */
  	static int	log_my_pid = 0;
  
+ 	/* pull the session authorization */
+ 	const char *session_auth = show_session_authorization();
+ 
  	/*
  	 * This is one of the few places where we'd rather not inherit a static
  	 * variable's value from the postmaster.  But since we will, reset it when
***************
*** 1989,1999 **** write_csvlog(ErrorData *edata)
  	appendStringInfoString(&buf, formatted_log_time);
  	appendStringInfoChar(&buf, ',');
  
! 	/* username */
! 	if (MyProcPort)
  		appendCSVLiteral(&buf, MyProcPort->user_name);
  	appendStringInfoChar(&buf, ',');
  
  	/* database name */
  	if (MyProcPort)
  		appendCSVLiteral(&buf, MyProcPort->database_name);
--- 2015,2036 ----
  	appendStringInfoString(&buf, formatted_log_time);
  	appendStringInfoChar(&buf, ',');
  
! 	/*
! 	 * session username, as %u from log_line_prefix
! 	 *
! 	 * If show_session_authorization() returned an empty
! 	 * string, then use user_name from MyProcPort
! 	 */
! 	if (*session_auth != '\0')
! 		appendCSVLiteral(&buf, session_auth);
! 	else if (MyProcPort)
  		appendCSVLiteral(&buf, MyProcPort->user_name);
  	appendStringInfoChar(&buf, ',');
  
+ 	/* current role name, matches %U in log_line_prefix */
+ 	appendStringInfoString(&buf, show_role());
+ 	appendStringInfoChar(&buf, ',');
+ 
  	/* database name */
  	if (MyProcPort)
  		appendCSVLiteral(&buf, MyProcPort->database_name);
*** a/src/backend/utils/misc/postgresql.conf.sample
--- b/src/backend/utils/misc/postgresql.conf.sample
***************
*** 361,367 ****
  #log_hostname = off
  #log_line_prefix = ''			# special values:
  					#   %a = application name
! 					#   %u = user name
  					#   %d = database name
  					#   %r = remote host and port
  					#   %h = remote host
--- 361,368 ----
  #log_hostname = off
  #log_line_prefix = ''			# special values:
  					#   %a = application name
! 					#   %u = session user name
! 					#   %U = current role name
  					#   %d = database name
  					#   %r = remote host and port
  					#   %h = remote host

Attachment: signature.asc
Description: Digital signature

Reply via email to