Add ActionController::Base.log_at

Allow setting a different log level per request.
This commit is contained in:
George Claghorn 2019-09-24 13:47:34 -04:00 committed by GitHub
parent 29be48f5a5
commit 75a53297c7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 126 additions and 16 deletions

View File

@ -1,3 +1,14 @@
* `ActionController::Base.log_at` allows setting a different log level per request.
```ruby
# Use the debug level if a particular cookie is set.
class ApplicationController < ActionController::Base
log_at :debug, if: -> { cookies[:debug] }
end
```
*George Claghorn*
* Allow system test screen shots to be taken more than once in
a test by prefixing the file name with an incrementing counter.

View File

@ -39,6 +39,7 @@ module ActionController
autoload :BasicImplicitRender
autoload :ImplicitRender
autoload :Instrumentation
autoload :Logging
autoload :MimeResponds
autoload :ParamsWrapper
autoload :Redirecting

View File

@ -123,6 +123,7 @@ module ActionController
ForceSSL,
DataStreaming,
DefaultHeaders,
Logging,
# Before callbacks should also be executed as early as possible, so
# also include them at the bottom.

View File

@ -234,6 +234,7 @@ module ActionController
HttpAuthentication::Digest::ControllerMethods,
HttpAuthentication::Token::ControllerMethods,
DefaultHeaders,
Logging,
# Before callbacks should also be executed as early as possible, so
# also include them at the bottom.

View File

@ -0,0 +1,20 @@
# frozen_string_literal: true
module ActionController
module Logging
extend ActiveSupport::Concern
module ClassMethods
# Set a different log level per request.
#
# # Use the debug log level if a particular cookie is set.
# class ApplicationController < ActionController::Base
# log_at :debug, if: -> { cookies[:debug] }
# end
#
def log_at(level, **options)
around_action ->(_, action) { logger.log_at(level, &action) }, **options
end
end
end
end

View File

@ -0,0 +1,39 @@
# frozen_string_literal: true
require "abstract_unit"
class LoggingTest < ActionController::TestCase
class TestController < ActionController::Base
log_at :debug, if: -> { params[:level] == "debug" }
log_at :warn, if: -> { params[:level] == "warn" }
def show
render plain: logger.level
end
end
tests TestController
setup do
@logger = @controller.logger = ActiveSupport::Logger.new(nil, level: Logger::INFO)
end
test "logging at the default level" do
get :show
assert_equal Logger::INFO.to_s, response.body
end
test "logging at a noisier level per request" do
assert_no_changes -> { @logger.level } do
get :show, params: { level: "debug" }
assert_equal Logger::DEBUG.to_s, response.body
end
end
test "logging at a quieter level per request" do
assert_no_changes -> { @logger.level } do
get :show, params: { level: "warn" }
assert_equal Logger::WARN.to_s, response.body
end
end
end

View File

@ -27,19 +27,8 @@ module ActiveSupport
end
# Silences the logger for the duration of the block.
def silence(temporary_level = Logger::ERROR)
if silencer
begin
old_local_level = local_level
self.local_level = temporary_level
yield self
ensure
self.local_level = old_local_level
end
else
yield self
end
def silence(severity = Logger::ERROR)
silencer ? log_at(severity) { yield self } : yield(self)
end
end
end

View File

@ -37,10 +37,15 @@ module ActiveSupport
end
def local_level=(level)
if level
case level
when Integer
self.class.local_levels[local_log_id] = level
else
when Symbol
self.class.local_levels[local_log_id] = Logger::Severity.const_get(level.to_s.upcase)
when nil
self.class.local_levels.delete(local_log_id)
else
raise ArgumentError, "Invalid log level: #{level.inspect}"
end
end
@ -48,9 +53,17 @@ module ActiveSupport
local_level || super
end
# Change the thread-local level for the duration of the given block.
def log_at(level)
old_local_level, self.local_level = local_level, level
yield
ensure
self.local_level = old_local_level
end
# Redefined to check severity against #level, and thus the thread-local level, rather than +@level+.
# FIXME: Remove when the minimum Ruby version supports overriding Logger#level.
def add(severity, message = nil, progname = nil, &block) # :nodoc:
def add(severity, message = nil, progname = nil, &block) #:nodoc:
severity ||= UNKNOWN
progname ||= @progname

View File

@ -315,6 +315,41 @@ class LoggerTest < ActiveSupport::TestCase
assert_level(Logger::INFO)
end
def test_temporarily_logging_at_a_noisier_level
@logger.level = Logger::INFO
@logger.debug "NOT THERE"
@logger.log_at Logger::DEBUG do
@logger.debug "THIS IS HERE"
end
@logger.debug "NOT THERE"
assert_not_includes @output.string, "NOT THERE"
assert_includes @output.string, "THIS IS HERE"
end
def test_temporarily_logging_at_a_quieter_level
@logger.log_at Logger::ERROR do
@logger.debug "NOT THERE"
@logger.error "THIS IS HERE"
end
assert_not_includes @output.string, "NOT THERE"
assert_includes @output.string, "THIS IS HERE"
end
def test_temporarily_logging_at_a_symbolic_level
@logger.log_at :error do
@logger.debug "NOT THERE"
@logger.error "THIS IS HERE"
end
assert_not_includes @output.string, "NOT THERE"
assert_includes @output.string, "THIS IS HERE"
end
private
def level_name(level)
::Logger::Severity.constants.find do |severity|