summaryrefslogtreecommitdiff
path: root/src/backend/tcop
diff options
context:
space:
mode:
authorMelanie Plageman2025-03-12 15:33:01 +0000
committerMelanie Plageman2025-03-12 15:35:21 +0000
commit9219093cab2607f34ac70612a65430a9c519157f (patch)
treee245b0dc191564005192cc596173187ec595ad3e /src/backend/tcop
parentf554a95379a9adef233d21b1e1e8981a8f5f8de3 (diff)
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 <[email protected]> Reviewed-by: Bertrand Drouvot <[email protected]> Reviewed-by: Fujii Masao <[email protected]> Reviewed-by: Daniel Gustafsson <[email protected]> Discussion: https://postgr.es/m/flat/CAAKRu_b_smAHK0ZjrnL5GRxnAVWujEXQWpLXYzGbmpcZd3nLYw%40mail.gmail.com
Diffstat (limited to 'src/backend/tcop')
-rw-r--r--src/backend/tcop/backend_startup.c161
1 files changed, 159 insertions, 2 deletions
diff --git a/src/backend/tcop/backend_startup.c b/src/backend/tcop/backend_startup.c
index c70746fa562..962b6e60002 100644
--- a/src/backend/tcop/backend_startup.c
+++ b/src/backend/tcop/backend_startup.c
@@ -34,13 +34,17 @@
#include "tcop/backend_startup.h"
#include "tcop/tcopprot.h"
#include "utils/builtins.h"
+#include "utils/guc_hooks.h"
#include "utils/injection_point.h"
#include "utils/memutils.h"
#include "utils/ps_status.h"
#include "utils/timeout.h"
+#include "utils/varlena.h"
/* GUCs */
bool Trace_connection_negotiation = false;
+uint32 log_connections = 0;
+char *log_connections_string = NULL;
static void BackendInitialize(ClientSocket *client_sock, CAC_state cac);
static int ProcessSSLStartup(Port *port);
@@ -48,6 +52,7 @@ static int ProcessStartupPacket(Port *port, bool ssl_done, bool gss_done);
static void SendNegotiateProtocolVersion(List *unrecognized_protocol_options);
static void process_startup_packet_die(SIGNAL_ARGS);
static void StartupPacketTimeoutHandler(void);
+static bool validate_log_connections_options(List *elemlist, uint32 *flags);
/*
* Entry point for a new backend process.
@@ -201,8 +206,8 @@ BackendInitialize(ClientSocket *client_sock, CAC_state cac)
port->remote_host = MemoryContextStrdup(TopMemoryContext, remote_host);
port->remote_port = MemoryContextStrdup(TopMemoryContext, remote_port);
- /* And now we can issue the Log_connections message, if wanted */
- if (Log_connections)
+ /* And now we can log that the connection was received, if enabled */
+ if (log_connections & LOG_CONNECTION_RECEIPT)
{
if (remote_port[0])
ereport(LOG,
@@ -924,3 +929,155 @@ StartupPacketTimeoutHandler(void)
{
_exit(1);
}
+
+/*
+ * Helper for the log_connections GUC check hook.
+ *
+ * `elemlist` is a listified version of the string input passed to the
+ * log_connections GUC check hook, check_log_connections().
+ * check_log_connections() is responsible for cleaning up `elemlist`.
+ *
+ * validate_log_connections_options() returns false if an error was
+ * encountered and the GUC input could not be validated and true otherwise.
+ *
+ * `flags` returns the flags that should be stored in the log_connections GUC
+ * by its assign hook.
+ */
+static bool
+validate_log_connections_options(List *elemlist, uint32 *flags)
+{
+ ListCell *l;
+ char *item;
+
+ /*
+ * For backwards compatibility, we accept these tokens by themselves.
+ *
+ * Prior to PostgreSQL 18, log_connections was a boolean GUC that accepted
+ * any unambiguous substring of 'true', 'false', 'yes', 'no', 'on', and
+ * 'off'. Since log_connections became a list of strings in 18, we only
+ * accept complete option strings.
+ */
+ static const struct config_enum_entry compat_options[] = {
+ {"off", 0},
+ {"false", 0},
+ {"no", 0},
+ {"0", 0},
+ {"on", LOG_CONNECTION_ON},
+ {"true", LOG_CONNECTION_ON},
+ {"yes", LOG_CONNECTION_ON},
+ {"1", LOG_CONNECTION_ON},
+ };
+
+ *flags = 0;
+
+ /* If an empty string was passed, we're done */
+ if (list_length(elemlist) == 0)
+ return true;
+
+ /*
+ * Now check for the backwards compatibility options. They must always be
+ * specified on their own, so we error out if the first option is a
+ * backwards compatibility option and other options are also specified.
+ */
+ item = linitial(elemlist);
+
+ for (size_t i = 0; i < lengthof(compat_options); i++)
+ {
+ struct config_enum_entry option = compat_options[i];
+
+ if (pg_strcasecmp(item, option.name) != 0)
+ continue;
+
+ if (list_length(elemlist) > 1)
+ {
+ GUC_check_errdetail("Cannot specify log_connections option \"%s\" in a list with other options.",
+ item);
+ return false;
+ }
+
+ *flags = option.val;
+ return true;
+ }
+
+ /* Now check the aspect options. The empty string was already handled */
+ foreach(l, elemlist)
+ {
+ static const struct config_enum_entry options[] = {
+ {"receipt", LOG_CONNECTION_RECEIPT},
+ {"authentication", LOG_CONNECTION_AUTHENTICATION},
+ {"authorization", LOG_CONNECTION_AUTHORIZATION},
+ {"all", LOG_CONNECTION_ALL},
+ };
+
+ item = lfirst(l);
+ for (size_t i = 0; i < lengthof(options); i++)
+ {
+ struct config_enum_entry option = options[i];
+
+ if (pg_strcasecmp(item, option.name) == 0)
+ {
+ *flags |= option.val;
+ goto next;
+ }
+ }
+
+ GUC_check_errdetail("Invalid option \"%s\".", item);
+ return false;
+
+next: ;
+ }
+
+ return true;
+}
+
+
+/*
+ * GUC check hook for log_connections
+ */
+bool
+check_log_connections(char **newval, void **extra, GucSource source)
+{
+ uint32 flags;
+ char *rawstring;
+ List *elemlist;
+ bool success;
+
+ /* Need a modifiable copy of string */
+ rawstring = pstrdup(*newval);
+
+ if (!SplitIdentifierString(rawstring, ',', &elemlist))
+ {
+ GUC_check_errdetail("Invalid list syntax in parameter \"log_connections\".");
+ pfree(rawstring);
+ list_free(elemlist);
+ return false;
+ }
+
+ /* Validation logic is all in the helper */
+ success = validate_log_connections_options(elemlist, &flags);
+
+ /* Time for cleanup */
+ pfree(rawstring);
+ list_free(elemlist);
+
+ if (!success)
+ return false;
+
+ /*
+ * We succeeded, so allocate `extra` and save the flags there for use by
+ * assign_log_connections().
+ */
+ *extra = guc_malloc(ERROR, sizeof(int));
+ *((int *) *extra) = flags;
+
+ return true;
+}
+
+/*
+ * GUC assign hook for log_connections
+ */
+void
+assign_log_connections(const char *newval, void *extra)
+{
+ log_connections = *((int *) extra);
+}