From 194520f80e1cdb71faa055d731450855a1ddb8d1 Mon Sep 17 00:00:00 2001 From: Mike Perham Date: Thu, 9 Feb 2023 17:08:33 -0800 Subject: [ruby/logger] Add Logger#with_level{...} for block-scoped log level. (https://github.com/ruby/logger/pull/85) * Update lib/logger/severity.rb https://github.com/ruby/logger/commit/7aabb0b4aa --- lib/logger.rb | 39 +++++++++++++++++++++------------------ lib/logger/severity.rb | 19 +++++++++++++++++++ test/logger/test_severity.rb | 32 ++++++++++++++++++++++++++++++++ 3 files changed, 72 insertions(+), 18 deletions(-) diff --git a/lib/logger.rb b/lib/logger.rb index 7e4dacc911..acc65ac8bb 100644 --- a/lib/logger.rb +++ b/lib/logger.rb @@ -10,6 +10,7 @@ # # A simple system for logging messages. See Logger for more documentation. +require 'fiber' require 'monitor' require 'rbconfig' @@ -380,7 +381,9 @@ class Logger include Severity # Logging severity threshold (e.g. Logger::INFO). - attr_reader :level + def level + @level_override[Fiber.current] || @level + end # Sets the log level; returns +severity+. # See {Log Level}[rdoc-ref:Logger@Log+Level]. @@ -395,24 +398,23 @@ class Logger # Logger#sev_threshold= is an alias for Logger#level=. # def level=(severity) - if severity.is_a?(Integer) - @level = severity - else - case severity.to_s.downcase - when 'debug' - @level = DEBUG - when 'info' - @level = INFO - when 'warn' - @level = WARN - when 'error' - @level = ERROR - when 'fatal' - @level = FATAL - when 'unknown' - @level = UNKNOWN + @level = Severity.coerce(severity) + end + + # Adjust the log level during the block execution for the current Fiber only + # + # logger.with_level(:debug) do + # logger.debug { "Hello" } + # end + def with_level(severity) + prev, @level_override[Fiber.current] = level, Severity.coerce(severity) + begin + yield + ensure + if prev + @level_override[Fiber.current] = prev else - raise ArgumentError, "invalid log level: #{severity}" + @level_override.delete(Fiber.current) end end end @@ -583,6 +585,7 @@ class Logger self.datetime_format = datetime_format self.formatter = formatter @logdev = nil + @level_override = {} if logdev && logdev != File::NULL @logdev = LogDevice.new(logdev, shift_age: shift_age, shift_size: shift_size, diff --git a/lib/logger/severity.rb b/lib/logger/severity.rb index b38afb7d22..e96fb0d320 100644 --- a/lib/logger/severity.rb +++ b/lib/logger/severity.rb @@ -15,5 +15,24 @@ class Logger FATAL = 4 # An unknown message that should always be logged. UNKNOWN = 5 + + LEVELS = { + "debug" => DEBUG, + "info" => INFO, + "warn" => WARN, + "error" => ERROR, + "fatal" => FATAL, + "unknown" => UNKNOWN, + } + private_constant :LEVELS + + def self.coerce(severity) + if severity.is_a?(Integer) + severity + else + key = severity.to_s.downcase + LEVELS[key] || raise(ArgumentError, "invalid log level: #{severity}") + end + end end end diff --git a/test/logger/test_severity.rb b/test/logger/test_severity.rb index dad63472a6..e1069c8262 100644 --- a/test/logger/test_severity.rb +++ b/test/logger/test_severity.rb @@ -3,6 +3,8 @@ require 'logger' class TestLoggerSeverity < Test::Unit::TestCase + include Logger::Severity + def test_enum logger_levels = Logger.constants levels = ["WARN", "UNKNOWN", "INFO", "FATAL", "DEBUG", "ERROR"] @@ -23,4 +25,34 @@ class TestLoggerSeverity < Test::Unit::TestCase assert(logger.level) == Logger::Severity.const_get(level) end end + + def test_thread_local_level + logger = Logger.new(nil) + logger.level = INFO # default level + other = Logger.new(nil) + other.level = ERROR # default level + + assert_equal(other.level, ERROR) + logger.with_level(:WARN) do + assert_equal(other.level, ERROR) + assert_equal(logger.level, WARN) + + logger.with_level(DEBUG) do # verify reentrancy + assert_equal(logger.level, DEBUG) + + Thread.new do + assert_equal(logger.level, INFO) + logger.with_level(:WARN) do + assert_equal(other.level, ERROR) + assert_equal(logger.level, WARN) + end + assert_equal(logger.level, INFO) + end.join + + assert_equal(logger.level, DEBUG) + end + assert_equal(logger.level, WARN) + end + assert_equal(logger.level, INFO) + end end -- cgit v1.2.3