diff --git a/doc/src/sgml/logical-replication.sgml b/doc/src/sgml/logical-replication.sgml
index 9e7868487de..7e08b9c0081 100644
--- a/doc/src/sgml/logical-replication.sgml
+++ b/doc/src/sgml/logical-replication.sgml
@@ -293,6 +293,20 @@
option of CREATE SUBSCRIPTION for details.
+
+ Conflicts that occur during replication are, by default, logged as plain text
+ in the server log, which can make automated monitoring and analysis difficult.
+ The CREATE SUBSCRIPTION command provides the
+
+ conflict_log_destination option to record detailed
+ conflict information in a structured, queryable format. When this parameter
+ is set to table or all, the system
+ automatically manages a dedicated conflict log table,
+ which is created and dropped along with the subscription. This significantly
+ improves post-mortem analysis and operational visibility of the replication
+ setup.
+
+
Logical Replication Slot Management
@@ -2009,6 +2023,9 @@ Included in publications:
operations will simply be skipped.
+
+ Conflict logging
+
Additional logging is triggered, and the conflict statistics are collected (displayed in the
pg_stat_subscription_stats view)
@@ -2121,8 +2138,111 @@ Included in publications:
log.
+
+
+
+ Table-based logging
+
+
+ If conflict_log_destination
+ is set to table or all then a dedicated conflict
+ log table will be automatically created. This table is created in the
+ pg_conflict namespace. The name of the conflict log table
+ is pg_conflict_log_<subid>. The predefined schema of this table is
+ detailed in
+ .
+
+
+
+ Conflict Log Table Schema
+
+
+
+ Column
+ Type
+ Description
+
+
+
+
+ relid
+ oid
+ The OID of the local table where the conflict occurred.
+
+
+ schemaname
+ text
+ The schema name of the conflicting table.
+
+
+ relname
+ text
+ The name of the conflicting table.
+
+
+ conflict_type
+ text
+ The type of conflict that occurred (e.g., insert_exists).
+
+
+ remote_xid
+ xid
+ The remote transaction ID that caused the conflict.
+
+
+ remote_commit_lsn
+ pg_lsn
+ The final LSN of the remote transaction.
+
+
+ remote_commit_ts
+ timestamptz
+ The remote commit timestamp of the remote transaction.
+
+
+ remote_origin
+ text
+ The origin of the remote transaction.
+
+
+ replica_identity
+ json
+ The JSON representation of the replica identity.
+
+
+ remote_tuple
+ json
+ The JSON representation of the incoming remote row that caused the conflict.
+
+
+ local_conflicts
+ json[]
+
+ An array of JSON objects representing the local state for each conflict attempt.
+ Each object includes the local transaction ID (xid), commit
+ timestamp (commit_ts), origin (origin),
+ conflicting key data (key), and the full local row
+ image (tuple).
+
+
+
+
+
+
+
+ The conflicting row data, including the incoming remote row (remote_tuple)
+ and the associated local conflict details (local_conflicts), is stored in
+ JSON formats for flexible querying and analysis.
+
+
+
+
+ File-based logging
+
- The log format for logical replication conflicts is as follows:
+ If conflict_log_destination
+ is set to log or all then conflicts are logged to the server log using
+ the following format:
LOG: conflict detected on relation "schemaname.tablename": conflict=conflict_type
DETAIL: detailed_explanation[: detail_values [, ... ]].
@@ -2235,6 +2355,10 @@ DETAIL: detailed_explanation[:
+
+
+ Notes
+
Logical replication operations are performed with the privileges of the role
which owns the subscription. Permissions failures on target tables will
@@ -2311,6 +2435,8 @@ CONTEXT: processing remote data for replication origin "pg_16395" during "INSER
linkend="sql-altersubscription">ALTER SUBSCRIPTION ...
SKIP.
+
+
@@ -2415,6 +2541,13 @@ CONTEXT: processing remote data for replication origin "pg_16395" during "INSER
key or replica identity defined for it.
+
+
+
+ Conflict log tables (see conflict_log_destination parameter)
+ are never published, even when using FOR ALL TABLES in a publication.
+
+
diff --git a/doc/src/sgml/ref/alter_subscription.sgml b/doc/src/sgml/ref/alter_subscription.sgml
index e4f0b6b16c7..07b7ede52ec 100644
--- a/doc/src/sgml/ref/alter_subscription.sgml
+++ b/doc/src/sgml/ref/alter_subscription.sgml
@@ -293,8 +293,9 @@ ALTER SUBSCRIPTION name RENAME TO <
failover,
two_phase,
retain_dead_tuples,
- max_retention_duration, and
- wal_receiver_timeout.
+ max_retention_duration,
+ wal_receiver_timeout, and
+ conflict_log_destination.
Only a superuser can set password_required = false.
@@ -352,6 +353,14 @@ ALTER SUBSCRIPTION name RENAME TO <
pg_conflict_detection, created to retain
dead tuples for conflict detection, will be dropped.
+
+
+ When the conflict_log_destination
+ parameter is set to table or all, the system
+ automatically creates the internal conflict log table. Conversely, if the destination is changed to
+ log, logging to the table stops and the internal
+ table is automatically dropped.
+
diff --git a/doc/src/sgml/ref/create_subscription.sgml b/doc/src/sgml/ref/create_subscription.sgml
index 07d5b1bd77c..82c651090ae 100644
--- a/doc/src/sgml/ref/create_subscription.sgml
+++ b/doc/src/sgml/ref/create_subscription.sgml
@@ -261,6 +261,55 @@ CREATE SUBSCRIPTION subscription_name
+
+ conflict_log_destination (enum)
+
+
+ Specifies the destination for recording logical replication conflicts.
+
+
+ The available destinations are:
+
+
+
+ log: Conflict details are recorded in the server log.
+ This is the default behavior.
+ See for details.
+
+
+
+
+ table: The system automatically creates a structured table
+ named pg_conflict_log_<subid> in the
+ pg_conflict schema. This allows for easy querying and
+ analysis of conflicts.
+ See for details.
+
+
+
+ The internal conflict log table is strictly tied to the lifecycle of the
+ subscription or the conflict_log_destination setting. If
+ the subscription is dropped, or if the destination is changed to
+ log, the table and all its recorded conflict data are
+ permanently deleted.
+
+
+ If conflict history may be needed later, back up the conflict log table before
+ it gets removed.
+
+
+
+
+
+ all: Records conflict details to both destinations
+ log and table.
+
+
+
+
+
+
+
copy_data (boolean)