Reputation: 1573
I am using the new Sentry (not Raven) for Ruby for my Rails 6.1 application:
gem "sentry-ruby"
gem "sentry-rails"
I am able to see the transactions when users triggered ActionController::RoutingError
, but I want these to appear as errors in Sentry.
I do not see ActionController::RoutingError
as an 'ignored' or 'excluded' error:
> Sentry::Configuration::IGNORE_DEFAULT
=> ["Mongoid::Errors::DocumentNotFound", "Rack::QueryParser::InvalidParameterError", "Rack::QueryParser::ParameterTypeError", "Sinatra::NotFound"]
I tried clearing excluded_exceptions
in sentry.rb
initializer file, but this had no effect:
Sentry.init do |config|
...
config.excluded_exceptions = []
end
How can I configure Sentry so that these are sent as errors? I was also thinking that I can modify the middleware (ActionDispatch?, ActionPack?) and add Sentry.capture_message
where appropriate, but I am not sure how to do that.
I do not want a "catch-all" route that redirects to an ErrorController or ApplicationController:
match '*path', to: "application#handle_route_error", via: :all
Upvotes: 3
Views: 404
Reputation: 30036
I don't use sentry, just replace p
with whatever command for sentry:
For production only, this is required: config.consider_all_requests_local = false
.
# config/initializers/report_routing_error.rb
class ReportRoutingErrorMiddleware
def initialize app
@app = app
end
def call(env)
@app.call(env)
rescue ActionController::RoutingError => e
p ["NOT FOUND", e]
raise
end
end
# DebugExceptions raises RoutingError when consider_all_requests_local is false
# insert_before - to catch the error
Rails.application.config.middleware.insert_before ActionDispatch::DebugExceptions, ReportRoutingErrorMiddleware
#=> ["NOT FOUND", #<ActionController::RoutingError: No route matches [GET] "/asdf">]
In development, DebugExceptions
middleware technically raises the error but it also rescues it and renders the full error page. Until response gets to that middleware it is just a 404 response from the router:
https://github.com/rails/rails/blob/v7.0.7/actionpack/lib/action_dispatch/routing/route_set.rb#L37
# config/initializers/report_routing_error.rb
class ReportRoutingErrorMiddleware
def initialize app
@app = app
end
def call(env)
status, headers, body = response = @app.call(env)
if status == 404
# no error, so get what you need from env
p ["NOT FOUND", env["REQUEST_METHOD"], env["PATH_INFO"]]
end
response
end
end
# insert_after - to get response first, because it doesn't go past DebugExceptions
Rails.application.config.middleware.insert_after ActionDispatch::DebugExceptions, ReportRoutingErrorMiddleware
#=> ["NOT FOUND", "GET", "/asdf"]
Apparently, they've figured it out a long time ago register_interceptor
:
# config/initializers/report_routing_error.rb
ActionDispatch::DebugExceptions.register_interceptor do |req, exception|
if exception.is_a? ActionController::RoutingError
p ["NOT FOUND", req, exception]
end
end
#=> ["NOT FOUND", #<ActionDispatch::Request GET "http://0.0.0.0:3000/asdf" for 127.0.0.1>, #<ActionController::RoutingError: No route matches [GET] "/asdf">]
Introduce
ActionDispatch::DebugExceptions.register_interceptor
, a way to hook intoDebugExceptions
and process the exception, before being rendered.
https://github.com/rails/rails/pull/23868
Upvotes: 3
Reputation: 15308
The problem is that this error is handled by default in Rails and rescued with "Not Found" response
Of course you can handle such errors ("Not Found", "Unprocessable Entity", "Internal Server Error", etc.) manually using router and response with specific action of something like ErrorsController. You can send message to Sentry from there
But since you don't want such decision, you can monkeypatch middleware or even exactly ActionController::RoutingError
. Find source of this error and add initializer like this
# config/initializers/handle_routing_error.rb
module ActionController
class RoutingError < ActionControllerError
attr_reader :failures
def initialize(message, failures = [])
Sentry.capture_message(message) # or Sentry.capture_error(self)
super(message)
@failures = failures
end
end
end
Usually monkeypatch is some hack and not nice solution, but it will work
Upvotes: 2