Trouble integrating Padrino Ruby app with Raygun
emanuil_tolev
Posted on
Dec 18 2014
I've got a spot of trouble integrating Raygun into a Padrino (Sinatra-based framework) app.
I am using the instructions at https://github.com/MindscapeHQ/raygun4ruby#sinatra , which by all accounts is exactly how you should do it (introduce Rack middleware). Padrino has support for Rack middleware, and I can see that the relevant Raygun class is being added to the list of middleware to be run.
However, it doesn't seem to send exception info to raygun.io .
So this is how I introduced Raygun into the Padrino app:
Gemfile:
gem 'raygun4ruby', "~> 1.1.4"
(and then bundle install, all OK)
boot.rb:
require 'raygun4ruby'
Raygun.setup do |config|
config.api_key = "I almost posted this publicly"
config.enable_reporting = true
end
Padrino.use Raygun::Middleware::RackExceptionInterceptor
# puts Padrino.middleware.inspect is supposed to give a list of loaded middleware
# and responds seemingly correctly with [[Raygun::Middleware::RackExceptionInterceptor, [], nil]]
The homepage route:
get :index do
# ... snip ...
raise "lala"
# ... snip ...
render :home, layout: "homepage"
end
The result - a Sinatra exception page, but no data in raygun.io. Also no message from Raygun's middleware saying Tracking Exception - the code never reaches the track_exception method in the Raygun gem.
Confirmed by (naughtily) modifying the Raygun middleware itself:
def call(env)
puts "now in RackExceptionInterceptor"
response = @app.call(env)
puts "end of RackExceptionInterceptor middleware call, no exceptions raised"
return response
rescue Exception => exception
puts 'rescuing exception in RackExceptionInterceptor'
Raygun.track_exception(exception, env)
puts 'after raygun tracking call'
raise exception
end
After restarting the app to load the modified gem, this code prints:
now in RackExceptionInterceptor
end of RackExceptionInterceptor middleware call, no exceptions raised
It doesn't go anywhere near Raygun.track_exception, which explains why the data never makes it to raygun.io. I've no idea why it's not handling the RuntimeError - obviously Sinatra later manages to handle it to show me an error page.
Here's a pastebin with the full traceback of my contrived exception: http://pastebin.com/f52WpWjY It is clearly going through the Raygun Rack middleware - see line 67. But the rescue clause does not take effect.
It does this in other environments too, not just development (the default Rack env).
I don't really want to use the "manual ruby" method as I would effectively have to wrap each response the app produces in something that catches all exceptions, sends them to Raygun, and re-raises them. Which is what the middleware does :).
The middleware itself seems to be written OK, since Honeybadger's ruby integration code is conceptually very similar (though theirs seems a bit more complex, https://github.com/honeybadger-io/honeybadger-ruby/blob/e9525295689eed37fb282c3e4c3ec33fec9f9260/lib/honeybadger/rack/errornotifier.rb ). I haven't tried actually integrating with them - we need Javascript and Ruby exception support in one place.
Any help on integrating would be appreciated, we intend to become paying users as soon as we can actually try the service :).
nikz
Posted on
Dec 18 2014
Heya,
Looking into this - will get back to you shortly.
Nik
nikz
Posted on
Dec 18 2014
Hey Emanuil,
Could you let me know what you have "show_exceptions" set to?
Cheers,
Nik
nikz
Posted on
Dec 18 2014
Looks like Padrino is swallowing the error somewhere. I'm investigating around here: https://github.com/padrino/padrino-framework/blob/0.12.4/padrino-core/lib/padrino-core/application/routing.rb#L919.
Have to head to bed now, but I will have another look in the morning.
Nik
emanuil_tolev
Posted on
Dec 18 2014
Hm, this page http://www.sinatrarb.com/configuration.html has a curious section:
:raise_errors - allow exceptions to propagate outside of the app
Boolean specifying whether exceptions raised from routes and filters should escape the application. When disabled, exceptions are rescued and mapped to error handlers which typically set a 5xx status code and render a custom error page. Enabling the :raise_errors setting causes exceptions to be raised outside of the application where it may be handled by the server handler or Rack middleware, such as Rack::ShowExceptions or Rack::MailExceptions.
That sounds exactly right. We are using a very basic custom error page (just to still render the site's layout rather than a jarring white page, with the words Sorry an error has occurred). Currently travelling a bit but will try this ASAP to see how it affects raygun.
nikz
Posted on
Dec 19 2014
Hmmm, even with :raise_errors the RackInterceptor isn't getting sent the exception. I will keep looking, let me know if you figure out why the exception isn't getting to the middleware!
emanuil_tolev
Posted on
Dec 19 2014
Yeah, I've got
set :raise_errors, true
set :show_exceptions, false
but it's still just going through.
emanuil_tolev
Posted on
Dec 19 2014
Trying this next: https://github.com/padrino/padrino-contrib/blob/master/lib/padrino-contrib/exceptionnotifier.rb
Looks like it registers as a 500 handler to the app and then lets the exception through after notifying somebody. Fine with me. I'll have to include a copy of that code rather than use it directly, but as long as it works OK and gives you all the data, why not, we'll put it in the readme. IF it works - will report back!
emanuil_tolev
Posted on
Dec 19 2014
Some good progress, though with a good bit of headdesk from me.
It does work in a development env - it's a question of configuring your app correctly.
Has to be done in the app itself. In the app's class, not in boot.rb. Like this more concrete example:
class App < Padrino::Application
use ActiveRecord::ConnectionAdapters::ConnectionManagement
register Padrino::Rendering
register Padrino::Mailer
register Padrino::Helpers
# ... etcetera
require 'raygun4ruby'
Raygun.setup do |config|
config.api_key = "api key"
config.enable_reporting = true
end
use Raygun::Middleware::RackExceptionInterceptor
end
Notice in my original code I was using Padrino.use
However, still can't get it to work in a production environment - because of the show_exceptions setting. You were right, it does affect the middleware.
# WORKING example in development environment, no modification of raise_errors or show_exceptions from their defaults, Padrino 0.12.4
puts settings.raise_errors # false
puts settings.show_exceptions # true
# WORKING example in development environment, Padrino 0.12.4
set :raise_errors, true
puts settings.raise_errors # true
puts settings.show_exceptions # true
# BROKEN example in development environment - exception not passed to middleware, Padrino 0.12.4
set :show_exceptions, false
puts settings.raise_errors # false
puts settings.show_exceptions # false
# BROKEN example in development environment - exception not passed to middleware, Padrino 0.12.4
set :raise_errors, true
set :show_exceptions, false
puts settings.raise_errors # true
puts settings.show_exceptions # false
Clearly, settings.show_exceptions should be on for the middleware to get the exception. Obviously this setting is off in production.
user@laptop:~/cl/theapp$ RACK_ENV=production padrino s
Output below. First line with all the middleware looks a lot more reasonable now that it's being called in the correct place - for our specific Padrino app.
All Rack Middleware loaded for this app [[ActiveRecord::ConnectionAdapters::ConnectionManagement, [], nil], [Rack::SslEnforcer, [{:only_environments=>[]}], nil], [TheApp::CustomRedirectForSpecificMinorityOfUsers, [], nil], [Raygun::Middleware::RackExceptionInterceptor, [], nil]]
settings.raise_errors is set to false
settings.show_exceptions is set to false
=> Padrino/0.12.4 has taken the stage production at http://127.0.0.1:3000
[2014-12-18 19:45:58] INFO WEBrick 1.3.1
[2014-12-18 19:45:58] INFO ruby 2.1.2 (2014-05-08) [x86_64-linux]
[2014-12-18 19:45:58] INFO WEBrick::HTTPServer#start: pid=23980 port=3000
now in RackExceptionInterceptor
RuntimeError - lala:
# ... full stack trace in http://pastebin.com/q0gB0rmg
So basically, I can send errors from my development env, but wouldn't be able to in production due to the show_exceptions setting. I'll raise it on the padrino repo, they might know more.
Full stack trace URL: http://pastebin.com/q0gB0rmg
emanuil_tolev
Posted on
Dec 19 2014
Raised on https://github.com/padrino/padrino-framework/issues/1845 , hopefully somebody with some Rack middleware experience will be able to help in getting middleware exception handling to work in a production env.
nikz
Posted on
Dec 20 2014
[Deleted, Whoops, didn't look at your post properly, you've got the middleware listed there]