Skip to content

Conversation

@mensfeld
Copy link
Collaborator

@mensfeld mensfeld commented Dec 11, 2025

Summary

This PR is a revised implementation of #765 by @ioquatix, addressing the need for fiber-local logging context in async environments.

The Problem

In fiber-based environments (Async gem, Falcon web server, etc.), multiple fibers can run on the same thread. Thread-local storage (Thread.current[:shoryuken_context]) causes context to "leak" between fibers, resulting in incorrect log messages.

Changes

  • Use Fiber[] storage (Ruby 3.2+) instead of Thread.current[] for logging context
  • Fall back to Thread.current for older Ruby versions (maintains backward compatibility)
  • Fix nested context handling (original PR Scope the shoryuken context to the current fiber. #765 always set to nil in ensure, destroying outer context)
  • Add Shoryuken::Logging.current_context method for direct context access
  • Add Shoryuken::Logging.context_storage method to get the appropriate storage backend

Key Improvements over PR #765

  1. No monkey-patching: Uses Ruby 3.2+'s native Fiber[] and Fiber[]= instead of adding attr_accessor to Fiber
  2. Nested context support: Properly saves and restores previous context in ensure block
  3. Backward compatible: Falls back to Thread-local storage on Ruby < 3.2

Code Example

# Before (Thread-local - context leaks between fibers)
def self.with_context(msg)
  Thread.current[:shoryuken_context] = msg
  yield
ensure
  Thread.current[:shoryuken_context] = nil
end

# After (Fiber-local with proper nesting)
def self.with_context(msg)
  previous = context_storage[:shoryuken_context]
  context_storage[:shoryuken_context] = msg
  yield
ensure
  context_storage[:shoryuken_context] = previous
end

Test plan

  • All existing logging tests pass
  • Added tests for nested context preservation
  • Added tests for current_context and context_storage methods
  • Full test suite passes (478 examples, 0 failures)
  • CI passes

Ref #765

cc @ioquatix - would love your feedback on this approach!

Summary by CodeRabbit

  • Improvements
    • Logging context now uses fiber-local storage on Ruby 3.2+, improving isolation in async environments and preserving nested-context restoration semantics.
  • Documentation
    • Changelog updated to describe fiber-local context behavior and Ruby 3.2+ usage.
  • Tests
    • Expanded tests covering context presence/absence, nested contexts, exception restoration, and storage behavior.

✏️ Tip: You can customize this high-level summary in your review settings.

Change logging context from Thread-local to Fiber-local storage to
properly support fiber-based/async environments (e.g., Async gem,
Falcon web server).

Key improvements over the original PR #765:
- Uses Ruby 3.2+ native Fiber[] storage instead of monkey-patching Fiber
- Falls back to Thread.current for older Ruby versions
- Properly preserves outer context in nested with_context calls
- Adds current_context and context_storage public methods

This prevents context "leaking" between fibers running on the same thread,
which was causing incorrect log messages in async environments.

Ref #765
@coderabbitai
Copy link

coderabbitai bot commented Dec 11, 2025

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Walkthrough

Refactors logging context storage from thread-local to fiber-local storage on Ruby 3.2+ (with thread-local fallback), adding public accessors current_context and context_storage, and updating with_context and formatters to use the new storage API while preserving prior public behavior.

Changes

Cohort / File(s) Summary
Core logging context storage refactoring
lib/shoryuken/logging.rb
Adds context_storage accessor (uses Fiber-based storage on Ruby 3.2+ with Thread fallback), adds current_context, and updates with_context to save/restore via the new storage.
Context retrieval integration
lib/shoryuken/logging/base.rb
Replaces direct Thread.current[:shoryuken_context] reads with Shoryuken::Logging.current_context in formatter context logic.
Test suite updates
spec/lib/shoryuken/logging_spec.rb
Replaces direct thread-local access with context_storage/current_context in tests, adds cleanup hooks, and expands tests for nested contexts, exception restoration, and storage behavior.
Changelog
CHANGELOG.md
Documents the change to fiber-local logging context storage and notes Ruby 3.2+ behavior.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20–25 minutes

  • Review context_storage detection logic (Fiber API detection and Thread fallback).
  • Verify with_context save/restore semantics for nested calls and exceptions in lib/shoryuken/logging.rb.
  • Confirm current_context usage in lib/shoryuken/logging/base.rb preserves formatting behavior and nil handling.
  • Review updated tests in spec/lib/shoryuken/logging_spec.rb for proper cleanup and coverage.

Possibly related PRs

Poem

🐇 I hop through fibers, light and fleet,
Holding context snug and neat.
Nested nooks restored with care,
No cross-talk drifting in the air.
A joyful thump — logs safe, complete!

Pre-merge checks and finishing touches

✅ 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 summarizes the main change: migrating from thread-local to fiber-local storage for logging context with Ruby 3.2+ support.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fiber-local-logging-context

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

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR updates Shoryuken's logging context management to use fiber-local storage (Ruby 3.2+) instead of thread-local storage, addressing context leakage issues in async/fiber-based environments. The implementation maintains backward compatibility with older Ruby versions and fixes nested context handling.

Key changes:

  • Replace Thread.current[] with Fiber[] for logging context storage on Ruby 3.2+
  • Implement proper nested context preservation by saving/restoring previous values instead of setting to nil
  • Add current_context and context_storage helper methods for accessing context state

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

File Description
lib/shoryuken/logging.rb Implements fiber-local storage with fallback to thread-local, adds context helper methods, and fixes nested context handling
lib/shoryuken/logging/base.rb Updates context retrieval to use new current_context method instead of direct thread-local access
spec/lib/shoryuken/logging_spec.rb Updates tests to use new context storage API and adds comprehensive tests for nested context preservation

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

mensfeld and others added 2 commits December 13, 2025 17:03
Since shoryuken requires Ruby >= 3.2.0, the fallback to Thread.current
for older Ruby versions is dead code. Fiber[] and Fiber[]= are always
available in supported Ruby versions.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Copy link

@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: 0

🧹 Nitpick comments (2)
spec/lib/shoryuken/logging_spec.rb (1)

27-29: Make context cleanup restore the previous value (not force nil).
Right now the after hooks can clobber a context that existed before the example ran (reduces spec isolation).

- after do
-   Shoryuken::Logging.context_storage[:shoryuken_context] = nil
- end
+ around do |ex|
+   storage  = Shoryuken::Logging.context_storage
+   previous = storage[:shoryuken_context]
+   storage[:shoryuken_context] = nil
+   ex.run
+ ensure
+   storage[:shoryuken_context] = previous
+ end

Also applies to: 48-50, 74-76, 97-99, 158-160

CHANGELOG.md (1)

2-6: Tighten changelog entry: format API names + add PR reference + clarify fallback/min-Ruby.
Consider using backticks (e.g., Fiber[]) and referencing PR #920; also clarify whether Thread fallback exists or if Ruby 3.2+ is required here (to avoid mixed messaging).

-- Enhancement: Use fiber-local storage for logging context
-  - Replaces thread-local storage with Fiber[] for proper isolation in async environments
+- Enhancement: Use fiber-local storage for logging context (#920)
+  - Replaces thread-local storage with `Fiber[]` for proper isolation in async environments
   - Ensures logging context doesn't leak between fibers in the same thread
-  - Leverages Ruby 3.2+ fiber-local storage API
+  - Leverages Ruby 3.2+ fiber-local storage API (with Thread fallback where applicable)
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 062a918 and 4fb17f9.

📒 Files selected for processing (3)
  • CHANGELOG.md (1 hunks)
  • lib/shoryuken/logging.rb (1 hunks)
  • spec/lib/shoryuken/logging_spec.rb (6 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • lib/shoryuken/logging.rb
🧰 Additional context used
🧬 Code graph analysis (1)
spec/lib/shoryuken/logging_spec.rb (2)
lib/shoryuken/logging.rb (3)
  • context_storage (38-40)
  • with_context (19-25)
  • current_context (30-32)
lib/shoryuken/logging/base.rb (1)
  • context (20-23)
🪛 ast-grep (0.40.0)
spec/lib/shoryuken/logging_spec.rb

[warning] 81-81: Found the use of an hardcoded passphrase for RSA. The passphrase can be easily discovered, and therefore should not be stored in source-code. It is recommended to remove the passphrase from source-code, and use system environment variables or a restricted configuration file.
Context: formatter.call('DEBUG', Time.now, 'program', 'debug message')
Note: [CWE-798]: Use of Hard-coded Credentials [OWASP A07:2021]: Identification and Authentication Failures [REFERENCES]
https://cwe.mitre.org/data/definitions/522.html

(hardcoded-secret-rsa-passphrase-ruby)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
  • GitHub Check: Integrations (3.4)
  • GitHub Check: Integrations (3.3)
  • GitHub Check: Integrations (3.2)
  • GitHub Check: Integrations (3.3)
  • GitHub Check: Integrations (3.4)
  • GitHub Check: Integrations (3.2)
🔇 Additional comments (3)
spec/lib/shoryuken/logging_spec.rb (3)

131-155: Nested context coverage (including inner exception) looks solid.
The outer restoration assertions match the new ensure-based behavior.


172-175: Avoid hard-coding Fiber in the spec if Thread fallback is supported.
If the library truly falls back on Ruby < 3.2 (per PR description), this expectation should be version-gated or behavior-based.

- expect(described_class.context_storage).to eq(Fiber)
+ if Fiber.respond_to?(:[])
+   expect(described_class.context_storage).to eq(Fiber)
+ else
+   expect(described_class.context_storage).to eq(Thread.current)
+ end

Alternatively, assert the storage API contract instead:

storage = described_class.context_storage
expect(storage).to respond_to(:[])
expect(storage).to respond_to(:[]=)

81-83: Ignore static-analysis “hardcoded RSA passphrase” warning here (false positive).
This is a log message string, not a credential.

@mensfeld mensfeld merged commit 4b11bd3 into main Dec 13, 2025
17 checks passed
@mensfeld mensfeld deleted the fiber-local-logging-context branch December 13, 2025 16:10
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