Fix logger silencing for broadcasted loggers
Fix #23609 Commit 629efb6 introduced thread safety to logger silencing but it didn't take into account the fact that the logger can be extended with broadcasting to other logger. This commit introduces local_level to broadcasting Module which enables broadcasted loggers to be properly silenced.
This commit is contained in:
parent
8a84f1c047
commit
2518bda97c
@ -1,8 +1,10 @@
|
||||
require 'active_support/logger_silence'
|
||||
require 'active_support/logger_thread_safe_level'
|
||||
require 'logger'
|
||||
|
||||
module ActiveSupport
|
||||
class Logger < ::Logger
|
||||
include ActiveSupport::LoggerThreadSafeLevel
|
||||
include LoggerSilence
|
||||
|
||||
# Returns true if the logger destination matches one of the sources
|
||||
@ -48,6 +50,11 @@ def self.broadcast(logger) # :nodoc:
|
||||
logger.level = level
|
||||
super(level)
|
||||
end
|
||||
|
||||
define_method(:local_level=) do |level|
|
||||
logger.local_level = level if logger.respond_to?(:local_level=)
|
||||
super(level) if respond_to?(:local_level=)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -7,39 +7,22 @@ module LoggerSilence
|
||||
|
||||
included do
|
||||
cattr_accessor :silencer
|
||||
attr_reader :local_levels
|
||||
self.silencer = true
|
||||
end
|
||||
|
||||
def after_initialize
|
||||
@local_levels = Concurrent::Map.new(:initial_capacity => 2)
|
||||
end
|
||||
|
||||
def local_log_id
|
||||
Thread.current.__id__
|
||||
end
|
||||
|
||||
def level
|
||||
local_levels[local_log_id] || super
|
||||
end
|
||||
|
||||
# Silences the logger for the duration of the block.
|
||||
def silence(temporary_level = Logger::ERROR)
|
||||
if silencer
|
||||
begin
|
||||
old_local_level = local_levels[local_log_id]
|
||||
local_levels[local_log_id] = temporary_level
|
||||
old_local_level = local_level
|
||||
self.local_level = temporary_level
|
||||
|
||||
yield self
|
||||
ensure
|
||||
if old_local_level
|
||||
local_levels[local_log_id] = old_local_level
|
||||
else
|
||||
local_levels.delete(local_log_id)
|
||||
end
|
||||
self.local_level = old_local_level
|
||||
end
|
||||
else
|
||||
yield self
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
31
activesupport/lib/active_support/logger_thread_safe_level.rb
Normal file
31
activesupport/lib/active_support/logger_thread_safe_level.rb
Normal file
@ -0,0 +1,31 @@
|
||||
require 'active_support/concern'
|
||||
|
||||
module ActiveSupport
|
||||
module LoggerThreadSafeLevel
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
def after_initialize
|
||||
@local_levels = Concurrent::Map.new(:initial_capacity => 2)
|
||||
end
|
||||
|
||||
def local_log_id
|
||||
Thread.current.__id__
|
||||
end
|
||||
|
||||
def local_level
|
||||
@local_levels[local_log_id]
|
||||
end
|
||||
|
||||
def local_level=(level)
|
||||
if level
|
||||
@local_levels[local_log_id] = level
|
||||
else
|
||||
@local_levels.delete(local_log_id)
|
||||
end
|
||||
end
|
||||
|
||||
def level
|
||||
local_level || super
|
||||
end
|
||||
end
|
||||
end
|
@ -141,6 +141,50 @@ def test_silencing_everything_but_errors
|
||||
assert @output.string.include?("THIS IS HERE")
|
||||
end
|
||||
|
||||
def test_logger_silencing_works_for_broadcast
|
||||
another_output = StringIO.new
|
||||
another_logger = Logger.new(another_output)
|
||||
|
||||
@logger.extend Logger.broadcast(another_logger)
|
||||
|
||||
@logger.debug "CORRECT DEBUG"
|
||||
@logger.silence do
|
||||
@logger.debug "FAILURE"
|
||||
@logger.error "CORRECT ERROR"
|
||||
end
|
||||
|
||||
assert @output.string.include?("CORRECT DEBUG")
|
||||
assert @output.string.include?("CORRECT ERROR")
|
||||
assert_not @output.string.include?("FAILURE")
|
||||
|
||||
assert another_output.string.include?("CORRECT DEBUG")
|
||||
assert another_output.string.include?("CORRECT ERROR")
|
||||
assert_not another_output.string.include?("FAILURE")
|
||||
end
|
||||
|
||||
def test_broadcast_silencing_does_not_break_plain_ruby_logger
|
||||
another_output = StringIO.new
|
||||
another_logger = ::Logger.new(another_output)
|
||||
|
||||
@logger.extend Logger.broadcast(another_logger)
|
||||
|
||||
@logger.debug "CORRECT DEBUG"
|
||||
@logger.silence do
|
||||
@logger.debug "FAILURE"
|
||||
@logger.error "CORRECT ERROR"
|
||||
end
|
||||
|
||||
assert @output.string.include?("CORRECT DEBUG")
|
||||
assert @output.string.include?("CORRECT ERROR")
|
||||
assert_not @output.string.include?("FAILURE")
|
||||
|
||||
assert another_output.string.include?("CORRECT DEBUG")
|
||||
assert another_output.string.include?("CORRECT ERROR")
|
||||
assert another_output.string.include?("FAILURE")
|
||||
# We can't silence plain ruby Logger cause with thread safety
|
||||
# but at least we don't break it
|
||||
end
|
||||
|
||||
def test_logger_level_per_object_thread_safety
|
||||
logger1 = Logger.new(StringIO.new)
|
||||
logger2 = Logger.new(StringIO.new)
|
||||
|
Loading…
Reference in New Issue
Block a user