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

Commit 9219093

Browse files
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). Note that previously supported substrings of on, off, true, false, yes, and no are no longer supported. 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 f554a95 commit 9219093

File tree

12 files changed

+331
-25
lines changed

12 files changed

+331
-25
lines changed

doc/src/sgml/config.sgml

+77-5
Original file line numberDiff line numberDiff line change
@@ -7315,20 +7315,92 @@ 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 to the server to be logged.
7326+
The default is the empty string, <literal>''</literal>, which
7327+
disables all connection logging. The following options may be
7328+
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 <productname>PostgreSQL</productname> username,
7354+
but some third-party authentication methods may alter the
7355+
original user 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+
Disconnection logging is separately controlled by <xref
7387+
linkend="guc-log-disconnections"/>.
7388+
</para>
7389+
7390+
<para>
7391+
For the purposes of backwards compatibility, <literal>on</literal>,
7392+
<literal>off</literal>, <literal>true</literal>,
7393+
<literal>false</literal>, <literal>yes</literal>,
7394+
<literal>no</literal>, <literal>1</literal>, and <literal>0</literal>
7395+
are still supported. The positive values are equivalent to specifying
7396+
the <literal>receipt</literal>, <literal>authentication</literal>, and
7397+
<literal>authorization</literal> options.
7398+
</para>
7399+
7400+
<para>
73287401
Only superusers and users with the appropriate <literal>SET</literal>
73297402
privilege can change this parameter at session start,
73307403
and it cannot be changed at all within a session.
7331-
The default is <literal>off</literal>.
73327404
</para>
73337405

73347406
<note>

src/backend/libpq/auth.c

+6-3
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

-1
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

+159-2
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

+2-1
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

+12-9
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 and setup."),
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)