aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorTomas Vondra <tomas.vondra@postgresql.org>2019-11-04 01:57:45 +0100
committerTomas Vondra <tomas.vondra@postgresql.org>2019-11-06 19:11:07 +0100
commit6e3e6cc0e884a6091e1094dff29db430af08fb93 (patch)
treeb44e1702678389fc68ec9a2da2ff5bb21c4db9a5 /src
parent11d9ac28e5e0077d8f23761c2962a30423f44cee (diff)
downloadpostgresql-6e3e6cc0e884a6091e1094dff29db430af08fb93.tar.gz
postgresql-6e3e6cc0e884a6091e1094dff29db430af08fb93.zip
Allow sampling of statements depending on duration
This allows logging a sample of statements, without incurring excessive log traffic (which may impact performance). This can be useful when analyzing workloads with lots of short queries. The sampling is configured using two new GUC parameters: * log_min_duration_sample - minimum required statement duration * log_statement_sample_rate - sample rate (0.0 - 1.0) Only statements with duration exceeding log_min_duration_sample are considered for sampling. To enable sampling, both those GUCs have to be set correctly. The existing log_min_duration_statement GUC has a higher priority, i.e. statements with duration exceeding log_min_duration_statement will be always logged, irrespectedly of how the sampling is configured. This means only configurations log_min_duration_sample < log_min_duration_statement do actually sample the statements, instead of logging everything. Author: Adrien Nayrat Reviewed-by: David Rowley, Vik Fearing, Tomas Vondra Discussion: https://postgr.es/m/bbe0a1a8-a8f7-3be2-155a-888e661cc06c@anayrat.info
Diffstat (limited to 'src')
-rw-r--r--src/backend/tcop/postgres.c40
-rw-r--r--src/backend/utils/misc/guc.c27
-rw-r--r--src/backend/utils/misc/postgresql.conf.sample11
-rw-r--r--src/include/utils/guc.h2
4 files changed, 68 insertions, 12 deletions
diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
index 4bec40aa287..82894eadc66 100644
--- a/src/backend/tcop/postgres.c
+++ b/src/backend/tcop/postgres.c
@@ -2235,12 +2235,15 @@ check_log_statement(List *stmt_list)
int
check_log_duration(char *msec_str, bool was_logged)
{
- if (log_duration || log_min_duration_statement >= 0 || xact_is_sampled)
+ if (log_duration || log_min_duration_sample >= 0 ||
+ log_min_duration_statement >= 0 || xact_is_sampled)
{
long secs;
int usecs;
int msecs;
- bool exceeded;
+ bool exceeded_duration;
+ bool exceeded_sample_duration;
+ bool in_sample = false;
TimestampDifference(GetCurrentStatementStartTimestamp(),
GetCurrentTimestamp(),
@@ -2248,20 +2251,35 @@ check_log_duration(char *msec_str, bool was_logged)
msecs = usecs / 1000;
/*
- * This odd-looking test for log_min_duration_statement being exceeded
- * is designed to avoid integer overflow with very long durations:
- * don't compute secs * 1000 until we've verified it will fit in int.
+ * This odd-looking test for log_min_duration_* being exceeded is
+ * designed to avoid integer overflow with very long durations: don't
+ * compute secs * 1000 until we've verified it will fit in int.
*/
- exceeded = (log_min_duration_statement == 0 ||
- (log_min_duration_statement > 0 &&
- (secs > log_min_duration_statement / 1000 ||
- secs * 1000 + msecs >= log_min_duration_statement)));
+ exceeded_duration = (log_min_duration_statement == 0 ||
+ (log_min_duration_statement > 0 &&
+ (secs > log_min_duration_statement / 1000 ||
+ secs * 1000 + msecs >= log_min_duration_statement)));
- if (exceeded || log_duration || xact_is_sampled)
+ exceeded_sample_duration = (log_min_duration_sample == 0 ||
+ (log_min_duration_sample > 0 &&
+ (secs > log_min_duration_sample / 1000 ||
+ secs * 1000 + msecs >= log_min_duration_sample)));
+
+ /*
+ * Do not log if log_statement_sample_rate = 0. Log a sample if
+ * log_statement_sample_rate <= 1 and avoid unecessary random() call
+ * if log_statement_sample_rate = 1.
+ */
+ if (exceeded_sample_duration)
+ in_sample = log_statement_sample_rate != 0 &&
+ (log_statement_sample_rate == 1 ||
+ random() <= log_statement_sample_rate * MAX_RANDOM_VALUE);
+
+ if (exceeded_duration || in_sample || log_duration || xact_is_sampled)
{
snprintf(msec_str, 32, "%ld.%03d",
secs * 1000 + msecs, usecs % 1000);
- if ((exceeded || xact_is_sampled) && !was_logged)
+ if ((exceeded_duration || in_sample || xact_is_sampled) && !was_logged)
return 2;
else
return 1;
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 31a5ef04747..e84c8cc4cfc 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -509,8 +509,10 @@ bool session_auth_is_superuser;
int log_min_error_statement = ERROR;
int log_min_messages = WARNING;
int client_min_messages = NOTICE;
+int log_min_duration_sample = -1;
int log_min_duration_statement = -1;
int log_temp_files = -1;
+double log_statement_sample_rate = 1.0;
double log_xact_sample_rate = 0;
int trace_recovery_messages = LOG;
@@ -2701,9 +2703,22 @@ static struct config_int ConfigureNamesInt[] =
},
{
+ {"log_min_duration_sample", PGC_SUSET, LOGGING_WHEN,
+ gettext_noop("Sets the minimum execution time above which "
+ "a sample of statements will be logged."
+ " Sampling is determined by log_statement_sample_rate."),
+ gettext_noop("Zero log a sample of all queries. -1 turns this feature off."),
+ GUC_UNIT_MS
+ },
+ &log_min_duration_sample,
+ -1, -1, INT_MAX,
+ NULL, NULL, NULL
+ },
+
+ {
{"log_min_duration_statement", PGC_SUSET, LOGGING_WHEN,
gettext_noop("Sets the minimum execution time above which "
- "statements will be logged."),
+ "all statements will be logged."),
gettext_noop("Zero prints all queries. -1 turns this feature off."),
GUC_UNIT_MS
},
@@ -3431,6 +3446,16 @@ static struct config_real ConfigureNamesReal[] =
},
{
+ {"log_statement_sample_rate", PGC_SUSET, LOGGING_WHEN,
+ gettext_noop("Fraction of statements exceeding log_min_duration_sample to be logged."),
+ gettext_noop("Use a value between 0.0 (never log) and 1.0 (always log).")
+ },
+ &log_statement_sample_rate,
+ 1.0, 0.0, 1.0,
+ NULL, NULL, NULL
+ },
+
+ {
{"log_transaction_sample_rate", PGC_SUSET, LOGGING_WHEN,
gettext_noop("Set the fraction of transactions to log for new transactions."),
gettext_noop("Logs all statements from a fraction of transactions. "
diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample
index 0fc23e3a612..be02a76d9d8 100644
--- a/src/backend/utils/misc/postgresql.conf.sample
+++ b/src/backend/utils/misc/postgresql.conf.sample
@@ -493,6 +493,17 @@
# statements running at least this number
# of milliseconds
+#log_min_duration_sample = -1 # -1 is disabled, 0 logs a sample of statements
+ # and their durations, > 0 logs only a sample of
+ # statements running at least this number
+ # of milliseconds
+ # Sample fraction is determined by log_statement_sample_rate
+
+#log_statement_sample_rate = 1.0 # Fraction of logged statements exceeding
+ # log_min_duration_sample to be logged.
+ # 1.0 logs all such statements, 0.0 never logs.
+
+
#log_transaction_sample_rate = 0.0 # Fraction of transactions whose statements
# are logged regardless of their duration. 1.0 logs all
# statements from all transactions, 0.0 never logs.
diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h
index 6791e0cbc20..9aa3d025965 100644
--- a/src/include/utils/guc.h
+++ b/src/include/utils/guc.h
@@ -251,8 +251,10 @@ extern bool session_auth_is_superuser;
extern int log_min_error_statement;
extern PGDLLIMPORT int log_min_messages;
extern PGDLLIMPORT int client_min_messages;
+extern int log_min_duration_sample;
extern int log_min_duration_statement;
extern int log_temp_files;
+extern double log_statement_sample_rate;
extern double log_xact_sample_rate;
extern int temp_file_limit;