module ExceptionNotification::ExceptionNotifiable
Public Class Methods
included(base)
click to toggle source
# File lib/exception_notification/exception_notifiable.rb, line 8 def self.included(base) base.extend ClassMethods # Sets up an alias chain to catch exceptions when Rails does #This is what makes it all work with Hoptoad or other exception catchers. #base.send(:alias_method, :rescue_action_locally_without_sen_handler, :rescue_action_locally) #base.send(:alias_method, :rescue_action_locally, :rescue_action_locally_with_sen_handler) #Alias method chaining doesn't work here because it would trigger a double render error. # Sets up an alias chain to catch exceptions when Rails does #This is what makes it all work with Hoptoad or other exception catchers. #base.send(:alias_method, :rescue_action_in_public_without_exception_notifiable, :rescue_action_in_public) #base.send(:alias_method, :rescue_action_in_public, :rescue_action_in_public_with_exception_notifiable) # Adds the following class attributes to the classes that include ExceptionNotifiable # HTTP status codes and what their 'English' status message is base.cattr_accessor :http_status_codes base.http_status_codes = HTTP_STATUS_CODES # error_layout: # can be defined at controller level to the name of the desired error layout, # or set to true to render the controller's own default layout, # or set to false to render errors with no layout base.cattr_accessor :error_layout base.error_layout = nil # Rails error classes to rescue and how to rescue them (which error code to use) base.cattr_accessor :error_class_status_codes base.error_class_status_codes = self.codes_for_error_classes # Verbosity of the gem base.cattr_accessor :exception_notifiable_verbose base.exception_notifiable_verbose = false # Do Not Ever send error notification emails for these Error Classes base.cattr_accessor :exception_notifiable_silent_exceptions base.exception_notifiable_silent_exceptions = SILENT_EXCEPTIONS # Notification Level base.cattr_accessor :exception_notifiable_notification_level base.exception_notifiable_notification_level = [:render, :email, :web_hooks] # Since there is no concept of locality from a request here allow user to explicitly define which env's are noisy (send notifications) base.cattr_accessor :exception_notifiable_noisy_environments base.exception_notifiable_noisy_environments = ["production"] base.cattr_accessor :exception_notifiable_pass_through base.exception_notifiable_pass_through = false end
Public Instance Methods
be_silent_for_exception?(exception)
click to toggle source
# File lib/exception_notification/exception_notifiable.rb, line 84 def be_silent_for_exception?(exception) self.class.be_silent_for_exception?(exception) end
Private Instance Methods
environment_is_noisy?()
click to toggle source
# File lib/exception_notification/exception_notifiable.rb, line 90 def environment_is_noisy? self.class.exception_notifiable_noisy_environments.include?(Rails.env) end
is_local?()
click to toggle source
# File lib/exception_notification/exception_notifiable.rb, line 244 def is_local? (consider_all_requests_local || local_request?) end
local_request?()
click to toggle source
overrides Rails' local_request? method to also check any ip addresses specified through consider_local.
# File lib/exception_notification/exception_notifiable.rb, line 108 def local_request? remote = IPAddr.new(request.remote_ip) !self.class.local_addresses.detect { |addr| addr.include?(remote) }.nil? end
notification_level_renders?()
click to toggle source
# File lib/exception_notification/exception_notifiable.rb, line 102 def notification_level_renders? self.class.exception_notifiable_notification_level.include?(:render) end
notification_level_sends_email?()
click to toggle source
# File lib/exception_notification/exception_notifiable.rb, line 94 def notification_level_sends_email? self.class.exception_notifiable_notification_level.include?(:email) end
notification_level_sends_web_hooks?()
click to toggle source
# File lib/exception_notification/exception_notifiable.rb, line 98 def notification_level_sends_web_hooks? self.class.exception_notifiable_notification_level.include?(:web_hooks) end
notify_and_render_error_template(status_cd, request, exception, file_path, verbose = false)
click to toggle source
# File lib/exception_notification/exception_notifiable.rb, line 160 def notify_and_render_error_template(status_cd, request, exception, file_path, verbose = false) logger.info "notify_and_render_error_template" status = self.class.http_status_codes[status_cd] ? status_cd + " " + self.class.http_status_codes[status_cd] : status_cd data = get_exception_data #We only send email if it has been configured in environment send_email = should_email_on_exception?(exception, status_cd, verbose) #We only send web hooks if they've been configured in environment send_web_hooks = should_web_hook_on_exception?(exception, status_cd, verbose) the_blamed = ExceptionNotification::Notifier.config[:git_repo_path].nil? ? nil : lay_blame(exception) rejected_sections = request.nil? ? %w(request session) : [] # Debugging output verbose_output(exception, status_cd, file_path, send_email, send_web_hooks, request, the_blamed, rejected_sections) if verbose #TODO: is _rescue_action something from rails 3? #if !(self.controller_name == 'application' && self.action_name == '_rescue_action') # Send the exception notification email perform_exception_notify_mailing(exception, data, request, the_blamed, verbose, rejected_sections) if send_email # Send Web Hook requests ExceptionNotification::HooksNotifier.deliver_exception_to_web_hooks(ExceptionNotification::Notifier.config, exception, self, request, data, the_blamed) if send_web_hooks # We put the render call after the deliver call to ensure that, if the # deliver raises an exception, we don't call render twice. # Render the error page to the end user render_error_template(file_path, status) end
pass_it_on(exception, env, request = {:params => {}}, params = {}, session = {}, verbose = false)
click to toggle source
some integration with hoptoad or other exception handler is done by tha alias method chain on:
rescue_action_locally
# File lib/exception_notification/exception_notifiable.rb, line 188 def pass_it_on(exception, env, request = {:params => {}}, params = {}, session = {}, verbose = false) begin case self.class.exception_notifiable_pass_through when :hoptoad then HoptoadNotifier.notify(exception, sen_hoptoad_request_data(env, request, params, session)) logger.info("[PASS-IT-ON] HOPTOAD NOTIFIED") if verbose else logger.info("[PASS-IT-ON] NO") if verbose #Do Nothing end rescue #Do Nothing logger.info("[PASS-IT-ON] FAILED") if verbose end end
render_error_template(file, status)
click to toggle source
# File lib/exception_notification/exception_notifiable.rb, line 256 def render_error_template(file, status) respond_to do |type| type.html { render :file => file, :layout => self.class.error_layout, :status => status } type.all { render :nothing => true, :status => status} end end
rescue_action_in_public(exception)
click to toggle source
Overrides the rescue_action method in ActionController::Base, but does not inhibit any custom processing that is defined with Rails 2's exception helpers. When the action being executed is letting SEN handle the exception completely
# File lib/exception_notification/exception_notifiable.rb, line 144 def rescue_action_in_public(exception) logger.info "rescue_action_in_public" # If the error class is NOT listed in the rails_error_class hash then we get a generic 500 error: # OTW if the error class is listed, but has a blank code or the code is == '200' then we get a custom error layout rendered # OTW the error class is listed! verbose = self.class.exception_notifiable_verbose && respond_to?(:logger) && !logger.nil? logger.info("[RESCUE STYLE] rescue_action_in_public") if verbose status_code = status_code_for_exception(exception) if status_code == '200' notify_and_render_error_template(status_code, request, exception, ExceptionNotification::Notifier.get_view_path_for_class(exception, verbose), verbose) else notify_and_render_error_template(status_code, request, exception, ExceptionNotification::Notifier.get_view_path_for_status_code(status_code, verbose), verbose) end pass_it_on(exception, ENV, request, params, session, verbose) end
rescue_with_handler(exception)
click to toggle source
No Request present
When the action being executed has its own local error handling (rescue) Or when the error occurs somewhere without a subsequent render (eg. method calls in console)
Calls superclass method
# File lib/exception_notification/exception_notifiable.rb, line 116 def rescue_with_handler(exception) to_return = super # Not sure how to do this. We aren't supposed to rely on the return value of the super handler. #if to_return verbose = self.class.exception_notifiable_verbose && respond_to?(:logger) && !logger.nil? logger.info("[RESCUE STYLE] rescue_with_handler") if verbose data = get_exception_data status_code = status_code_for_exception(exception) #We only send email if it has been configured in environment send_email = should_email_on_exception?(exception, status_code, verbose) #We only send web hooks if they've been configured in environment send_web_hooks = should_web_hook_on_exception?(exception, status_code, verbose) the_blamed = ExceptionNotification::Notifier.config[:git_repo_path].nil? ? nil : lay_blame(exception) rejected_sections = %w(request session) # Debugging output verbose_output(exception, status_code, "rescued by handler", send_email, send_web_hooks, nil, the_blamed, rejected_sections) if verbose # Send the exception notification email perform_exception_notify_mailing(exception, data, nil, the_blamed, verbose, rejected_sections) if send_email # Send Web Hook requests ExceptionNotification::HooksNotifier.deliver_exception_to_web_hooks(ExceptionNotification::Notifier.config, exception, self, request, data, the_blamed) if send_web_hooks pass_it_on(exception, ENV, verbose) #end to_return end
sen_hoptoad_filter_if_filtering(hash)
click to toggle source
# File lib/exception_notification/exception_notifiable.rb, line 215 def sen_hoptoad_filter_if_filtering(hash) if respond_to?(:filter_parameters) filter_parameters(hash) rescue hash else hash end end
sen_hoptoad_request_data(env, request, params, session)
click to toggle source
# File lib/exception_notification/exception_notifiable.rb, line 204 def sen_hoptoad_request_data(env, request, params, session) { :parameters => sen_hoptoad_filter_if_filtering(params.to_hash), :session_data => sen_hoptoad_session_data(session), :controller => params[:controller], :action => params[:action], :url => sen_hoptoad_request_url(request), :cgi_data => request.respond_to?(:env) ? sen_hoptoad_filter_if_filtering(request.env) : nil, :environment_vars => sen_hoptoad_filter_if_filtering(env), :request => request } end
sen_hoptoad_request_url(request)
click to toggle source
# File lib/exception_notification/exception_notifiable.rb, line 231 def sen_hoptoad_request_url(request) if request.respond_to?(:protocol) url = "#{request.protocol}#{request.host}" unless [80, 443].include?(request.port) url << ":#{request.port}" end url << request.request_uri url end end
sen_hoptoad_session_data(session)
click to toggle source
# File lib/exception_notification/exception_notifiable.rb, line 223 def sen_hoptoad_session_data(session) if session.respond_to?(:to_hash) session.to_hash elsif session.respond_to?(:data) session.data end end
status_code_for_exception(exception)
click to toggle source
# File lib/exception_notification/exception_notifiable.rb, line 248 def status_code_for_exception(exception) self.class.error_class_status_codes[exception.class].nil? ? '500' : self.class.error_class_status_codes[exception.class].blank? ? '200' : self.class.error_class_status_codes[exception.class] end