Commit 799e2203 authored by Alvaro Herrera's avatar Alvaro Herrera

Log all statements from a sample of transactions

This is useful to obtain a view of the different transaction types in an
application, regardless of the durations of the statements each runs.

Author: Adrien Nayrat
Reviewed-by: Masahiko Sawada, Hayato Kuroda, Andres Freund
parent d8c0bd9f
...@@ -5871,6 +5871,32 @@ local0.* /var/log/postgresql ...@@ -5871,6 +5871,32 @@ local0.* /var/log/postgresql
</listitem> </listitem>
</varlistentry> </varlistentry>
<varlistentry id="guc-log-transaction-sample-rate" xreflabel="log_transaction_sample_rate">
<term><varname>log_transaction_sample_rate</varname> (<type>real</type>)
<indexterm>
<primary><varname>log_transaction_sample_rate</varname> configuration parameter</primary>
</indexterm>
</term>
<listitem>
<para>
Set the fraction of transactions whose statements are all logged,
in addition to statements logged for other reasons. It applies to
each new transaction regardless of its statements' durations.
The default is <literal>0</literal>, meaning not to log statements
from any additional transaction. Setting this to <literal>1</literal>
logs all statements for all transactions.
<varname>log_transaction_sample_rate</varname> is helpful to track a
sample of transaction.
</para>
<note>
<para>
Like all statement-logging options, this option can add significant
overhead.
</para>
</note>
</listitem>
</varlistentry>
</variablelist> </variablelist>
<para> <para>
......
...@@ -264,6 +264,9 @@ static char *prepareGID; ...@@ -264,6 +264,9 @@ static char *prepareGID;
*/ */
static bool forceSyncCommit = false; static bool forceSyncCommit = false;
/* Flag for logging statements in a transaction. */
bool xact_is_sampled = false;
/* /*
* Private context for transaction-abort work --- we reserve space for this * Private context for transaction-abort work --- we reserve space for this
* at startup to ensure that AbortTransaction and AbortSubTransaction can work * at startup to ensure that AbortTransaction and AbortSubTransaction can work
...@@ -1903,6 +1906,11 @@ StartTransaction(void) ...@@ -1903,6 +1906,11 @@ StartTransaction(void)
s->state = TRANS_START; s->state = TRANS_START;
s->fullTransactionId = InvalidFullTransactionId; /* until assigned */ s->fullTransactionId = InvalidFullTransactionId; /* until assigned */
/* Determine if statements are logged in this transaction */
xact_is_sampled = log_xact_sample_rate != 0 &&
(log_xact_sample_rate == 1 ||
random() <= log_xact_sample_rate * MAX_RANDOM_VALUE);
/* /*
* initialize current transaction state fields * initialize current transaction state fields
* *
......
...@@ -2194,6 +2194,8 @@ check_log_statement(List *stmt_list) ...@@ -2194,6 +2194,8 @@ check_log_statement(List *stmt_list)
* check_log_duration * check_log_duration
* Determine whether current command's duration should be logged. * Determine whether current command's duration should be logged.
* If log_statement_sample_rate < 1.0, log only a sample. * If log_statement_sample_rate < 1.0, log only a sample.
* We also check if this statement in this transaction must be logged
* (regardless of its duration).
* *
* Returns: * Returns:
* 0 if no logging is needed * 0 if no logging is needed
...@@ -2209,7 +2211,7 @@ check_log_statement(List *stmt_list) ...@@ -2209,7 +2211,7 @@ check_log_statement(List *stmt_list)
int int
check_log_duration(char *msec_str, bool was_logged) check_log_duration(char *msec_str, bool was_logged)
{ {
if (log_duration || log_min_duration_statement >= 0) if (log_duration || log_min_duration_statement >= 0 || xact_is_sampled)
{ {
long secs; long secs;
int usecs; int usecs;
...@@ -2243,11 +2245,11 @@ check_log_duration(char *msec_str, bool was_logged) ...@@ -2243,11 +2245,11 @@ check_log_duration(char *msec_str, bool was_logged)
(log_statement_sample_rate == 1 || (log_statement_sample_rate == 1 ||
random() <= log_statement_sample_rate * MAX_RANDOM_VALUE); random() <= log_statement_sample_rate * MAX_RANDOM_VALUE);
if ((exceeded && in_sample) || log_duration) if ((exceeded && in_sample) || log_duration || xact_is_sampled)
{ {
snprintf(msec_str, 32, "%ld.%03d", snprintf(msec_str, 32, "%ld.%03d",
secs * 1000 + msecs, usecs % 1000); secs * 1000 + msecs, usecs % 1000);
if (exceeded && !was_logged) if ((exceeded || xact_is_sampled) && !was_logged)
return 2; return 2;
else else
return 1; return 1;
......
...@@ -510,6 +510,7 @@ int client_min_messages = NOTICE; ...@@ -510,6 +510,7 @@ int client_min_messages = NOTICE;
int log_min_duration_statement = -1; int log_min_duration_statement = -1;
int log_temp_files = -1; int log_temp_files = -1;
double log_statement_sample_rate = 1.0; double log_statement_sample_rate = 1.0;
double log_xact_sample_rate = 0;
int trace_recovery_messages = LOG; int trace_recovery_messages = LOG;
int temp_file_limit = -1; int temp_file_limit = -1;
...@@ -3386,6 +3387,18 @@ static struct config_real ConfigureNamesReal[] = ...@@ -3386,6 +3387,18 @@ static struct config_real ConfigureNamesReal[] =
NULL, NULL, NULL 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. "
"Use a value between 0.0 (never log) and 1.0 (log all "
"statements for all transactions).")
},
&log_xact_sample_rate,
0.0, 0.0, 1.0,
NULL, NULL, NULL
},
/* End-of-list marker */ /* End-of-list marker */
{ {
{NULL, 0, 0, NULL, NULL}, NULL, 0.0, 0.0, 0.0, NULL, NULL, NULL {NULL, 0, 0, NULL, NULL}, NULL, 0.0, 0.0, 0.0, NULL, NULL, NULL
......
...@@ -495,6 +495,10 @@ ...@@ -495,6 +495,10 @@
# log_min_duration_statement. 1.0 logs all statements, # log_min_duration_statement. 1.0 logs all statements,
# 0 never logs. # 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.
# - What to Log - # - What to Log -
#debug_print_parse = off #debug_print_parse = off
......
...@@ -55,6 +55,9 @@ extern PGDLLIMPORT int XactIsoLevel; ...@@ -55,6 +55,9 @@ extern PGDLLIMPORT int XactIsoLevel;
extern bool DefaultXactReadOnly; extern bool DefaultXactReadOnly;
extern bool XactReadOnly; extern bool XactReadOnly;
/* flag for logging statements in this transaction */
extern bool xact_is_sampled;
/* /*
* Xact is deferrable -- only meaningful (currently) for read only * Xact is deferrable -- only meaningful (currently) for read only
* SERIALIZABLE transactions * SERIALIZABLE transactions
......
...@@ -252,6 +252,7 @@ extern PGDLLIMPORT int client_min_messages; ...@@ -252,6 +252,7 @@ extern PGDLLIMPORT int client_min_messages;
extern int log_min_duration_statement; extern int log_min_duration_statement;
extern int log_temp_files; extern int log_temp_files;
extern double log_statement_sample_rate; extern double log_statement_sample_rate;
extern double log_xact_sample_rate;
extern int temp_file_limit; extern int temp_file_limit;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment