How can I disable logging in Ruby on Rails on a per-action basis?
The following works with at least Rails 3.1.0:
Make a custom logger that can be silenced:
# selective_logger.rb
class SelectiveLogger < Rails::Rack::Logger
def initialize app, opts = {}
@app = app
@opts = opts
@opts[:silenced] ||= []
end
def call env
if @opts[:silenced].include?(env['PATH_INFO']) || @opts[:silenced].any? {|silencer| silencer.is_a?( Regexp) && silencer.match( env['PATH_INFO']) }
Rails.logger.silence do
@app.call env
end
else
super env
end
end
end
Tell Rails to use it:
# application.rb
config.middleware.swap Rails::Rack::Logger, SelectiveLogger, :silenced => ["/remote/every_minute", %r"^/assets/"]
The example above shows silencing asset serving requests, which in the development environment means less ( and sometimes no) scrolling back is required to see the actual request.
You can silence the Rails logger object:
def action
Rails.logger.silence do
# Things within this block will not be logged...
end
end
Use lograge
gem.
Gemfile:
gem 'lograge'
config/application.rb:
config.lograge.enabled = true
config.lograge.ignore_actions = ['StatusController#nginx', ...]
The answer turns out to be a lot harder than I expected, since rails really does provide no hook to do this. Instead, you need to wrap some of the guts of ActionController::Base. In the common base class for my controllers, I do
def silent?(action)
false
end
# this knows more than I'd like about the internals of process, but
# the other options require knowing even more. It would have been
# nice to be able to use logger.silence, but there isn't a good
# method to hook that around, due to the way benchmarking logs.
def log_processing_with_silence_logs
if logger && silent?(action_name) then
@old_logger_level, logger.level = logger.level, Logger::ERROR
end
log_processing_without_silence_logs
end
def process_with_silence_logs(request, response, method = :perform_action, *arguments)
ret = process_without_silence_logs(request, response, method, *arguments)
if logger && silent?(action_name) then
logger.level = @old_logger_level
end
ret
end
alias_method_chain :log_processing, :silence_logs
alias_method_chain :process, :silence_logs
then, in the controller with the method I want to suppress logging on:
def silent?(action)
RAILS_ENV == "development" && ['my_noisy_action'].include?(action)
end