Search code examples
ruby-on-railsruby-on-rails-5

How to skip logging uncaught exceptions in Rails?


When using custom exceptions_app and rescue_responses, an application has more control of uncaught exceptions and an excessive logging from DebugExceptions middleware becomes noise.

As an example, the application knows how to process ActionPolicy::Unauthorized, renders proper page in exceptions_app and thus the following log is redundant:

FATAL -- :   
FATAL -- : ActionPolicy::Unauthorized (Not Authorized):
FATAL -- :   
FATAL -- : app/controllers/topics_suggest_controller.rb:47:in `topic_load' 

What would be the most idiomatic way to skip logging only those exceptions listed in rescue_responses?


Solution

  • Some historical notes are below. As of June 25, 2021, my PR to Rails https://github.com/rails/rails/pull/42592 has been accepted and this functionality will be available in Rails 6.1.5 7.0.0


    Approach 1

    It's tempting to delete DebugExceptions middleware from the application's Rails stack.

    config/application.rb:

    config.middleware.delete ActionDispatch::DebugExceptions
    

    The problem is that it is exactly the middleware that determines Rails cannot find a route and throws ActionController::RoutingError in such cases. Hence, if you would like to react to this exception in your exceptions_app, this approach is a no-go for you.

    Go ahead and use this approach if it's fine for you to see HTTP status 404 and plain text response Not found when no route was found.

    Approach 2

    Monkey patch or change ActionDispatch::DebugExceptions in some way. In fact, there was a proposal in 2013 to change DebugExceptions behavior so that it skips logging exceptions registered in rescue_responses: 9343, there is an example code in there.

    I think it's too much to overwrite the whole class, so I chose to override its method log_error responsible for logging errors.

    lib/ext/suppress_exceptions.rb:

    module Ext
      module SuppressExceptions
        private
    
        def log_error(_request, wrapper)
          exception = wrapper.exception
          return if ActionDispatch::ExceptionWrapper.rescue_responses.key? exception.class.name
          super
        end
      end
    end
    

    config/initializers/error_handling.rb:

    require_dependency 'ext/suppress_exceptions'
    
    ActiveSupport.on_load(:action_controller) do
      ActionDispatch::DebugExceptions.prepend Ext::SuppressExceptions
    end