Skip to content

Commit 6b98370

Browse files
author
Commitfest Bot
committed
[CF 5272] V6 - Truncate logs by max_log_size
This branch was automatically generated by a robot using patches from an email thread registered at: https://commitfest.postgresql.org/patch/5272 The branch will be overwritten each time a new patch version is posted to the thread, and also periodically to check for bitrot caused by changes on the master branch. Patch(es): https://www.postgresql.org/message-id/CA+E0NR7XD3wpts2GEFpZpO-M8kj9f8pTrhnAKvq5n4xjtLgLKg@mail.gmail.com Author(s): Kirill Gavrilov
2 parents bc19f63 + 6a9f791 commit 6b98370

File tree

7 files changed

+112
-2
lines changed

7 files changed

+112
-2
lines changed

doc/src/sgml/config.sgml

+16
Original file line numberDiff line numberDiff line change
@@ -8135,6 +8135,22 @@ log_line_prefix = '%m [%p] %q%u@%d/%a '
81358135
</listitem>
81368136
</varlistentry>
81378137

8138+
<varlistentry id="guc-max-log-size" xreflabel="max_log_size">
8139+
<term><varname>max_log_size</varname> (<type>integer</type>)
8140+
<indexterm>
8141+
<primary><varname>max_log_size</varname> configuration parameter</primary>
8142+
</indexterm>
8143+
</term>
8144+
<listitem>
8145+
<para>
8146+
If greater than zero, each query logged is truncated to this many bytes.
8147+
Zero disables the setting.
8148+
If this value is specified without units, it is taken as bytes.
8149+
This feature is disabled by default.
8150+
</para>
8151+
</listitem>
8152+
</varlistentry>
8153+
81388154
</variablelist>
81398155
</sect2>
81408156
<sect2 id="runtime-config-logging-csvlog">

src/backend/tcop/postgres.c

+16-2
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@
7171
#include "tcop/pquery.h"
7272
#include "tcop/tcopprot.h"
7373
#include "tcop/utility.h"
74+
#include "utils/elog.h"
7475
#include "utils/guc_hooks.h"
7576
#include "utils/injection_point.h"
7677
#include "utils/lsyscache.h"
@@ -1018,11 +1019,22 @@ exec_simple_query(const char *query_string)
10181019
bool was_logged = false;
10191020
bool use_implicit_block;
10201021
char msec_str[32];
1022+
char* truncated_query = NULL;
1023+
const char* query_log;
10211024

10221025
/*
10231026
* Report query to various monitoring facilities.
10241027
*/
10251028
debug_query_string = query_string;
1029+
if (need_truncate_query_log(query_string))
1030+
{
1031+
truncated_query = truncate_query_log(query_string);
1032+
query_log = truncated_query;
1033+
}
1034+
else
1035+
{
1036+
query_log = query_string;
1037+
}
10261038

10271039
pgstat_report_activity(STATE_RUNNING, query_string);
10281040

@@ -1067,7 +1079,7 @@ exec_simple_query(const char *query_string)
10671079
if (check_log_statement(parsetree_list))
10681080
{
10691081
ereport(LOG,
1070-
(errmsg("statement: %s", query_string),
1082+
(errmsg("statement: %s", query_log),
10711083
errhidestmt(true),
10721084
errdetail_execute(parsetree_list)));
10731085
was_logged = true;
@@ -1367,7 +1379,7 @@ exec_simple_query(const char *query_string)
13671379
case 2:
13681380
ereport(LOG,
13691381
(errmsg("duration: %s ms statement: %s",
1370-
msec_str, query_string),
1382+
msec_str, query_log),
13711383
errhidestmt(true),
13721384
errdetail_execute(parsetree_list)));
13731385
break;
@@ -1378,6 +1390,8 @@ exec_simple_query(const char *query_string)
13781390

13791391
TRACE_POSTGRESQL_QUERY_DONE(query_string);
13801392

1393+
if (truncated_query)
1394+
pfree(truncated_query);
13811395
debug_query_string = NULL;
13821396
}
13831397

src/backend/utils/error/elog.c

+47
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@ int Log_destination = LOG_DESTINATION_STDERR;
112112
char *Log_destination_string = NULL;
113113
bool syslog_sequence_numbers = true;
114114
bool syslog_split_messages = true;
115+
int max_log_size = 0;
115116

116117
/* Processed form of backtrace_functions GUC */
117118
static char *backtrace_function_list;
@@ -1693,11 +1694,18 @@ EmitErrorReport(void)
16931694
{
16941695
ErrorData *edata = &errordata[errordata_stack_depth];
16951696
MemoryContext oldcontext;
1697+
char* truncated_query = NULL;
16961698

16971699
recursion_depth++;
16981700
CHECK_STACK_DEPTH();
16991701
oldcontext = MemoryContextSwitchTo(edata->assoc_context);
17001702

1703+
if (need_truncate_query_log(debug_query_string))
1704+
{
1705+
truncated_query = truncate_query_log(debug_query_string);
1706+
debug_query_string = truncated_query;
1707+
}
1708+
17011709
/*
17021710
* Reset the formatted timestamp fields before emitting any logs. This
17031711
* includes all the log destinations and emit_log_hook, as the latter
@@ -1738,6 +1746,9 @@ EmitErrorReport(void)
17381746

17391747
MemoryContextSwitchTo(oldcontext);
17401748
recursion_depth--;
1749+
1750+
if (truncated_query)
1751+
pfree(truncated_query);
17411752
}
17421753

17431754
/*
@@ -3814,3 +3825,39 @@ write_stderr(const char *fmt,...)
38143825
#endif
38153826
va_end(ap);
38163827
}
3828+
3829+
/*
3830+
* Apply truncation to build query that will be logged.
3831+
*
3832+
* If query needs to be truncated, copied will be set to true
3833+
* and returned string must be freed
3834+
*/
3835+
char*
3836+
truncate_query_log(const char* query)
3837+
{
3838+
size_t truncated_query_len;
3839+
char* truncatd_query;
3840+
size_t query_len;
3841+
3842+
if (!query)
3843+
return NULL;
3844+
3845+
query_len = strlen(query);
3846+
truncated_query_len = pg_mbcliplen(query, query_len, max_log_size);
3847+
truncatd_query = (char *) palloc(truncated_query_len+1);
3848+
memcpy(truncatd_query, query, truncated_query_len);
3849+
truncatd_query[truncated_query_len] = '\0';
3850+
return truncatd_query;
3851+
}
3852+
3853+
/*
3854+
* Checks if query should be truncated
3855+
* according to max_log_size
3856+
*/
3857+
bool
3858+
need_truncate_query_log(const char* query)
3859+
{
3860+
if (!query)
3861+
return false;
3862+
return !(max_log_size == 0 || strlen(query) < max_log_size);
3863+
}

src/backend/utils/misc/guc_tables.c

+12
Original file line numberDiff line numberDiff line change
@@ -3860,6 +3860,18 @@ struct config_int ConfigureNamesInt[] =
38603860
NULL, NULL, NULL
38613861
},
38623862

3863+
{
3864+
{"max_log_size", PGC_SUSET, LOGGING_WHAT,
3865+
gettext_noop("Sets max size in bytes of logged statement."),
3866+
NULL,
3867+
GUC_UNIT_BYTE
3868+
},
3869+
&max_log_size,
3870+
0,
3871+
0, INT_MAX,
3872+
NULL, NULL, NULL
3873+
},
3874+
38633875
/* End-of-list marker */
38643876
{
38653877
{NULL, 0, 0, NULL, NULL}, NULL, 0, 0, 0, NULL, NULL, NULL

src/backend/utils/misc/postgresql.conf.sample

+2
Original file line numberDiff line numberDiff line change
@@ -638,6 +638,8 @@
638638
# bind-parameter values to N bytes;
639639
# -1 means print in full, 0 disables
640640
#log_statement = 'none' # none, ddl, mod, all
641+
#max_log_size = 0 # max size of logged statement
642+
# 0 disables the feature
641643
#log_replication_commands = off
642644
#log_temp_files = -1 # log temporary files equal or larger
643645
# than the specified size in kilobytes;

src/bin/pg_ctl/t/004_logrotate.pl

+15
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ sub check_log_pattern
6969
# these ensure stability of test results:
7070
log_rotation_age = 0
7171
lc_messages = 'C'
72+
max_log_size = 32
7273
));
7374

7475
$node->start();
@@ -135,6 +136,20 @@ sub check_log_pattern
135136
check_log_pattern('csvlog', $new_current_logfiles, 'syntax error', $node);
136137
check_log_pattern('jsonlog', $new_current_logfiles, 'syntax error', $node);
137138

139+
$node->psql('postgres', 'INSERT INTO SOME_NON_EXISTANT_TABLE VALUES (TEST)');
140+
for (my $attempts = 0; $attempts < $max_attempts; $attempts++)
141+
{
142+
eval {
143+
$current_logfiles = slurp_file($node->data_dir . '/current_logfiles');
144+
};
145+
last unless $@;
146+
usleep(100_000);
147+
}
148+
die $@ if $@;
149+
check_log_pattern('stderr', $current_logfiles, 'INSERT INTO SOME_NON_EXISTANT_TA(?!(BLE VALUES \(TEST\)))', $node);
150+
check_log_pattern('csvlog', $current_logfiles, 'INSERT INTO SOME_NON_EXISTANT_TA(?!(BLE VALUES \(TEST\)))', $node);
151+
check_log_pattern('jsonlog', $current_logfiles, 'INSERT INTO SOME_NON_EXISTANT_TA(?!(BLE VALUES \(TEST\)))', $node);
152+
138153
$node->stop();
139154

140155
done_testing();

src/include/utils/elog.h

+4
Original file line numberDiff line numberDiff line change
@@ -493,6 +493,7 @@ extern PGDLLIMPORT int Log_destination;
493493
extern PGDLLIMPORT char *Log_destination_string;
494494
extern PGDLLIMPORT bool syslog_sequence_numbers;
495495
extern PGDLLIMPORT bool syslog_split_messages;
496+
extern PGDLLIMPORT int max_log_size;
496497

497498
/* Log destination bitmap */
498499
#define LOG_DESTINATION_STDERR 1
@@ -508,6 +509,9 @@ extern void DebugFileOpen(void);
508509
extern char *unpack_sql_state(int sql_state);
509510
extern bool in_error_recursion_trouble(void);
510511

512+
extern bool need_truncate_query_log(const char* query);
513+
extern char* truncate_query_log(const char* query);
514+
511515
/* Common functions shared across destinations */
512516
extern void reset_formatted_start_time(void);
513517
extern char *get_formatted_start_time(void);

0 commit comments

Comments
 (0)