Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 2f6f7d1

Browse files
melanieplagemanCommitfest Bot
authored and
Commitfest Bot
committed
Modularize log_connections output
Convert the boolean log_connections GUC into a list GUC comprised of the connection aspects to log. This gives users more control over the volume and kind of connection logging. The current log_connections options are 'receipt', 'authentication', and 'authorization'. The empty string disables all connection logging. 'all' enables all available connection logging. For backwards compatibility, the most common values for the log_connections boolean are still supported (on, off, 1, 0, true, false, yes, no). Author: Melanie Plageman <melanieplageman@gmail.com> Reviewed-by: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Fujii Masao <masao.fujii@oss.nttdata.com> Reviewed-by: Daniel Gustafsson <daniel@yesql.se> Discussion: https://postgr.es/m/flat/CAAKRu_b_smAHK0ZjrnL5GRxnAVWujEXQWpLXYzGbmpcZd3nLYw%40mail.gmail.com
1 parent 043745c commit 2f6f7d1

File tree

12 files changed

+326
-25
lines changed

12 files changed

+326
-25
lines changed

doc/src/sgml/config.sgml

Lines changed: 72 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7315,20 +7315,87 @@ local0.* /var/log/postgresql
73157315
</varlistentry>
73167316

73177317
<varlistentry id="guc-log-connections" xreflabel="log_connections">
7318-
<term><varname>log_connections</varname> (<type>boolean</type>)
7318+
<term><varname>log_connections</varname> (<type>string</type>)
73197319
<indexterm>
73207320
<primary><varname>log_connections</varname> configuration parameter</primary>
73217321
</indexterm>
73227322
</term>
73237323
<listitem>
73247324
<para>
7325-
Causes each attempted connection to the server to be logged,
7326-
as well as successful completion of both client authentication (if
7327-
necessary) and authorization.
7325+
Causes aspects of each connection attempt to the server to be
7326+
logged. The default is the empty string, <literal>''</literal>,
7327+
which disables all connection logging. The following options may
7328+
be specified alone or in a comma-separated list:
7329+
</para>
7330+
7331+
<table id="log-connections-options">
7332+
<title>Log Connection Options</title>
7333+
<tgroup cols="2">
7334+
<colspec colname="col1" colwidth="1*"/>
7335+
<colspec colname="col2" colwidth="2*"/>
7336+
<thead>
7337+
<row>
7338+
<entry>Name</entry>
7339+
<entry>Description</entry>
7340+
</row>
7341+
</thead>
7342+
<tbody>
7343+
<row>
7344+
<entry><literal>receipt</literal></entry>
7345+
<entry>Logs receipt of a connection.</entry>
7346+
</row>
7347+
7348+
<row>
7349+
<entry><literal>authentication</literal></entry>
7350+
<entry>
7351+
Logs the original identity used by an authentication method
7352+
to identify a user. In most cases, the identity string
7353+
matches the PostgreSQL username, but some third-party
7354+
authentication methods may alter the original user
7355+
identifier before the server stores it. Failed
7356+
authentication is always logged regardless of the value of
7357+
this setting.
7358+
</entry>
7359+
</row>
7360+
7361+
<row>
7362+
<entry><literal>authorization</literal></entry>
7363+
<entry>
7364+
Logs successful completion of authorization. At this point
7365+
the connection has been established but the backend is not
7366+
yet fully set up. The log message includes the authorized
7367+
username as well as the database name and application name,
7368+
if applicable.
7369+
</entry>
7370+
</row>
7371+
7372+
<row>
7373+
<entry><literal>all</literal></entry>
7374+
<entry>
7375+
A convenience alias equivalent to specifying all options. If
7376+
<literal>all</literal> is specified in a list of other
7377+
options, all connection aspects will be logged.
7378+
</entry>
7379+
</row>
7380+
7381+
</tbody>
7382+
</tgroup>
7383+
</table>
7384+
7385+
<para>
7386+
For the purposes of backwards compatibility, <literal>on</literal>,
7387+
<literal>off</literal>, <literal>true</literal>,
7388+
<literal>false</literal>, <literal>yes</literal>,
7389+
<literal>no</literal>, <literal>1</literal>, and <literal>0</literal>
7390+
are still supported. The positive values are equivalent to specifying
7391+
the <literal>receipt</literal>, <literal>authentication</literal>, and
7392+
<literal>authorization</literal> options.
7393+
</para>
7394+
7395+
<para>
73287396
Only superusers and users with the appropriate <literal>SET</literal>
73297397
privilege can change this parameter at session start,
73307398
and it cannot be changed at all within a session.
7331-
The default is <literal>off</literal>.
73327399
</para>
73337400

73347401
<note>

src/backend/libpq/auth.c

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
#include "postmaster/postmaster.h"
3939
#include "replication/walsender.h"
4040
#include "storage/ipc.h"
41+
#include "tcop/backend_startup.h"
4142
#include "utils/memutils.h"
4243

4344
/*----------------------------------------------------------------
@@ -317,7 +318,8 @@ auth_failed(Port *port, int status, const char *logdetail)
317318
/*
318319
* Sets the authenticated identity for the current user. The provided string
319320
* will be stored into MyClientConnectionInfo, alongside the current HBA
320-
* method in use. The ID will be logged if log_connections is enabled.
321+
* method in use. The ID will be logged if log_connections has the
322+
* 'authentication' option specified.
321323
*
322324
* Auth methods should call this routine exactly once, as soon as the user is
323325
* successfully authenticated, even if they have reasons to know that
@@ -349,7 +351,7 @@ set_authn_id(Port *port, const char *id)
349351
MyClientConnectionInfo.authn_id = MemoryContextStrdup(TopMemoryContext, id);
350352
MyClientConnectionInfo.auth_method = port->hba->auth_method;
351353

352-
if (Log_connections)
354+
if (log_connections & LOG_CONNECTION_AUTHENTICATION)
353355
{
354356
ereport(LOG,
355357
errmsg("connection authenticated: identity=\"%s\" method=%s "
@@ -633,7 +635,8 @@ ClientAuthentication(Port *port)
633635
#endif
634636
}
635637

636-
if (Log_connections && status == STATUS_OK &&
638+
if ((log_connections & LOG_CONNECTION_AUTHENTICATION) &&
639+
status == STATUS_OK &&
637640
!MyClientConnectionInfo.authn_id)
638641
{
639642
/*

src/backend/postmaster/postmaster.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -237,7 +237,6 @@ int PreAuthDelay = 0;
237237
int AuthenticationTimeout = 60;
238238

239239
bool log_hostname; /* for ps display and logging */
240-
bool Log_connections = false;
241240

242241
bool enable_bonjour = false;
243242
char *bonjour_name;

src/backend/tcop/backend_startup.c

Lines changed: 159 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,20 +34,25 @@
3434
#include "tcop/backend_startup.h"
3535
#include "tcop/tcopprot.h"
3636
#include "utils/builtins.h"
37+
#include "utils/guc_hooks.h"
3738
#include "utils/injection_point.h"
3839
#include "utils/memutils.h"
3940
#include "utils/ps_status.h"
4041
#include "utils/timeout.h"
42+
#include "utils/varlena.h"
4143

4244
/* GUCs */
4345
bool Trace_connection_negotiation = false;
46+
uint32 log_connections = 0;
47+
char *log_connections_string = NULL;
4448

4549
static void BackendInitialize(ClientSocket *client_sock, CAC_state cac);
4650
static int ProcessSSLStartup(Port *port);
4751
static int ProcessStartupPacket(Port *port, bool ssl_done, bool gss_done);
4852
static void SendNegotiateProtocolVersion(List *unrecognized_protocol_options);
4953
static void process_startup_packet_die(SIGNAL_ARGS);
5054
static void StartupPacketTimeoutHandler(void);
55+
static bool validate_log_connections_options(List *elemlist, uint32 *flags);
5156

5257
/*
5358
* Entry point for a new backend process.
@@ -201,8 +206,8 @@ BackendInitialize(ClientSocket *client_sock, CAC_state cac)
201206
port->remote_host = MemoryContextStrdup(TopMemoryContext, remote_host);
202207
port->remote_port = MemoryContextStrdup(TopMemoryContext, remote_port);
203208

204-
/* And now we can issue the Log_connections message, if wanted */
205-
if (Log_connections)
209+
/* And now we can log that the connection was received, if enabled */
210+
if (log_connections & LOG_CONNECTION_RECEIPT)
206211
{
207212
if (remote_port[0])
208213
ereport(LOG,
@@ -924,3 +929,155 @@ StartupPacketTimeoutHandler(void)
924929
{
925930
_exit(1);
926931
}
932+
933+
/*
934+
* Helper for the log_connections GUC check hook.
935+
*
936+
* `elemlist` is a listified version of the string input passed to the
937+
* log_connections GUC check hook, check_log_connections().
938+
* check_log_connections() is responsible for cleaning up `elemlist`.
939+
*
940+
* validate_log_connections_options() returns false if an error was
941+
* encountered and the GUC input could not be validated and true otherwise.
942+
*
943+
* `flags` returns the flags that should be stored in the log_connections GUC
944+
* by its assign hook.
945+
*/
946+
static bool
947+
validate_log_connections_options(List *elemlist, uint32 *flags)
948+
{
949+
ListCell *l;
950+
char *item;
951+
952+
/*
953+
* For backwards compatibility, we accept these tokens by themselves.
954+
*
955+
* Prior to PostgreSQL 18, log_connections was a boolean GUC that accepted
956+
* any unambiguous substring of 'true', 'false', 'yes', 'no', 'on', and
957+
* 'off'. Since log_connections became a list of strings in 18, we only
958+
* accept complete option strings.
959+
*/
960+
static const struct config_enum_entry compat_options[] = {
961+
{"off", 0},
962+
{"false", 0},
963+
{"no", 0},
964+
{"0", 0},
965+
{"on", LOG_CONNECTION_ON},
966+
{"true", LOG_CONNECTION_ON},
967+
{"yes", LOG_CONNECTION_ON},
968+
{"1", LOG_CONNECTION_ON},
969+
};
970+
971+
*flags = 0;
972+
973+
/* If an empty string was passed, we're done */
974+
if (list_length(elemlist) == 0)
975+
return true;
976+
977+
/*
978+
* Now check for the backwards compatibility options. They must always be
979+
* specified on their own, so we error out if the first option is a
980+
* backwards compatibility option and other options are also specified.
981+
*/
982+
item = linitial(elemlist);
983+
984+
for (size_t i = 0; i < lengthof(compat_options); i++)
985+
{
986+
struct config_enum_entry option = compat_options[i];
987+
988+
if (pg_strcasecmp(item, option.name) != 0)
989+
continue;
990+
991+
if (list_length(elemlist) > 1)
992+
{
993+
GUC_check_errdetail("Cannot specify log_connections option \"%s\" in a list with other options.",
994+
item);
995+
return false;
996+
}
997+
998+
*flags = option.val;
999+
return true;
1000+
}
1001+
1002+
/* Now check the aspect options. The empty string was already handled */
1003+
foreach(l, elemlist)
1004+
{
1005+
static const struct config_enum_entry options[] = {
1006+
{"receipt", LOG_CONNECTION_RECEIPT},
1007+
{"authentication", LOG_CONNECTION_AUTHENTICATION},
1008+
{"authorization", LOG_CONNECTION_AUTHORIZATION},
1009+
{"all", LOG_CONNECTION_ALL},
1010+
};
1011+
1012+
item = lfirst(l);
1013+
for (size_t i = 0; i < lengthof(options); i++)
1014+
{
1015+
struct config_enum_entry option = options[i];
1016+
1017+
if (pg_strcasecmp(item, option.name) == 0)
1018+
{
1019+
*flags |= option.val;
1020+
goto next;
1021+
}
1022+
}
1023+
1024+
GUC_check_errdetail("Invalid option \"%s\".", item);
1025+
return false;
1026+
1027+
next: ;
1028+
}
1029+
1030+
return true;
1031+
}
1032+
1033+
1034+
/*
1035+
* GUC check hook for log_connections
1036+
*/
1037+
bool
1038+
check_log_connections(char **newval, void **extra, GucSource source)
1039+
{
1040+
uint32 flags;
1041+
char *rawstring;
1042+
List *elemlist;
1043+
bool success;
1044+
1045+
/* Need a modifiable copy of string */
1046+
rawstring = pstrdup(*newval);
1047+
1048+
if (!SplitIdentifierString(rawstring, ',', &elemlist))
1049+
{
1050+
GUC_check_errdetail("Invalid list syntax in parameter \"log_connections\".");
1051+
pfree(rawstring);
1052+
list_free(elemlist);
1053+
return false;
1054+
}
1055+
1056+
/* Validation logic is all in the helper */
1057+
success = validate_log_connections_options(elemlist, &flags);
1058+
1059+
/* Time for cleanup */
1060+
pfree(rawstring);
1061+
list_free(elemlist);
1062+
1063+
if (!success)
1064+
return false;
1065+
1066+
/*
1067+
* We succeeded, so allocate `extra` and save the flags there for use by
1068+
* assign_log_connections().
1069+
*/
1070+
*extra = guc_malloc(ERROR, sizeof(int));
1071+
*((int *) *extra) = flags;
1072+
1073+
return true;
1074+
}
1075+
1076+
/*
1077+
* GUC assign hook for log_connections
1078+
*/
1079+
void
1080+
assign_log_connections(const char *newval, void *extra)
1081+
{
1082+
log_connections = *((int *) extra);
1083+
}

src/backend/utils/init/postinit.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@
5454
#include "storage/sinvaladt.h"
5555
#include "storage/smgr.h"
5656
#include "storage/sync.h"
57+
#include "tcop/backend_startup.h"
5758
#include "tcop/tcopprot.h"
5859
#include "utils/acl.h"
5960
#include "utils/builtins.h"
@@ -252,7 +253,7 @@ PerformAuthentication(Port *port)
252253
*/
253254
disable_timeout(STATEMENT_TIMEOUT, false);
254255

255-
if (Log_connections)
256+
if (log_connections & LOG_CONNECTION_AUTHORIZATION)
256257
{
257258
StringInfoData logmsg;
258259

src/backend/utils/misc/guc_tables.c

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1219,15 +1219,6 @@ struct config_bool ConfigureNamesBool[] =
12191219
true,
12201220
NULL, NULL, NULL
12211221
},
1222-
{
1223-
{"log_connections", PGC_SU_BACKEND, LOGGING_WHAT,
1224-
gettext_noop("Logs each successful connection."),
1225-
NULL
1226-
},
1227-
&Log_connections,
1228-
false,
1229-
NULL, NULL, NULL
1230-
},
12311222
{
12321223
{"trace_connection_negotiation", PGC_POSTMASTER, DEVELOPER_OPTIONS,
12331224
gettext_noop("Logs details of pre-authentication connection handshake."),
@@ -4886,6 +4877,18 @@ struct config_string ConfigureNamesString[] =
48864877
NULL, NULL, NULL
48874878
},
48884879

4880+
{
4881+
{"log_connections", PGC_SU_BACKEND, LOGGING_WHAT,
4882+
gettext_noop("Logs specified aspects of connection establishment."),
4883+
NULL,
4884+
GUC_LIST_INPUT
4885+
},
4886+
&log_connections_string,
4887+
"",
4888+
check_log_connections, assign_log_connections, NULL
4889+
},
4890+
4891+
48894892
/* End-of-list marker */
48904893
{
48914894
{NULL, 0, 0, NULL, NULL}, NULL, NULL, NULL, NULL, NULL

0 commit comments

Comments
 (0)