Custom error-handling plugin for Strelka::App.
plugin :errors # Handle only status 400 errors on_status HTTP::BAD_REQUEST do |res, status_info| # Do something on 400 errors end # Handle any other error in the 4xx range on_status 400..499 do |res, status_info| # Do something on 4xx errors end
If you have the :templating
plugin loaded, you can substitute
a Symbol that corresponds with one of the declared templates instead:
class MyApp < Strelka::App plugins :errors, :templating layout 'layout.tmpl' templates :missing => 'errors/missing.tmpl' # Load the 'missing' template, wrap it up in the layout # template and render that as the body of the 404 # response on_status HTTP::NOT_FOUND, :missing end # class MyApp
The template can access the status info hash via the
:status_info
note on the request or response object:
<!-- error.tmpl --> Sorry, there was a <?call request.notes[:status_info][:status] ?> error: <?escape request.notes[:status_info][:message] ?>.
If you want to do something application-specific for an error, but still use the default error-handling, just call finish_with again with the status info from your status handler:
class MyApp < Strelka::App plugins :errors # Send an email when an app is going to return a 500 error on_status HTTP::SERVER_ERROR do |res, info| require 'mail' Mail.deliver do from 'app@example.com' to 'team@example.com' subject "SERVER_ERROR: %p [%s]" % [ self.class, self.class.version_string ] body "Server error while running %p [%s]: %s" % [ self.class, self.conn, status.message ] end # Finish the transaction finish_with( info ) end def handle( req ) finish_with( HTTP::SERVER_ERROR, "Ack! Something bad happened." ) end end # class MyApp
See the documentation for Strelka::App::Errors::ClassMethods#on_status for more details on the status-handler block.
The range of status codes to delegate to an on_status handler that doesn't specify one
Check for a status response that is hooked, and run the hook if one is found.
# File lib/strelka/app/errors.rb, line 143
def handle_request( request )
self.log.debug "[:errors] Wrapping request in custom error-handling."
response = nil
# Catch a finish_with; the status_response will only be non-nil
status_response = catch( :finish ) do
# Provide our own exception-handling and translate them into server errors
begin
response = super
rescue => err
self.log.error "%s: %s %s" % [ err.class.name, err.message, err.backtrace.first ]
err.backtrace[ 1..-1 ].each {|frame| self.log.debug(' ' + frame) }
finish_with(
status: HTTP::SERVER_ERROR,
message: err.message,
headers: {},
backtrace: err.backtrace,
exception: err
)
end
nil
end
# If the app or any plugins threw a finish, look for a handler for the status code
# and call it if one is found.
response = self.handle_status_response( request, status_response ) if status_response
return response
end
Return a response built out of the status_info
for the
specified request
if there is a custom handler. If there
isn't one, rethrows to the main :finish handler.
# File lib/strelka/app/errors.rb, line 178
def handle_status_response( request, status_info )
status = status_info[:status]
# If we can't find a custom handler for this status, re-throw
# to the default handler instead
handler = self.status_handler_for( status ) or
throw( :finish, status_info )
self.log.debug "Custom %d handler: %p" % [ status, handler ]
# Set up the request's response with the right status code
request.notes[:status_info] = status_info
response = request.response
response.status = status
# The handler is an UnboundMethod, so bind it to the app instance
# and call it
return handler.bind( self ).call( response, status_info )
end
Find a status handler for the given status_code
and return it
as an UnboundMethod.
# File lib/strelka/app/errors.rb, line 199
def status_handler_for( status_code )
self.log.debug "[:errors] Looking for a status handler for %d responses" % [ status_code ]
handlers = self.class.status_handlers
ranges = handlers.keys
ranges.each do |range|
return handlers[ range ] if range.include?( status_code )
end
return nil
end