wrangler 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|