wrangler 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +20 -0
- data/README +247 -0
- data/lib/wrangler/exception_handler.rb +280 -0
- data/lib/wrangler/exception_notifier.rb +142 -0
- data/lib/wrangler/wrangler_exceptions.rb +63 -0
- data/lib/wrangler/wrangler_helper.rb +95 -0
- data/lib/wrangler.rb +284 -0
- data/rails/app/views/wrangler/400.html +6 -0
- data/rails/app/views/wrangler/401.html +6 -0
- data/rails/app/views/wrangler/403.html +6 -0
- data/rails/app/views/wrangler/404.html +6 -0
- data/rails/app/views/wrangler/405.html +6 -0
- data/rails/app/views/wrangler/410.html +7 -0
- data/rails/app/views/wrangler/422.html +6 -0
- data/rails/app/views/wrangler/423.html +7 -0
- data/rails/app/views/wrangler/500.html +6 -0
- data/rails/app/views/wrangler/501.html +8 -0
- data/rails/app/views/wrangler/503.html +6 -0
- data/views/wrangler/exception_notifier/exception_notification.text.plain.erb +44 -0
- data/wrangler.gemspec +61 -0
- metadata +87 -0
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
# Copyright (c) 2009 Umamibud, Inc.
|
2
|
+
#
|
3
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
# a copy of this software and associated documentation files (the
|
5
|
+
# "Software"), to deal in the Software without restriction, including
|
6
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
# the following conditions:
|
10
|
+
#
|
11
|
+
# The above copyright notice and this permission notice shall be
|
12
|
+
# included in all copies or substantial portions of the Software.
|
13
|
+
#
|
14
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README
ADDED
@@ -0,0 +1,247 @@
|
|
1
|
+
= Wrangler
|
2
|
+
|
3
|
+
== NOTE/DISCLAIMER
|
4
|
+
This gem is almost completely inspired by/ripped off the exception_notification
|
5
|
+
plugin/gem, but had to hack too much to get things to work with delayed_job
|
6
|
+
that I just decided to start from scratch. You'll see that much has been
|
7
|
+
borrowed however, so I owe a huge debt to the originals (exception_notification
|
8
|
+
[http://github.com/rails/exception_notification] and
|
9
|
+
super_exception_notification [http://github.com/pboling/exception_notification])
|
10
|
+
to help me recreate the Rails hacking.
|
11
|
+
|
12
|
+
If you don't really care about using delayed_job for your emailing, consider
|
13
|
+
going back to the originals, as they're likely better maintained.... ;)
|
14
|
+
|
15
|
+
== Overview:
|
16
|
+
A gem for handling exceptions in a Rails application/environment.
|
17
|
+
|
18
|
+
Some highlights:
|
19
|
+
* Allows for rendering error pages and sending email notifications in case of
|
20
|
+
errors.
|
21
|
+
* Allows for lots of configuring of which pages to show, whether to email or not.
|
22
|
+
* Allows for asynchronous emailing through delayed_job if available, but works
|
23
|
+
fine even if delayed_job not installed (email will be synchronous however)
|
24
|
+
* Will honor filter_parameters set in the controller including the Wrangler
|
25
|
+
module (except if the parameters are in the URL for GETs) when logging and
|
26
|
+
emailing application state at the time of the exception
|
27
|
+
* Allows email notification on exceptions thrown totally outside Controller
|
28
|
+
context, e.g. in a script run (with rails environment) in a cronjob or
|
29
|
+
delayed_job
|
30
|
+
|
31
|
+
== Quickstart
|
32
|
+
=== Bare Minimum
|
33
|
+
There are a lot of defaults set, so getting started should be pretty easy. In
|
34
|
+
fact, if you don't want any email notifications, you basically just need to
|
35
|
+
include the Wrangler module in your controller:
|
36
|
+
# application_controller.rb
|
37
|
+
class ApplicationController < ActionController::Base
|
38
|
+
include Wrangler
|
39
|
+
|
40
|
+
...
|
41
|
+
end
|
42
|
+
|
43
|
+
=== Enabling email notifications
|
44
|
+
Email notifications are configured to be sent with the default configuration,
|
45
|
+
but you'll need to specify from and to addresses for emails to actually be sent.
|
46
|
+
So that brings us to the configuration of Wrangler. Recommended: just create a
|
47
|
+
new initializer file (create a wrangler.rb (or whatever you want to name the file)
|
48
|
+
in RAILS_ROOT/config/initializers/wrangler.rb). In it, add the following:
|
49
|
+
|
50
|
+
Wrangler::ExceptionNotifier.configure do |notifier_config|
|
51
|
+
notifier_config.merge! :from_address => 'monitor@umamibud.com',
|
52
|
+
:recipient_addresses => ['u-ops-monitor@umamibud.com']
|
53
|
+
end
|
54
|
+
|
55
|
+
And, if you haven't already configured ActionMailer to send emails, you'll need
|
56
|
+
to do that (e.g. setting ActionMailer::Base.smtp_settings), and even after you
|
57
|
+
have, you may want to change some settings in order to send from a different
|
58
|
+
account from the one you may use to email your users (e.g. change the :user_name
|
59
|
+
for smtp_settings):
|
60
|
+
|
61
|
+
Wrangler::ExceptionNotifier.smtp_settings.merge! :user_name => 'notifier@mydomain.com'
|
62
|
+
|
63
|
+
(Recommend just putting that in the same wrangler.rb initializer you created above)
|
64
|
+
|
65
|
+
For more info on smtp_settings, see ActionMailer (http://am.rubyonrails.org/)
|
66
|
+
|
67
|
+
== Configuration
|
68
|
+
There are two different classes that receive configuration, ExceptionHandler and
|
69
|
+
ExceptionNotifier.
|
70
|
+
|
71
|
+
ExceptionHandler stores configurations about what to do about exceptions (whether to
|
72
|
+
handle them, email them, which error templates to render for each exception...).
|
73
|
+
|
74
|
+
ExceptionNotifier handles the sending of emails when exceptions occur, so
|
75
|
+
stores configurations about where to send the emails.
|
76
|
+
|
77
|
+
You override defaults on each using the same syntax (as seen above) by calling the
|
78
|
+
configure() method on the class and using the config hash that is yielded to
|
79
|
+
set your configurations. See the method documentation for the configure() methods
|
80
|
+
themselves, but here's the basic idea:
|
81
|
+
|
82
|
+
Wrangler::ExceptionHandler.configure do |handler_config|
|
83
|
+
handler_config[:key1] = value1
|
84
|
+
handler_config[:key2] = value2
|
85
|
+
handler_config[:key_for_a_hash].merge! :subkey => value
|
86
|
+
handler_config[:key_for_an_array] << another_value
|
87
|
+
end
|
88
|
+
|
89
|
+
OR
|
90
|
+
|
91
|
+
Wrangler::ExceptionHandler.configure do |handler_config|
|
92
|
+
handler_config.merge! :key1 => value1,
|
93
|
+
:key2 => value2,
|
94
|
+
handler_config[:key_for_a_hash].merge! :subkey => value
|
95
|
+
handler_config[:key_for_an_array] << another_value
|
96
|
+
end
|
97
|
+
|
98
|
+
(same with Wrangler::ExceptionNotifier, except different classname)
|
99
|
+
|
100
|
+
Most configurations are single values (e.g. nums or strings),
|
101
|
+
but some are hashes or arrays. You can either overwrite the hashes/arrays, or
|
102
|
+
selectively delete, or just append. Recommend just appending to the defaults
|
103
|
+
in most cases, but if you know what you're doing, you can do whatever you like!
|
104
|
+
|
105
|
+
Here is the full set of configuration values for both classes, as well as their
|
106
|
+
default values (pasted in from the classes, so you can check the code directly
|
107
|
+
to make sure you've got the latest! :) ):
|
108
|
+
|
109
|
+
####################
|
110
|
+
# ExceptionHandler:
|
111
|
+
####################
|
112
|
+
|
113
|
+
:app_name => '',
|
114
|
+
:handle_local_errors => false,
|
115
|
+
:handle_public_errors => true,
|
116
|
+
# send email for local reqeusts. ignored if :handle_local_errors false
|
117
|
+
:notify_on_local_error => false,
|
118
|
+
# send email for public requests. ignored if :handle_public_errors false
|
119
|
+
:notify_on_public_error => true,
|
120
|
+
# send email for exceptions caught outside of a controller context
|
121
|
+
:notify_on_background_error => true,
|
122
|
+
# configure whether to send emails synchronously or asynchronously
|
123
|
+
# using delayed_job (these can be true even if delayed job is not
|
124
|
+
# installed, in which case, will just send emails synchronously anyway)
|
125
|
+
:delayed_job_for_controller_errors => false,
|
126
|
+
:delayed_job_for_non_controller_errors => false,
|
127
|
+
# mappings from exception classes to http status codes (see above)
|
128
|
+
# add/remove from this list as desired in environment configuration
|
129
|
+
:error_class_status_codes => Wrangler::codes_for_exception_classes,
|
130
|
+
# explicitly indicate which exceptions to send email notifications for
|
131
|
+
:notify_exception_classes => %w(),
|
132
|
+
# indicate which http status codes should result in email notification
|
133
|
+
:notify_status_codes => %w( 405 500 503 ),
|
134
|
+
# where to look for app-specific error page templates (ones you create
|
135
|
+
# yourself, for example...there are some defaults in this gem you can
|
136
|
+
# use as well...and that are configured already by default)
|
137
|
+
:error_template_dir => File.join(RAILS_ROOT, 'app', 'views', 'error'),
|
138
|
+
# excplicit mappings from exception class to arbitrary error page
|
139
|
+
# templates, different set for html and js responses (Wrangler determines
|
140
|
+
# which to use automatically, so you can have an entry in both
|
141
|
+
# hashes for the same error class)
|
142
|
+
:error_class_html_templates => {},
|
143
|
+
:error_class_js_templates => {},
|
144
|
+
# you can specify a fallback failsafe error template to render if
|
145
|
+
# no appropriate template is found in the usual places (you shouldn't
|
146
|
+
# rely on this, and error messages will be logged if this template is
|
147
|
+
# used). note: there's an even more failsafe template included in the
|
148
|
+
# gem (absolute_last_resort...) below, but DON'T CHANGE IT!!!
|
149
|
+
:default_error_template => '',
|
150
|
+
# these filter out any HTTP params that are undesired
|
151
|
+
:request_env_to_skip => [ /^rack\./,
|
152
|
+
"action_controller.rescue.request",
|
153
|
+
"action_controller.rescue.response" ],
|
154
|
+
# mapping from exception classes to templates (if desired), express
|
155
|
+
# in absolute paths. use wildcards like on cmd line (glob-like), NOT
|
156
|
+
# regexp-style
|
157
|
+
|
158
|
+
# just DON'T change this! this is the error template of last resort!
|
159
|
+
:absolute_last_resort_default_error_template =>
|
160
|
+
File.join(WRANGLER_ROOT,'rails','app','views','wrangler','500.html')
|
161
|
+
|
162
|
+
#####################
|
163
|
+
# ExceptionNotifier:
|
164
|
+
#####################
|
165
|
+
|
166
|
+
# who the emails will be coming from. if nil or missing or empty string,
|
167
|
+
# effectively disables email notification
|
168
|
+
:from_address => '',
|
169
|
+
# array of addresses that the emails will be sent to. if nil or missing
|
170
|
+
# or empty array, effectively disables email notification.
|
171
|
+
:recipient_addresses => [],
|
172
|
+
# what will show up at the beginning of the subject line for each email
|
173
|
+
# sent note: will be preceded by "[<app_name (if any)>...", where app_name
|
174
|
+
# is the :app_name config value from ExceptionHandler (or explicit
|
175
|
+
# proc_name given to notify_on_error() method)
|
176
|
+
:subject_prefix => "#{(defined?(Rails) ? Rails.env : RAILS_ENV).capitalize} ERROR",
|
177
|
+
# can use this to define app-specific mail views using the same data
|
178
|
+
# made available in exception_notification()
|
179
|
+
:mailer_template_root => File.join(WRANGLER_ROOT, 'views')
|
180
|
+
|
181
|
+
== Search algorithm for error templates (given an exception and a status_code):
|
182
|
+
When trying to find an appropriate error page template to render, Wrangler
|
183
|
+
goes through several different attempts to locate an appropriate template,
|
184
|
+
beginning with templates you've explicitly associated with the exception class
|
185
|
+
or status code that has arisen...and on through to assuming default file naming
|
186
|
+
conventions and finally failsafe default templates.
|
187
|
+
|
188
|
+
# if there is an explicit mapping from the exception to an error page in
|
189
|
+
:error_class_xxx_templates, use that
|
190
|
+
# if there is a mapping in :error_class_templates for which the exception
|
191
|
+
returns true to an is_a? call, use that
|
192
|
+
# if there is a file/template corresponding to the exception name
|
193
|
+
(underscorified) in one of the following locations, use that:
|
194
|
+
** config[:error_template_dir]/
|
195
|
+
** RAILS_ROOT/public/
|
196
|
+
** WRANGLER_ROOT/rails/app/views/wrangler/
|
197
|
+
# if there is a file/template corresponding to the status code
|
198
|
+
(e.g. named ###.html.erb where ### is the status code) in one of the following
|
199
|
+
locations, use that:
|
200
|
+
** config[:error_template_dir]/
|
201
|
+
** RAILS_ROOT/public/
|
202
|
+
** WRANGLER_ROOT/rails/app/views/wrangler/
|
203
|
+
# if there is a file/template corresponding to a parent class name of the
|
204
|
+
exception (underscorified) one of the following locations, use that:
|
205
|
+
** config[:error_template_dir]/
|
206
|
+
** RAILS_ROOT/public/
|
207
|
+
** WRANGLER_ROOT/rails/app/views/wrangler/
|
208
|
+
# :default_error_template
|
209
|
+
# :absolute_last_resort_default_error_template
|
210
|
+
|
211
|
+
== Using outside a Controller:
|
212
|
+
You can still use Wrangler outside the context of a Controller class. If you'll
|
213
|
+
be running within the context of an object instance, you can just include Wrangler
|
214
|
+
in the object's class. If you'll be running 'static' code, you can refer to
|
215
|
+
relevant methods via the Wrangler module. Note that in both cases, you'll be
|
216
|
+
calling the notify_on_error() method. Also note that the notify_on_error()
|
217
|
+
method will re-raise the exception that occurred in the block, so you may want
|
218
|
+
to begin/rescue/end around the notify_on_error() method call
|
219
|
+
|
220
|
+
using in an object instance:
|
221
|
+
|
222
|
+
class MyClass
|
223
|
+
include Wrangler
|
224
|
+
|
225
|
+
def my_error_method; raise "error!"; end
|
226
|
+
|
227
|
+
def call_a_method
|
228
|
+
notify_on_error { my_error_method }
|
229
|
+
rescue => e
|
230
|
+
exit
|
231
|
+
end
|
232
|
+
end
|
233
|
+
|
234
|
+
using 'statically':
|
235
|
+
|
236
|
+
Wrangler::notify_on_error { run_some_method_that_might_raise_exceptions }
|
237
|
+
|
238
|
+
== Maintaining the Wrangler gem
|
239
|
+
Should be pretty straightforward. Note that we're using jeweler, so the .gemspec
|
240
|
+
isn't included in the git repos; it gets generated dynamically from the settings
|
241
|
+
in Rakefile.
|
242
|
+
|
243
|
+
To build:
|
244
|
+
|
245
|
+
cd .../wrangler
|
246
|
+
rake gemspec
|
247
|
+
rake build
|
@@ -0,0 +1,280 @@
|
|
1
|
+
module Wrangler
|
2
|
+
|
3
|
+
# a utility method that should only be used internally. don't call this; it
|
4
|
+
# should only be called once by the Config class and you can get/set it there.
|
5
|
+
# returns a mapping from exception classes to http status codes
|
6
|
+
#-----------------------------------------------------------------------------
|
7
|
+
def self.codes_for_exception_classes
|
8
|
+
classes = {
|
9
|
+
# These are standard errors in rails / ruby
|
10
|
+
NameError => "503",
|
11
|
+
TypeError => "503",
|
12
|
+
RuntimeError => "500",
|
13
|
+
ArgumentError => "500",
|
14
|
+
# the default mapping for an unrecognized exception class
|
15
|
+
:default => "500"
|
16
|
+
}
|
17
|
+
|
18
|
+
# from exception_notification gem:
|
19
|
+
# Highly dependent on the verison of rails, so we're very protective about these'
|
20
|
+
classes.merge!({ ActionView::TemplateError => "500"}) if defined?(ActionView) && ActionView.const_defined?(:TemplateError)
|
21
|
+
classes.merge!({ ActiveRecord::RecordNotFound => "400" }) if defined?(ActiveRecord) && ActiveRecord.const_defined?(:RecordNotFound)
|
22
|
+
classes.merge!({ ActiveResource::ResourceNotFound => "404" }) if defined?(ActiveResource) && ActiveResource.const_defined?(:ResourceNotFound)
|
23
|
+
|
24
|
+
# from exception_notification gem:
|
25
|
+
if defined?(ActionController)
|
26
|
+
classes.merge!({ ActionController::UnknownController => "404" }) if ActionController.const_defined?(:UnknownController)
|
27
|
+
classes.merge!({ ActionController::MissingTemplate => "404" }) if ActionController.const_defined?(:MissingTemplate)
|
28
|
+
classes.merge!({ ActionController::MethodNotAllowed => "405" }) if ActionController.const_defined?(:MethodNotAllowed)
|
29
|
+
classes.merge!({ ActionController::UnknownAction => "501" }) if ActionController.const_defined?(:UnknownAction)
|
30
|
+
classes.merge!({ ActionController::RoutingError => "404" }) if ActionController.const_defined?(:RoutingError)
|
31
|
+
classes.merge!({ ActionController::InvalidAuthenticityToken => "405" }) if ActionController.const_defined?(:InvalidAuthenticityToken)
|
32
|
+
end
|
33
|
+
|
34
|
+
return classes
|
35
|
+
end
|
36
|
+
|
37
|
+
# class that holds configuration for the exception handling logic. may also
|
38
|
+
# include a helper method or two, but the main interaction with
|
39
|
+
# ExceptionHandler is setting and getting config, e.g.
|
40
|
+
#
|
41
|
+
# Wrangler::ExceptionHandler.configure do |handler_config|
|
42
|
+
# handler_config.merge! :key => value
|
43
|
+
# end
|
44
|
+
#-----------------------------------------------------------------------------
|
45
|
+
class ExceptionHandler
|
46
|
+
|
47
|
+
# the default configuration
|
48
|
+
@@config ||= {
|
49
|
+
:app_name => '',
|
50
|
+
:handle_local_errors => false,
|
51
|
+
:handle_public_errors => true,
|
52
|
+
# send email for local reqeusts. ignored if :handle_local_errors false
|
53
|
+
:notify_on_local_error => false,
|
54
|
+
# send email for public requests. ignored if :handle_public_errors false
|
55
|
+
:notify_on_public_error => true,
|
56
|
+
# send email for exceptions caught outside of a controller context
|
57
|
+
:notify_on_background_error => true,
|
58
|
+
# configure whether to send emails synchronously or asynchronously
|
59
|
+
# using delayed_job (these can be true even if delayed job is not
|
60
|
+
# installed, in which case, will just send emails synchronously anyway)
|
61
|
+
:delayed_job_for_controller_errors => false,
|
62
|
+
:delayed_job_for_non_controller_errors => false,
|
63
|
+
# mappings from exception classes to http status codes (see above)
|
64
|
+
# add/remove from this list as desired in environment configuration
|
65
|
+
:error_class_status_codes => Wrangler::codes_for_exception_classes,
|
66
|
+
# explicitly indicate which exceptions to send email notifications for
|
67
|
+
:notify_exception_classes => %w(),
|
68
|
+
# indicate which http status codes should result in email notification
|
69
|
+
:notify_status_codes => %w( 405 500 503 ),
|
70
|
+
# where to look for app-specific error page templates (ones you create
|
71
|
+
# yourself, for example...there are some defaults in this gem you can
|
72
|
+
# use as well...and that are configured already by default)
|
73
|
+
:error_template_dir => File.join(RAILS_ROOT, 'app', 'views', 'error'),
|
74
|
+
# excplicit mappings from exception class to arbitrary error page
|
75
|
+
# templates, different set for html and js responses (Wrangler determines
|
76
|
+
# which to use automatically, so you can have an entry in both
|
77
|
+
# hashes for the same error class)
|
78
|
+
:error_class_html_templates => {},
|
79
|
+
:error_class_js_templates => {},
|
80
|
+
# you can specify a fallback failsafe error template to render if
|
81
|
+
# no appropriate template is found in the usual places (you shouldn't
|
82
|
+
# rely on this, and error messages will be logged if this template is
|
83
|
+
# used). note: there's an even more failsafe template included in the
|
84
|
+
# gem (absolute_last_resort...) below, but DON'T CHANGE IT!!!
|
85
|
+
:default_error_template => '',
|
86
|
+
# these filter out any HTTP params that are undesired
|
87
|
+
:request_env_to_skip => [ /^rack\./,
|
88
|
+
"action_controller.rescue.request",
|
89
|
+
"action_controller.rescue.response" ],
|
90
|
+
# mapping from exception classes to templates (if desired), express
|
91
|
+
# in absolute paths. use wildcards like on cmd line (glob-like), NOT
|
92
|
+
# regexp-style
|
93
|
+
|
94
|
+
# just DON'T change this! this is the error template of last resort!
|
95
|
+
:absolute_last_resort_default_error_template =>
|
96
|
+
File.join(WRANGLER_ROOT,'rails','app','views','wrangler','500.html')
|
97
|
+
}
|
98
|
+
|
99
|
+
cattr_accessor :config
|
100
|
+
|
101
|
+
# allows for overriding default configuration settings.
|
102
|
+
# in your environment.rb or environments/<env name>.rb, use a block that
|
103
|
+
# accepts one argument
|
104
|
+
# * recommend against naming it 'config' as you will probably be calling it
|
105
|
+
# within the config block in env.rb...):
|
106
|
+
# * note that some of the config values are arrays or hashes; you can
|
107
|
+
# overwrite them completely, delete or insert/merge new entries into the
|
108
|
+
# default values as you see fit...but in most cases, recommend AGAINST
|
109
|
+
# overwriting the arrays/hashes completely unless you don't want to
|
110
|
+
# take advantage of lots of out-of-the-box config
|
111
|
+
#
|
112
|
+
# Wrangler::ExceptionHandler.configure do |handler_config|
|
113
|
+
# handler_config[:key1] = value1
|
114
|
+
# handler_config[:key2] = value2
|
115
|
+
# handler_config[:key_for_a_hash].merge! :subkey => value
|
116
|
+
# handler_config[:key_for_an_array] << another_value
|
117
|
+
# end
|
118
|
+
#
|
119
|
+
# OR
|
120
|
+
#
|
121
|
+
# Wrangler::ExceptionHandler.configure do |handler_config|
|
122
|
+
# handler_config.merge! :key1 => value1,
|
123
|
+
# :key2 => value2,
|
124
|
+
# handler_config[:key_for_a_hash].merge! :subkey => value
|
125
|
+
# handler_config[:key_for_an_array] << another_value
|
126
|
+
# end
|
127
|
+
#
|
128
|
+
# NOTE: sure, you can change this configuration on the fly in your app, but
|
129
|
+
# we don't recommend it. plus, if you do and you're using delayed_job, there
|
130
|
+
# may end up being configuration differences between the rails process and
|
131
|
+
# the delayed_job process, resulting in unexpected behavior. so recommend
|
132
|
+
# you just modify this in the environment config files...or if you're doing
|
133
|
+
# something sneaky, you're on your own.
|
134
|
+
#-----------------------------------------------------------------------------
|
135
|
+
def self.configure(&block)
|
136
|
+
yield @@config
|
137
|
+
end
|
138
|
+
|
139
|
+
|
140
|
+
# translate the exception class to an http status code, using default
|
141
|
+
# code (set in config) if the exception class isn't excplicitly mapped
|
142
|
+
# to a status code in config
|
143
|
+
#---------------------------------------------------------------------------
|
144
|
+
def self.status_code_for_exception(exception)
|
145
|
+
if exception.respond_to?(:status_code)
|
146
|
+
return exception.status_code
|
147
|
+
else
|
148
|
+
return config[:error_class_status_codes][exception.class] ||
|
149
|
+
config[:error_class_status_codes][:default]
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
end # end ExceptionHandler class
|
154
|
+
|
155
|
+
##############################################################################
|
156
|
+
# actual exception handling code
|
157
|
+
##############################################################################
|
158
|
+
|
159
|
+
# make all of these instance methods also module functions
|
160
|
+
module_function
|
161
|
+
|
162
|
+
# execute the code block passed as an argument, and follow notification
|
163
|
+
# rules if an exception bubbles out of the block.
|
164
|
+
#
|
165
|
+
# return value:
|
166
|
+
# * if an exception bubbles out of the block, the exception is re-raised to
|
167
|
+
# calling code.
|
168
|
+
# * otherwise, returns nil
|
169
|
+
#-----------------------------------------------------------------------------
|
170
|
+
def notify_on_error(proc_name = nil, &block)
|
171
|
+
begin
|
172
|
+
yield
|
173
|
+
rescue => exception
|
174
|
+
options = {}
|
175
|
+
options.merge! :proc_name => proc_name unless proc_name.nil?
|
176
|
+
handle_exception(exception, options)
|
177
|
+
end
|
178
|
+
|
179
|
+
return nil
|
180
|
+
end
|
181
|
+
|
182
|
+
# the main exception-handling method. decides whether to notify or not,
|
183
|
+
# whether to render an error page or not, and to make it happen.
|
184
|
+
#
|
185
|
+
# arguments:
|
186
|
+
# - exception: the exception that was caught
|
187
|
+
#
|
188
|
+
# options:
|
189
|
+
# :request: the request object (if any) that resulted in the exception
|
190
|
+
# :render_errors: boolean indicating if an error page should be rendered
|
191
|
+
# or not (Rails only)
|
192
|
+
# :proc_name: a string representation of the process/app that was running
|
193
|
+
# when the exception was raised. default value is
|
194
|
+
# Wrangler::ExceptionHandler.config[:app_name].
|
195
|
+
#-----------------------------------------------------------------------------
|
196
|
+
def handle_exception(exception, options = {})
|
197
|
+
request = options[:request]
|
198
|
+
render_errors = options[:render_errors] || false
|
199
|
+
proc_name = options[:proc_name] || config[:app_name]
|
200
|
+
|
201
|
+
status_code = Wrangler::ExceptionHandler.status_code_for_exception(exception)
|
202
|
+
request_data = request_data_from_request(request) unless request.nil?
|
203
|
+
|
204
|
+
if notify_on_exception?(exception, status_code)
|
205
|
+
if notify_with_delayed_job?
|
206
|
+
# don't pass in request as it contains not-easily-serializable stuff
|
207
|
+
Wrangler::ExceptionNotifier.send_later(:deliver_exception_notification,
|
208
|
+
exception,
|
209
|
+
proc_name,
|
210
|
+
exception.backtrace,
|
211
|
+
status_code,
|
212
|
+
request_data)
|
213
|
+
else
|
214
|
+
Wrangler::ExceptionNotifier.deliver_exception_notification(exception,
|
215
|
+
proc_name,
|
216
|
+
exception.backtrace,
|
217
|
+
status_code,
|
218
|
+
request_data,
|
219
|
+
request)
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
log_exception(exception, request_data, status_code)
|
224
|
+
|
225
|
+
if render_errors
|
226
|
+
render_error_template(exception, status_code)
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
230
|
+
|
231
|
+
# determine if the app is configured to notify for the given exception or
|
232
|
+
# status code
|
233
|
+
#-----------------------------------------------------------------------------
|
234
|
+
def notify_on_exception?(exception, status_code = nil)
|
235
|
+
# first determine if we're configured to notify given the context of the
|
236
|
+
# exception
|
237
|
+
if self.respond_to?(:local_request?)
|
238
|
+
if (local_request? && config[:notify_on_local_error]) ||
|
239
|
+
(!local_request? && config[:notify_on_public_error])
|
240
|
+
notify = true
|
241
|
+
else
|
242
|
+
notify = false
|
243
|
+
end
|
244
|
+
else
|
245
|
+
notify = config[:notify_on_background_error]
|
246
|
+
end
|
247
|
+
|
248
|
+
# now if config says notify in this case, check if we're configured to
|
249
|
+
# notify for this exception or this status code
|
250
|
+
return notify &&
|
251
|
+
(config[:notify_exception_classes].include?(exception.class) ||
|
252
|
+
config[:notify_status_codes].include?(status_code))
|
253
|
+
end
|
254
|
+
|
255
|
+
# determine if email should be sent with delayed job or not (delayed job
|
256
|
+
# must be installed and config set to use delayed job
|
257
|
+
#-----------------------------------------------------------------------------
|
258
|
+
def notify_with_delayed_job?
|
259
|
+
use_dj = false
|
260
|
+
|
261
|
+
if self.is_a?(ActionController::Base)
|
262
|
+
if config[:delayed_job_for_controller_errors] &&
|
263
|
+
ExceptionNotifier.respond_to?(:send_later)
|
264
|
+
use_dj = true
|
265
|
+
else
|
266
|
+
use_dj = false
|
267
|
+
end
|
268
|
+
else
|
269
|
+
if config[:delayed_job_for_non_controller_errors] &&
|
270
|
+
ExceptionNotifier.respond_to?(:send_later)
|
271
|
+
use_dj = true
|
272
|
+
else
|
273
|
+
use_dj = false
|
274
|
+
end
|
275
|
+
end
|
276
|
+
|
277
|
+
return use_dj
|
278
|
+
end
|
279
|
+
|
280
|
+
end
|