Skip to content

Add spock.log_verbosity and spock.apply_change_logging GUCs#477

Open
ibrarahmad wants to merge 1 commit into
mainfrom
SPOC-551
Open

Add spock.log_verbosity and spock.apply_change_logging GUCs#477
ibrarahmad wants to merge 1 commit into
mainfrom
SPOC-551

Conversation

@ibrarahmad

@ibrarahmad ibrarahmad commented May 20, 2026

Copy link
Copy Markdown
Contributor

log_verbosity (normal|verbose) promotes spock DEBUG1/DEBUG2 to LOG. apply_change_logging (none|key_only|verbose) emits per-change JSON from the apply worker: action/schema/table/pk/origin/commit_ts in key_only, plus old/new row data in verbose. DDL is logged in both non-none modes. Both GUCs are PGC_SUSET (SET / SIGHUP reload).

TAP coverage in tests/tap/t/044_apply_change_logging.pl - 24/24.

SPOC-551

@coderabbitai

coderabbitai Bot commented May 20, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: d9957c19-748f-46f9-ba56-8a70e0c8ddcf

📥 Commits

Reviewing files that changed from the base of the PR and between 90e60e5 and a64a2eb.

📒 Files selected for processing (9)
  • include/spock.h
  • include/spock_change_log.h
  • src/spock.c
  • src/spock_apply.c
  • src/spock_change_log.c
  • src/spock_common.c
  • src/spock_dependency.c
  • tests/tap/schedule
  • tests/tap/t/044_apply_change_logging.pl
✅ Files skipped from review due to trivial changes (2)
  • src/spock_dependency.c
  • tests/tap/schedule
🚧 Files skipped from review as they are similar to previous changes (4)
  • include/spock_change_log.h
  • include/spock.h
  • src/spock_common.c
  • tests/tap/t/044_apply_change_logging.pl

📝 Walkthrough

Walkthrough

Adds new logging GUCs and public logging APIs, emits JSON change logs for replicated DML and DDL in the apply worker, routes selected debug messages through new macros, and adds TAP coverage for the new behavior.

Changes

Apply Worker Change Logging

Layer / File(s) Summary
Public logging contracts
include/spock.h, include/spock_change_log.h, src/spock.c
Adds public logging enums, macros, and change-log declarations, and registers spock.log_verbosity and spock.apply_change_logging as enum GUCs.
JSON change-log implementation
src/spock_change_log.c
Serializes relation rows and shared header fields into JSON and emits LOG-level records for DML and DDL change events.
Apply worker logging hooks
src/spock_apply.c
Calls the new DML and DDL logging functions from the apply worker after successful row changes and before executing queued SQL.
Debug severity macro adoption
src/spock_common.c, src/spock_dependency.c
Replaces selected DEBUG1 and DEBUG2 ereport levels with the new routed debug macros.
TAP coverage
tests/tap/schedule, tests/tap/t/044_apply_change_logging.pl
Adds the new TAP test to the schedule and checks GUC defaults, logging modes, replicated change logs, and the disabled case.

Poem

🐰 I hopped through logs with JSON light,
and debug carrots gleamed just right.
INSERT, UPDATE, DDL too,
now trail their crumbs in logs anew.
Thump-thump—Spock changes bloom in sight.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 73.68% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: adding the two new Spock GUCs.
Description check ✅ Passed The description matches the implemented GUCs, logging behavior, and test coverage in the change set.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch SPOC-551

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@codacy-production

codacy-production Bot commented May 20, 2026

Copy link
Copy Markdown

Up to standards ✅

🟢 Issues 2 medium

Results:
2 new issues

Category Results
Complexity 2 medium

View in Codacy

🟢 Metrics 42 complexity · 0 duplication

Metric Results
Complexity 42
Duplication 0

View in Codacy

NEW Get contextual insights on your PRs based on Codacy's metrics, along with PR and Jira context, without leaving GitHub. Enable AI reviewer
TIP This summary will be updated as you push new changes.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
tests/tap/t/044_apply_change_logging.pl (1)

20-30: ⚡ Quick win

Add a test case for skipped DML in TRANSDISCARD/SUB_DISABLE modes.

Current coverage is strong for normal apply flow, but it doesn’t assert that skipped DML in exception replay modes does not emit apply-change records. Adding this would close a high-risk gap in logging correctness.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/tap/t/044_apply_change_logging.pl` around lines 20 - 30, Add a new test
in the same TAP file that verifies skipped DML under the TRANSDISCARD and
SUB_DISABLE replay modes does not emit apply-change JSON log records: set
apply_change_logging to key_only (and repeat for verbose), configure
publisher/subscriber, perform DML on the publisher that will be skipped on the
subscriber by triggering TRANSDISCARD and SUB_DISABLE replay behavior, capture
the subscriber server logs (same log-capture helpers used elsewhere in this test
file), and assert that no apply-change JSON lines (those containing
action/schema/table/pk and, for verbose, new row data) are present for the
skipped DML; name the test case clearly (e.g., "skipped DML in
TRANSDISCARD/SUB_DISABLE produces no apply_change_logging records") so it’s easy
to find.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/spock_apply.c`:
- Around line 1414-1416: The apply-change log is emitted even when DML was
intentionally skipped under exception-replay modes TRANSDISCARD/SUB_DISABLE;
update the three spots that call spock_log_apply_change (the INSERT block with
newtup, the UPDATE block with oldtup/newtup, and the DELETE block with oldtup)
to only call spock_log_apply_change when the operation both did not fail and was
actually applied — i.e., change the guard from if (!failed) to if (!failed &&
!<skip-dml-flag>), where <skip-dml-flag> checks the current exception replay
mode (TRANSDISCARD or SUB_DISABLE) or otherwise detects that DML was skipped;
use the existing symbols for those modes so the check reflects the code’s
exception replay state and ensures no “applied change” log is produced for
skipped operations.

---

Nitpick comments:
In `@tests/tap/t/044_apply_change_logging.pl`:
- Around line 20-30: Add a new test in the same TAP file that verifies skipped
DML under the TRANSDISCARD and SUB_DISABLE replay modes does not emit
apply-change JSON log records: set apply_change_logging to key_only (and repeat
for verbose), configure publisher/subscriber, perform DML on the publisher that
will be skipped on the subscriber by triggering TRANSDISCARD and SUB_DISABLE
replay behavior, capture the subscriber server logs (same log-capture helpers
used elsewhere in this test file), and assert that no apply-change JSON lines
(those containing action/schema/table/pk and, for verbose, new row data) are
present for the skipped DML; name the test case clearly (e.g., "skipped DML in
TRANSDISCARD/SUB_DISABLE produces no apply_change_logging records") so it’s easy
to find.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: ebbbe842-5466-4b4d-86ca-e2caf912cda8

📥 Commits

Reviewing files that changed from the base of the PR and between 3886058 and 771775f.

📒 Files selected for processing (10)
  • include/spock.h
  • include/spock_change_log.h
  • src/spock.c
  • src/spock_apply.c
  • src/spock_change_log.c
  • src/spock_common.c
  • src/spock_dependency.c
  • src/spock_sync.c
  • tests/tap/schedule
  • tests/tap/t/044_apply_change_logging.pl

Comment thread src/spock_apply.c
Comment thread src/spock.c
Comment thread src/spock_apply.c
Comment thread src/spock_change_log.c
@mason-sharp mason-sharp changed the title SPOC-551: add spock.log_verbosity and spock.apply_change_logging GUCs Add spock.log_verbosity and spock.apply_change_logging GUCs May 24, 2026
Comment thread src/spock_change_log.c
Comment thread src/spock_apply.c
Comment thread src/spock.c
@danolivo danolivo added the skip-test-nightly Skip this PR in the nightly TAP workflow label May 25, 2026
@ibrarahmad ibrarahmad force-pushed the SPOC-551 branch 2 times, most recently from a374f5e to 66ba3cd Compare June 4, 2026 13:50

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/spock_sync.c (1)

16-16: ⚠️ Potential issue | 🔴 Critical

Fix WIN32 build break: <sys/wait.h> and UNIX-only exec_cmd() appear unguarded in src/spock_sync.c.

  • src/spock_sync.c includes #include <sys/wait.h> in the main include block (no nearby #ifdef WIN32 guards shown), but <sys/wait.h> isn’t available on Windows.
  • The only exec_cmd() implementation visible here is UNIX-oriented (pid_t, fork/exec-style); no WIN32-specific exec_cmd alternative (exec_cmd_win32/CreateProcess) is present in the shown code.

Run on Windows will likely fail at the header include and/or during compilation of the UNIX-only code.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/spock_sync.c` at line 16, The file includes the UNIX-only header
<sys/wait.h> and contains a UNIX-style exec_cmd implementation (uses
pid_t/fork/exec) unguarded, breaking WIN32 builds; wrap the include and the UNIX
exec_cmd implementation in proper platform guards (e.g., `#if` !defined(_WIN32) /
`#endif`) so <sys/wait.h> and the fork/exec-based exec_cmd are only compiled on
POSIX, and provide either a Win32 alternative declaration or call to a
Windows-specific implementation (e.g., exec_cmd_win32/CreateProcess) for _WIN32
builds so compilation on Windows succeeds; update references to exec_cmd to use
the platform-appropriate implementation or a common wrapper function name where
needed.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@src/spock_sync.c`:
- Line 16: The file includes the UNIX-only header <sys/wait.h> and contains a
UNIX-style exec_cmd implementation (uses pid_t/fork/exec) unguarded, breaking
WIN32 builds; wrap the include and the UNIX exec_cmd implementation in proper
platform guards (e.g., `#if` !defined(_WIN32) / `#endif`) so <sys/wait.h> and the
fork/exec-based exec_cmd are only compiled on POSIX, and provide either a Win32
alternative declaration or call to a Windows-specific implementation (e.g.,
exec_cmd_win32/CreateProcess) for _WIN32 builds so compilation on Windows
succeeds; update references to exec_cmd to use the platform-appropriate
implementation or a common wrapper function name where needed.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 09849b26-cd7c-4c9b-93d5-be6a02003286

📥 Commits

Reviewing files that changed from the base of the PR and between 771775f and 6fae92b.

📒 Files selected for processing (5)
  • src/spock_apply.c
  • src/spock_change_log.c
  • src/spock_sync.c
  • tests/tap/schedule
  • tests/tap/t/044_apply_change_logging.pl
✅ Files skipped from review due to trivial changes (1)
  • tests/tap/schedule

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
src/spock_apply.c (1)

2393-2409: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Missing DDL apply-change logs in replay skip modes.

Line 2395 enters the TRANSDISCARD/SUB_DISABLE skip path and bypasses handle_sql(), so the DDL log call at Line 2365 never runs. That drops spock apply change JSON for queued SQL/DDL in exactly the skipped/replay path this feature is meant to expose.

Suggested fix
+/* Extract queued SQL scalar as raw string (shared by execute/skip paths). */
+static char *
+extract_queued_sql(QueuedMessage *queued_message)
+{
+    /* move current JSON scalar validation/extraction logic from handle_sql() here */
+}
+
 static void
 handle_sql(QueuedMessage *queued_message, bool tx_just_started, char **sql)
 {
-    /* Validate the json and extract the SQL string from it. */
-    ...
+    *sql = extract_queued_sql(queued_message);
     spock_log_apply_ddl(*sql, remote_origin_name);
     spock_execute_sql_command(*sql, queued_message->role, tx_just_started);
 }
 
 ...
 if (exception_behaviour == TRANSDISCARD ||
     exception_behaviour == SUB_DISABLE)
 {
-    sql = JsonbToCString(NULL, &queued_message->message->root, 0);
+    sql = extract_queued_sql(queued_message);
+    spock_log_apply_ddl(sql, remote_origin_name);
     exception_command_counter++;
     failed = false;
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/spock_apply.c` around lines 2393 - 2409, When exception_behaviour is
TRANSDISCARD or SUB_DISABLE the current branch extracts sql with JsonbToCString
and skips calling handle_sql(), which prevents emitting the DDL "spock apply
change" log; modify the TRANSDISCARD/SUB_DISABLE branch in spock_apply.c so
after sql = JsonbToCString(...) and before incrementing
exception_command_counter/setting failed you invoke the same logging path used
in the normal apply path (i.e. emit the apply-change JSON/log entry for
queued_message->message and sql) — mirror the log call that handle_sql() or the
code at the earlier log site uses so skipped/replay DDL still gets recorded
while keeping the skip behavior for execution. Ensure you reference
MyApplyWorker->use_try_block, exception_behaviour, TRANSDISCARD, SUB_DISABLE,
JsonbToCString, queued_message, exception_command_counter and failed in the
change.
src/spock_sync.c (1)

16-16: ⚠️ Potential issue | 🔴 Critical

Potential Windows build break: unguarded <sys/wait.h> + fork()/waitpid() in src/spock_sync.c

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/spock_sync.c` at line 16, The unguarded `#include` <sys/wait.h> and use of
POSIX APIs (fork(), waitpid()) in src/spock_sync.c will break Windows builds;
wrap the include and any code that calls fork()/waitpid() in platform checks
(e.g. `#if` !defined(_WIN32) || defined(HAVE_SYS_WAIT_H) ... `#endif`) and provide a
Windows-safe alternative or stub for the spock sync path (use
CreateProcess/WaitForSingleObject or return a clear "not supported on Windows"
error). Specifically, guard the <sys/wait.h> include and all occurrences of
fork() and waitpid() so Windows compiles, or add `#ifdef` _WIN32 branches that
implement equivalent behavior or disable the feature.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@src/spock_apply.c`:
- Around line 2393-2409: When exception_behaviour is TRANSDISCARD or SUB_DISABLE
the current branch extracts sql with JsonbToCString and skips calling
handle_sql(), which prevents emitting the DDL "spock apply change" log; modify
the TRANSDISCARD/SUB_DISABLE branch in spock_apply.c so after sql =
JsonbToCString(...) and before incrementing exception_command_counter/setting
failed you invoke the same logging path used in the normal apply path (i.e. emit
the apply-change JSON/log entry for queued_message->message and sql) — mirror
the log call that handle_sql() or the code at the earlier log site uses so
skipped/replay DDL still gets recorded while keeping the skip behavior for
execution. Ensure you reference MyApplyWorker->use_try_block,
exception_behaviour, TRANSDISCARD, SUB_DISABLE, JsonbToCString, queued_message,
exception_command_counter and failed in the change.

In `@src/spock_sync.c`:
- Line 16: The unguarded `#include` <sys/wait.h> and use of POSIX APIs (fork(),
waitpid()) in src/spock_sync.c will break Windows builds; wrap the include and
any code that calls fork()/waitpid() in platform checks (e.g. `#if`
!defined(_WIN32) || defined(HAVE_SYS_WAIT_H) ... `#endif`) and provide a
Windows-safe alternative or stub for the spock sync path (use
CreateProcess/WaitForSingleObject or return a clear "not supported on Windows"
error). Specifically, guard the <sys/wait.h> include and all occurrences of
fork() and waitpid() so Windows compiles, or add `#ifdef` _WIN32 branches that
implement equivalent behavior or disable the feature.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 5980fd5a-34c1-424f-b966-4660e1f83bc9

📥 Commits

Reviewing files that changed from the base of the PR and between 6fae92b and 66ba3cd.

📒 Files selected for processing (5)
  • src/spock_apply.c
  • src/spock_change_log.c
  • src/spock_sync.c
  • tests/tap/schedule
  • tests/tap/t/044_apply_change_logging.pl
🚧 Files skipped from review as they are similar to previous changes (1)
  • tests/tap/t/044_apply_change_logging.pl

@rasifr rasifr left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • Although I still favor single GUC, even accepting two separate GUCs, the new SPOCK_DEBUG1/SPOCK_DEBUG2 macros are unnecessary complexity. Every existing ereport(DEBUG1/2, …) is already gated by log_min_messages — that is exactly the mechanism Postgres provides for controlling what debug output reaches the log. Wrapping that with a spock-specific level macro that duplicates the concept adds indirection without adding capability.
    If the goal is to promote spock debug messages to LOG without touching log_min_messages globally, the GUC alone can do that at the call site with a simple helper function.

  • spock_jsonb_utils.c already provides spock_tuple_to_json_cstring() — the same conceptual operation this PR implements again in append_row_json. The right approach is to extend spock_jsonb_utils.c to cover the additional requirements (such as PK-only filtering etc) rather than introduce a parallel set of JSON helpers in a new file.

  • The removal of the entire Win32 exec_cmd path (~324 lines) and the PG_VERSION_NUM guard change from >= 180000 to >= 170000 for build_exclude_extension_string have no connection to the GUC feature being added here. These should be in a separate PR

@mason-sharp

Copy link
Copy Markdown
Member
  • Although I still favor single GUC, even accepting two separate GUCs, the new SPOCK_DEBUG1/SPOCK_DEBUG2 macros are unnecessary complexity. Every existing ereport(DEBUG1/2, …) is already gated by log_min_messages — that is exactly the mechanism Postgres provides for controlling what debug output reaches the log. Wrapping that with a spock-specific level macro that duplicates the concept adds indirection without adding capability.
    If the goal is to promote spock debug messages to LOG without touching log_min_messages globally, the GUC alone can do that at the call site with a simple helper function.

OK, now I understand what you meant. spock.apply_change_logging could promote to LOG if the mode is not NONE. @ibrarahmad what do you think?

  • spock_jsonb_utils.c already provides spock_tuple_to_json_cstring() — the same conceptual operation this PR implements again in append_row_json. The right approach is to extend spock_jsonb_utils.c to cover the additional requirements (such as PK-only filtering etc) rather than introduce a parallel set of JSON helpers in a new file.

@ibrarahmad I agree with Asif.

  • The removal of the entire Win32 exec_cmd path (~324 lines) and the PG_VERSION_NUM guard change from >= 180000 to >= 170000 for build_exclude_extension_string have no connection to the GUC feature being added here. These should be in a separate PR

I think he just needs to rebase, that was already removed.

log_verbosity (normal|verbose) promotes spock DEBUG1/DEBUG2 to LOG.
apply_change_logging (none|key_only|verbose) emits per-change JSON
from the apply worker: action/schema/table/pk/origin/commit_ts in
key_only, plus old/new row data in verbose.  DDL is logged in both
non-none modes.  Both GUCs are PGC_SUSET (SET / SIGHUP reload).

TAP coverage in tests/tap/t/044_apply_change_logging.pl - 24/24.
@mason-sharp

Copy link
Copy Markdown
Member

Gave this a rebase because of the extra windows code removal changes

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

6.0 skip-test-nightly Skip this PR in the nightly TAP workflow

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants