Technical Analysis: Truncate Logged Statements by Maximum Length
Core Problem
PostgreSQL's logging infrastructure has no built-in mechanism to limit the size of individual logged statements. When queries contain very large payloads—multi-megabyte BLOBs encoded as literals, massive IN-lists, or enormous COPY data—the resulting log entries can consume disproportionate disk space and degrade log analysis tooling. This is not merely a disk management issue; it's a log abuse vector where a single malformed or intentionally oversized query can flood logs, making it impossible to find meaningful diagnostic information.
The existing mitigations are indirect:
GRANT ... ON PARAMETER+SET LOCALto disable logging for specific sessions- Log rotation settings or external log management tools (logrotate, syslog)
- None of these address the fundamental issue of a single statement being unboundedly large in the log output
Proposed Solution
The patch introduces a new GUC parameter log_statement_max_length (originally named max_log_size, renamed after review feedback) that truncates statements written to the server log at a configurable byte limit. The key design decisions evolved over ~20 months of development:
GUC Design
- Name: Changed from
max_log_size→log_statement_max_lengthto avoid confusion with log file size limits - Unit: Bytes (with standard unit suffixes: kB, MB, GB), using
GUC_UNIT_BYTE - Default:
-1(no truncation; logs statements in full) — changed from original0and then5MBdefaults - Disable value:
-1(consistent withlog_parameter_max_length) - Context:
PGC_SUSET— settable per-session by superusers, which is important for targeted debugging - Scope: Applies to statements logged by
log_statementandlog_min_duration_statementonly, NOT to error-context STATEMENT lines (a deliberate design choice)
Implementation Architecture
The core implementation adds a truncate_query_log() function in elog.c that:
- Checks if
log_statement_max_length >= 0and the query exceeds that length - Uses
pg_mbcliplen()to ensure truncation respects multi-byte character boundaries (important for UTF-8 correctness) - Returns a palloc'd truncated copy, or NULL if no truncation needed
- Caller is responsible for pfree
Truncation is applied in four code paths:
exec_simple_query()— simple query protocolexec_parse_message()— extended protocol parse phaseexec_bind_message()— extended protocol bind phaseexec_execute_message()— extended protocol execute phase
Critical Fix: Empty STATEMENT Bug
An important bug was identified by Fujii: when log_statement logs a truncated query and then the same query errors, the STATEMENT line in the error report was empty. This occurred because the original patch modified debug_query_string globally. The fix separates truncation from the error-reporting path—truncation applies only to proactive logging (log_statement, log_min_duration_statement), while error STATEMENT lines remain untruncated.
Performance Consideration
A key optimization identified during review: early patch versions called truncate_query_log() unconditionally in exec_simple_query() (performing strlen() on every query regardless of whether logging would occur). The final version calls truncation lazily—only inside the check_log_statement() true-branch or check_log_duration() case 2—avoiding overhead for the common case where queries aren't logged.
Key Technical Tradeoffs
-
Truncation on error statements: The patch deliberately does NOT truncate statements in error STATEMENT lines. Maxym Kharchenko raised whether a companion
log_statement_max_length_on_error(analogous tolog_parameter_max_length_on_error) is needed. The consensus is this should be a follow-up patch—error statements serve debugging purposes where full context is valuable. -
Multi-byte safety: The patch uses
pg_mbcliplen()rather than raw byte truncation, ensuring truncated output never splits a multi-byte character. The size limit is in bytes (not characters), which was a deliberate choice documented clearly. -
Replication commands: Fujii noted that
log_replication_commandsalso logs statements but the patch doesn't cover this path. This remains unaddressed. -
CONTEXT line queries: Queries logged in CONTEXT (e.g., from PL/pgSQL
DOblocks) are not truncated. This is noted but not addressed. -
Security model: The feature is positioned as log-size management, not security/privacy control (unlike
log_parameter_max_lengthwhich protects sensitive parameter values).
Relationship to CVE-2026-2006
A brief security review was performed regarding CVE-2026-2006 (details not elaborated in thread). The conclusion was that the patch's use of pg_mbcliplen() is correct and not vulnerable to the encoding-related issues that CVE addressed.
Current Status
The patch reached "LGTM" status from Fujii Masao (a committer) as of v11, with the intent to commit once the PostgreSQL 20 development cycle opens. It has been through extensive iterative review addressing compilation warnings, C90 compliance, documentation clarity, test placement (moved from pg_ctl tests to src/test/modules/test_misc/), and performance optimization.