Skip to content

feat: add thread-local logging support for parallel test isolation#485

Merged
xdustinface merged 1 commit intov0.42-devfrom
feat/thread-local-logging
Mar 3, 2026
Merged

feat: add thread-local logging support for parallel test isolation#485
xdustinface merged 1 commit intov0.42-devfrom
feat/thread-local-logging

Conversation

@xdustinface
Copy link
Collaborator

@xdustinface xdustinface commented Feb 28, 2026

This is to allow independent logging in integration tests. Adds a thread_local flag to LoggingConfig that uses tracing::subscriber::set_default (thread-local) instead of try_init (global). This allows multiple independent loggers in the same process, primarily for parallel tests where each test needs its own log subscriber. The LoggingGuard now holds an optional DefaultGuard to keep the thread-local subscriber alive. Additionally, the FFI client's tokio runtime builder propagates the caller's tracing dispatcher to worker threads via on_thread_start, so spawned async tasks capture logs through the correct subscriber.

Summary by CodeRabbit

Release Notes

  • Bug Fixes
    • Improved logging behavior in worker threads and async operations with proper thread isolation.

Adds a `thread_local` flag to `LoggingConfig` that uses `tracing::subscriber::set_default` (thread-local) instead of `try_init` (global). This allows multiple independent loggers in the same process, primarily for parallel tests where each test needs its own log subscriber. The `LoggingGuard` now holds an optional `DefaultGuard` to keep the thread-local subscriber alive. Additionally, the FFI client's tokio runtime builder propagates the caller's tracing dispatcher to worker threads via `on_thread_start`, so spawned async tasks capture logs through the correct subscriber.
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 28, 2026

📝 Walkthrough

Walkthrough

The changes introduce thread-local logging support to enable proper log isolation for async tasks spawned on worker threads. A new thread_local boolean field is added to LoggingConfig and LoggingGuard to conditionally initialize either thread-local or global subscribers, with worker threads now propagating the caller's tracing dispatch.

Changes

Cohort / File(s) Summary
Logging Configuration
dash-spv/src/logging.rs, dash-spv-ffi/src/utils.rs, dash-spv/src/main.rs
Added thread_local: bool field to LoggingConfig struct and updated initialization sites to explicitly set the flag. LoggingGuard now carries an optional DefaultGuard to keep thread-local subscriber scope alive. Conditional logic chooses between set_default (thread-local) and try_init (global) modes.
Worker Thread Tracing
dash-spv-ffi/src/client.rs
Propagates the caller's tracing dispatcher to worker threads by capturing the global dispatch via get_default and re-setting it on each thread startup via on_thread_start. Intentionally leaks the dispatch guard to preserve dispatcher across thread lifecycle.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 A patch of perfect threading,
Logs now dance in isolation,
Worker threads receive their dispatch,
Tracing follows—no frustration!
Thread-local magic blooms anew.

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: adding thread-local logging support for parallel test isolation, which is the primary objective of this PR.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

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

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/thread-local-logging

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 and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

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)
dash-spv/src/logging.rs (1)

149-156: Add regression tests for the new thread_local branch.

Please add tests that exercise init_logging with thread_local: true (including guard drop/restoration behavior) to prevent subtle regressions in scoped subscriber handling.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@dash-spv/src/logging.rs` around lines 149 - 156, Add regression tests that
cover the new thread_local branch in init_logging: write tests that call
init_logging with config.thread_local = true, verify that
set_default(subscriber) is used (observe return of default_guard), and exercise
guard drop/restoration behavior by dropping the guard and ensuring the previous
global subscriber is restored or logging behavior reverts accordingly;
specifically target the init_logging function and the thread_local handling
around set_default and default_guard to assert correct scoped subscriber
behavior and prevent regressions.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@dash-spv-ffi/src/client.rs`:
- Around line 11-13: Replace the forget(guard) pattern with a thread-local
storage for the dispatcher guard: create a thread_local! static (e.g.
DISPATCHER_GUARD: std::cell::RefCell<Option<tracing::dispatcher::DefaultGuard>>)
and, after calling set_default(...), store the returned guard into
DISPATCHER_GUARD.with(|c| *c.borrow_mut() = Some(guard)); remove the use of
std::mem::forget and keep get_default/set_default imports; this preserves the
DefaultGuard for the lifetime of the thread so its Drop will restore the
previous dispatcher when the thread exits.

---

Nitpick comments:
In `@dash-spv/src/logging.rs`:
- Around line 149-156: Add regression tests that cover the new thread_local
branch in init_logging: write tests that call init_logging with
config.thread_local = true, verify that set_default(subscriber) is used (observe
return of default_guard), and exercise guard drop/restoration behavior by
dropping the guard and ensuring the previous global subscriber is restored or
logging behavior reverts accordingly; specifically target the init_logging
function and the thread_local handling around set_default and default_guard to
assert correct scoped subscriber behavior and prevent regressions.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2824e52 and 947c08c.

📒 Files selected for processing (4)
  • dash-spv-ffi/src/client.rs
  • dash-spv-ffi/src/utils.rs
  • dash-spv/src/logging.rs
  • dash-spv/src/main.rs

@xdustinface xdustinface requested a review from ZocoLini February 28, 2026 01:39
@xdustinface xdustinface merged commit aa85b87 into v0.42-dev Mar 3, 2026
53 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants