Skip to content

Fix broadcast logger patch#25

Open
wpliao1989 wants to merge 3 commits intomainfrom
wl-FixBroadcastLoggerPatch
Open

Fix broadcast logger patch#25
wpliao1989 wants to merge 3 commits intomainfrom
wl-FixBroadcastLoggerPatch

Conversation

@wpliao1989
Copy link
Collaborator

Fix duplicate logging in Rails 7.1+

Summary

  • Fixes duplicate log lines caused by Rails 7.1's BroadcastLogger wrapping custom loggers
  • Prevents broadcast_to from adding additional log destinations that cause double logging
  • Fixes timing issue where the broadcast_to no-op was applied too late (in after_initialize) allowing gems like Sidekiq to add duplicate loggers before the fix was in place

Problem

In Rails 7.1+, the bootstrap process wraps custom loggers (like the logging gem) in an ActiveSupport::BroadcastLogger:

# rails/railties/lib/rails/application/bootstrap.rb
broadcast_logger = ActiveSupport::BroadcastLogger.new(Rails.logger)
Rails.logger = broadcast_logger

Then various components call Rails.logger.broadcast_to() to add additional log destinations:

  • Rails server (log_to_stdout) - adds console logger in development
  • Rails console - adds STDERR logger
  • Sidekiq - adds Sidekiq.logger as a broadcast sink
  • ActiveRecord railtie - adds console logger

This causes:

  1. Duplicate log lines - each log message is written once per broadcast sink
  2. Double block execution - BroadcastLogger#method_missing calls methods like with_context on each sink, executing the block multiple times

Solution

Add an initializer that runs after :initialize_logger (when the BroadcastLogger is created) but before any after_initialize hooks (where Sidekiq and others add their loggers):

initializer 'epilog.prevent_broadcast', after: :initialize_logger do
  if ::Rails.gem_version >= Gem::Version.new('7.1') && ::Rails.logger
    ::Rails.logger.define_singleton_method(:broadcast_to) { |*| nil }
  end
end

This ensures the no-op broadcast_to is in place before any gem can add duplicate destinations.

Timeline Comparison

Before (broken):

1. :initialize_logger → Rails wraps logger in BroadcastLogger
2. after_initialize hooks run:
   - Sidekiq calls broadcast_to → ADDS LOGGER ❌
   - Epilog adds no-op → too late!

After (fixed):

1. :initialize_logger → Rails wraps logger in BroadcastLogger
2. epilog.prevent_broadcast → adds no-op broadcast_to ✓
3. after_initialize hooks run:
   - Sidekiq calls broadcast_to → NO-OP (blocked) ✓

@wpliao1989 wpliao1989 force-pushed the wl-FixBroadcastLoggerPatch branch from ddad8e4 to cac7ee8 Compare February 13, 2026 00: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.

1 participant