Skip to content

Commit a50faf4

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 6551a05 + 213591d commit a50faf4

File tree

7 files changed

+112
-2
lines changed

7 files changed

+112
-2
lines changed

doc/src/sgml/config.sgml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8140,6 +8140,22 @@ log_line_prefix = '%m [%p] %q%u@%d/%a '
81408140
</listitem>
81418141
</varlistentry>
81428142

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

src/backend/tcop/postgres.c

Lines changed: 16 additions & 2 deletions
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"
@@ -1019,11 +1020,22 @@ exec_simple_query(const char *query_string)
10191020
bool was_logged = false;
10201021
bool use_implicit_block;
10211022
char msec_str[32];
1023+
char* truncated_query = NULL;
1024+
const char* query_log;
10221025

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

10281040
pgstat_report_activity(STATE_RUNNING, query_string);
10291041

@@ -1068,7 +1080,7 @@ exec_simple_query(const char *query_string)
10681080
if (check_log_statement(parsetree_list))
10691081
{
10701082
ereport(LOG,
1071-
(errmsg("statement: %s", query_string),
1083+
(errmsg("statement: %s", query_log),
10721084
errhidestmt(true),
10731085
errdetail_execute(parsetree_list)));
10741086
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

Lines changed: 47 additions & 0 deletions
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;
@@ -1696,11 +1697,18 @@ EmitErrorReport(void)
16961697
{
16971698
ErrorData *edata = &errordata[errordata_stack_depth];
16981699
MemoryContext oldcontext;
1700+
char* truncated_query = NULL;
16991701

17001702
recursion_depth++;
17011703
CHECK_STACK_DEPTH();
17021704
oldcontext = MemoryContextSwitchTo(edata->assoc_context);
17031705

1706+
if (need_truncate_query_log(debug_query_string))
1707+
{
1708+
truncated_query = truncate_query_log(debug_query_string);
1709+
debug_query_string = truncated_query;
1710+
}
1711+
17041712
/*
17051713
* Reset the formatted timestamp fields before emitting any logs. This
17061714
* includes all the log destinations and emit_log_hook, as the latter
@@ -1741,6 +1749,9 @@ EmitErrorReport(void)
17411749

17421750
MemoryContextSwitchTo(oldcontext);
17431751
recursion_depth--;
1752+
1753+
if (truncated_query)
1754+
pfree(truncated_query);
17441755
}
17451756

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

src/backend/utils/misc/guc_tables.c

Lines changed: 12 additions & 0 deletions
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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -634,6 +634,8 @@
634634
# bind-parameter values to N bytes;
635635
# -1 means print in full, 0 disables
636636
#log_statement = 'none' # none, ddl, mod, all
637+
#max_log_size = 0 # max size of logged statement
638+
# 0 disables the feature
637639
#log_replication_commands = off
638640
#log_temp_files = -1 # log temporary files equal or larger
639641
# than the specified size in kilobytes;

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

Lines changed: 15 additions & 0 deletions
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

Lines changed: 4 additions & 0 deletions
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)