April 23, 2010
Following code has been tested with Rails 2.3.5 .
Every one knows for sure that hoptoad notifier sends exception messages to server in production environment. Between 'development' and 'production' there could be a number of environments. Some of these would have settings closer to 'development' environment and some would have setting closely matching the settings of 'production' environment.
When you have many environments and when an exception occurs, one is not really sure if that message is getting logged at hoptoad or not. Here is a run down of which messages will get logged and why.
When an exception occurs while rendering a page then action_controller
catches
the exception. Following logic is evaluated to decide if user should see an
error page with full stack trace or 'we are sorry something went wrong' message.
if consider_all_requests_local || local_request?
rescue_action_locally(exception)
else
rescue_action_in_public(exception)
end
Let's look at first part consider_all_requests_local
. Open
~/config/environments/development.rb
and ~/config/environments/production.rb
.
# ~/config/environments/development.rb
config.action_controller.consider_all_requests_local = true
# ~/config/environments/production.rb
config.action_controller.consider_all_requests_local = false
As you can see in development mode all requests are local. Be careful with what you put in your intermediary environments.
If you want to override that value then you can do like this.
#~/app/controllers/application_controller.rb
ActionController::Base.consider_all_requests_local = true
The second part of the equation was local_request?
.
Rails has following code for that method.
LOCALHOST = '127.0.0.1'.freeze
def local_request?
request.remote_addr == LOCALHOST && request.remote_ip == LOCALHOST
end
As you can see all requests coming from 127.0.0.1
are considered local even if
RAILS_ENV is 'production'. For testing purpose you can override this value like
this.
#~/app/controllers/application_controller.rb
def local_request?
false
end
If consider_all_request_local
is false and if request is not local then
hoptoad will get access to exception thanks to alias_method_chain
.
def self.included(base)
base.send(:alias_method, :rescue_action_in_public_without_hoptoad, :rescue_action_in_public)
base.send(:alias_method, :rescue_action_in_public, :rescue_action_in_public_with_hoptoad)
end
In rescue_action_in_public_with_hoptoad
there is a call to notify_or_ignore
like this.
unless hoptoad_ignore_user_agent?
HoptoadNotifier.notify_or_ignore(exception, hoptoad_request_data)
end
For majority of us there is no special handling for a particular user_agent
.
def notify_or_ignore(exception, opts = {})
notice = build_notice_for(exception, opts)
send_notice(notice) unless notice.ignore?
end
Hoptoad defines following methods as ignorable by default and you won't get notifications for following types of exceptions.
IGNORE_DEFAULT = ['ActiveRecord::RecordNotFound',
'ActionController::RoutingError',
'ActionController::InvalidAuthenticityToken',
'CGI::Session::CookieStore::TamperedWithCookie',
'ActionController::UnknownAction']
Next hop is method send_notice
.
def send_notice(notice)
if configuration.public?
sender.send_to_hoptoad(notice.to_xml)
end
end
configuration.public?
is defined like this.
@development_environments = %w(development test cucumber)
def public?
!development_environments.include?(environment_name)
end
As you can see if the Rails.env
is development
or test
or cucumber
the
exception will not be reported to hoptoad server.
If this blog was helpful, check out our full blog archive.