pboling-super_exception_notifier 1.6.5
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/MIT-LICENSE +21 -0
- data/README.rdoc +419 -0
- data/VERSION.yml +4 -0
- data/exception_notification.gemspec +71 -0
- data/init.rb +1 -0
- data/lib/exception_notifiable.rb +278 -0
- data/lib/exception_notifier.rb +108 -0
- data/lib/exception_notifier_helper.rb +58 -0
- data/lib/hooks_notifier.rb +53 -0
- data/lib/notifiable.rb +8 -0
- data/lib/super_exception_notifier/custom_exception_classes.rb +16 -0
- data/lib/super_exception_notifier/custom_exception_methods.rb +50 -0
- data/rails/app/views/exception_notifiable/400.html +5 -0
- data/rails/app/views/exception_notifiable/403.html +6 -0
- data/rails/app/views/exception_notifiable/404.html +6 -0
- data/rails/app/views/exception_notifiable/405.html +6 -0
- data/rails/app/views/exception_notifiable/410.html +7 -0
- data/rails/app/views/exception_notifiable/418.html +6 -0
- data/rails/app/views/exception_notifiable/422.html +5 -0
- data/rails/app/views/exception_notifiable/423.html +6 -0
- data/rails/app/views/exception_notifiable/501.html +8 -0
- data/rails/app/views/exception_notifiable/503.html +6 -0
- data/rails/init.rb +18 -0
- data/test/exception_notifier_helper_test.rb +76 -0
- data/test/exception_notify_functional_test.rb +102 -0
- data/test/mocks/404.html +1 -0
- data/test/mocks/500.html +1 -0
- data/test/mocks/controllers.rb +46 -0
- data/test/test_helper.rb +28 -0
- data/views/exception_notifier/_backtrace.html.erb +1 -0
- data/views/exception_notifier/_environment.html.erb +14 -0
- data/views/exception_notifier/_inspect_model.html.erb +16 -0
- data/views/exception_notifier/_request.html.erb +8 -0
- data/views/exception_notifier/_session.html.erb +7 -0
- data/views/exception_notifier/_title.html.erb +3 -0
- data/views/exception_notifier/background_exception_notification.text.plain.erb +6 -0
- data/views/exception_notifier/exception_notification.text.plain.erb +10 -0
- metadata +100 -0
data/init.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require File.dirname(__FILE__) + "/rails/init"
|
@@ -0,0 +1,278 @@
|
|
1
|
+
require 'ipaddr'
|
2
|
+
|
3
|
+
module ExceptionNotifiable
|
4
|
+
include SuperExceptionNotifier::CustomExceptionClasses
|
5
|
+
include SuperExceptionNotifier::CustomExceptionMethods
|
6
|
+
include HooksNotifier
|
7
|
+
|
8
|
+
unless defined?(SILENT_EXCEPTIONS)
|
9
|
+
SILENT_EXCEPTIONS = []
|
10
|
+
SILENT_EXCEPTIONS << ActiveRecord::RecordNotFound if defined?(ActiveRecord)
|
11
|
+
SILENT_EXCEPTIONS << [
|
12
|
+
ActionController::UnknownController,
|
13
|
+
ActionController::UnknownAction,
|
14
|
+
ActionController::RoutingError,
|
15
|
+
ActionController::MethodNotAllowed
|
16
|
+
] if defined?(ActionController)
|
17
|
+
end
|
18
|
+
|
19
|
+
HTTP_ERROR_CODES = {
|
20
|
+
"400" => "Bad Request",
|
21
|
+
"403" => "Forbidden",
|
22
|
+
"404" => "Not Found",
|
23
|
+
"405" => "Method Not Allowed",
|
24
|
+
"410" => "Gone",
|
25
|
+
"418" => "I�m a teapot",
|
26
|
+
"422" => "Unprocessable Entity",
|
27
|
+
"423" => "Locked",
|
28
|
+
"500" => "Internal Server Error",
|
29
|
+
"501" => "Not Implemented",
|
30
|
+
"503" => "Service Unavailable"
|
31
|
+
} unless defined?(HTTP_ERROR_CODES)
|
32
|
+
|
33
|
+
def self.codes_for_rails_error_classes
|
34
|
+
classes = {
|
35
|
+
# These are standard errors in rails / ruby
|
36
|
+
NameError => "503",
|
37
|
+
TypeError => "503",
|
38
|
+
RuntimeError => "500",
|
39
|
+
# These are custom error names defined in lib/super_exception_notifier/custom_exception_classes
|
40
|
+
AccessDenied => "403",
|
41
|
+
PageNotFound => "404",
|
42
|
+
InvalidMethod => "405",
|
43
|
+
ResourceGone => "410",
|
44
|
+
CorruptData => "422",
|
45
|
+
NoMethodError => "500",
|
46
|
+
NotImplemented => "501",
|
47
|
+
MethodDisabled => "200"
|
48
|
+
}
|
49
|
+
# Highly dependent on the verison of rails, so we're very protective about these'
|
50
|
+
classes.merge!({ ActionView::TemplateError => "500"}) if defined?(ActionView) && ActionView.const_defined?(:TemplateError)
|
51
|
+
classes.merge!({ ActiveRecord::RecordNotFound => "400" }) if defined?(ActiveRecord) && ActiveRecord.const_defined?(:RecordNotFound)
|
52
|
+
classes.merge!({ ActiveResource::ResourceNotFound => "404" }) if defined?(ActiveResource) && ActiveResource.const_defined?(:ResourceNotFound)
|
53
|
+
|
54
|
+
if defined?(ActionController)
|
55
|
+
classes.merge!({ ActionController::UnknownController => "404" }) if ActionController.const_defined?(:UnknownController)
|
56
|
+
classes.merge!({ ActionController::MissingTemplate => "404" }) if ActionController.const_defined?(:MissingTemplate)
|
57
|
+
classes.merge!({ ActionController::MethodNotAllowed => "405" }) if ActionController.const_defined?(:MethodNotAllowed)
|
58
|
+
classes.merge!({ ActionController::UnknownAction => "501" }) if ActionController.const_defined?(:UnknownAction)
|
59
|
+
classes.merge!({ ActionController::RoutingError => "404" }) if ActionController.const_defined?(:RoutingError)
|
60
|
+
classes.merge!({ ActionController::InvalidAuthenticityToken => "405" }) if ActionController.const_defined?(:InvalidAuthenticityToken)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def self.included(base)
|
65
|
+
base.extend ClassMethods
|
66
|
+
|
67
|
+
# Adds the following class attributes to the classes that include ExceptionNotifiable
|
68
|
+
# HTTP status codes and what their 'English' status message is
|
69
|
+
# Rails error classes to rescue and how to rescue them
|
70
|
+
# error_layout:
|
71
|
+
# can be defined at controller level to the name of the layout,
|
72
|
+
# or set to true to render the controller's own default layout,
|
73
|
+
# or set to false to render errors with no layout
|
74
|
+
base.cattr_accessor :http_error_codes
|
75
|
+
base.http_error_codes = HTTP_ERROR_CODES
|
76
|
+
base.cattr_accessor :error_layout
|
77
|
+
base.error_layout = nil
|
78
|
+
base.cattr_accessor :rails_error_classes
|
79
|
+
base.rails_error_classes = self.codes_for_rails_error_classes
|
80
|
+
base.cattr_accessor :exception_notifier_verbose
|
81
|
+
base.exception_notifier_verbose = false
|
82
|
+
base.cattr_accessor :silent_exceptions
|
83
|
+
base.silent_exceptions = SILENT_EXCEPTIONS
|
84
|
+
end
|
85
|
+
|
86
|
+
module ClassMethods
|
87
|
+
# specifies ip addresses that should be handled as though local
|
88
|
+
def consider_local(*args)
|
89
|
+
local_addresses.concat(args.flatten.map { |a| IPAddr.new(a) })
|
90
|
+
end
|
91
|
+
|
92
|
+
def local_addresses
|
93
|
+
addresses = read_inheritable_attribute(:local_addresses)
|
94
|
+
unless addresses
|
95
|
+
addresses = [IPAddr.new("127.0.0.1")]
|
96
|
+
write_inheritable_attribute(:local_addresses, addresses)
|
97
|
+
end
|
98
|
+
addresses
|
99
|
+
end
|
100
|
+
|
101
|
+
# set the exception_data deliverer OR retrieve the exception_data
|
102
|
+
def exception_data(deliverer = nil)
|
103
|
+
if deliverer
|
104
|
+
write_inheritable_attribute(:exception_data, deliverer)
|
105
|
+
else
|
106
|
+
read_inheritable_attribute(:exception_data)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
private
|
112
|
+
|
113
|
+
# overrides Rails' local_request? method to also check any ip
|
114
|
+
# addresses specified through consider_local.
|
115
|
+
def local_request?
|
116
|
+
remote = IPAddr.new(request.remote_ip)
|
117
|
+
!self.class.local_addresses.detect { |addr| addr.include?(remote) }.nil?
|
118
|
+
end
|
119
|
+
|
120
|
+
# When the action being executed has its own local error handling (rescue)
|
121
|
+
def rescue_with_handler(exception)
|
122
|
+
to_return = super
|
123
|
+
if to_return
|
124
|
+
data = get_exception_data
|
125
|
+
send_email = should_notify_on_exception?(exception)
|
126
|
+
send_web_hooks = !ExceptionNotifier.config[:web_hooks].empty?
|
127
|
+
the_blamed = ExceptionNotifier.config[:git_repo_path].nil? ? nil : lay_blame(exception)
|
128
|
+
verbose_output(exception, "N/A", "rescued by handler", send_email, send_web_hooks, nil, the_blamed) if self.class.exception_notifier_verbose
|
129
|
+
# Send the exception notificaiton email
|
130
|
+
perform_exception_notify_mailing(exception, data, nil, the_blamed) if send_email
|
131
|
+
# Send Web Hook requests
|
132
|
+
HooksNotifier.deliver_exception_to_web_hooks(ExceptionNotifier.config, exception, self, request, data, the_blamed) if send_web_hooks
|
133
|
+
end
|
134
|
+
to_return
|
135
|
+
end
|
136
|
+
|
137
|
+
# When the action being executed is letting SEN handle the exception completely
|
138
|
+
def rescue_action_in_public(exception)
|
139
|
+
# If the error class is NOT listed in the rails_errror_class hash then we get a generic 500 error:
|
140
|
+
# 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
|
141
|
+
# OTW the error class is listed!
|
142
|
+
status_code = status_code_for_exception(exception)
|
143
|
+
if status_code == '200'
|
144
|
+
notify_and_render_error_template(status_code, request, exception, exception_to_filename(exception))
|
145
|
+
else
|
146
|
+
notify_and_render_error_template(status_code, request, exception)
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
def notify_and_render_error_template(status_cd, request, exception, file_path = nil)
|
151
|
+
status = self.class.http_error_codes[status_cd] ? status_cd + " " + self.class.http_error_codes[status_cd] : status_cd
|
152
|
+
file = file_path ? ExceptionNotifier.get_view_path(file_path) : ExceptionNotifier.get_view_path(status_cd)
|
153
|
+
data = get_exception_data
|
154
|
+
send_email = should_notify_on_exception?(exception, status_cd)
|
155
|
+
send_web_hooks = !ExceptionNotifier.config[:web_hooks].empty?
|
156
|
+
the_blamed = ExceptionNotifier.config[:git_repo_path].nil? ? nil : lay_blame(exception)
|
157
|
+
|
158
|
+
# Debugging output
|
159
|
+
verbose_output(exception, status_cd, file, send_email, send_web_hooks, request, the_blamed) if self.class.exception_notifier_verbose
|
160
|
+
# Send the email before rendering to avert possible errors on render preventing the email from being sent.
|
161
|
+
perform_exception_notify_mailing(exception, data, request, the_blamed) if send_email
|
162
|
+
# Send Web Hook requests
|
163
|
+
HooksNotifier.deliver_exception_to_web_hooks(ExceptionNotifier.config, exception, self, request, data, the_blamed) if send_web_hooks
|
164
|
+
# Render the error page to the end user
|
165
|
+
render_error_template(file, status)
|
166
|
+
end
|
167
|
+
|
168
|
+
def get_exception_data
|
169
|
+
deliverer = self.class.exception_data
|
170
|
+
return case deliverer
|
171
|
+
when nil then {}
|
172
|
+
when Symbol then send(deliverer)
|
173
|
+
when Proc then deliverer.call(self)
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
def render_error_template(file, status)
|
178
|
+
respond_to do |type|
|
179
|
+
type.html { render :file => file,
|
180
|
+
:layout => self.class.error_layout,
|
181
|
+
:status => status }
|
182
|
+
type.all { render :nothing => true,
|
183
|
+
:status => status}
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
def verbose_output(exception, status_cd, file, send_email, send_web_hooks, request = nil, the_blamed = nil)
|
188
|
+
puts "[EXCEPTION] #{exception}"
|
189
|
+
puts "[EXCEPTION CLASS] #{exception.class}"
|
190
|
+
puts "[EXCEPTION STATUS_CD] #{status_cd}"
|
191
|
+
puts "[ERROR LAYOUT] #{self.class.error_layout}" if self.class.error_layout
|
192
|
+
puts "[ERROR VIEW PATH] #{ExceptionNotifier.config[:view_path]}" if !ExceptionNotifier.nil? && !ExceptionNotifier.config[:view_path].nil?
|
193
|
+
puts "[ERROR RENDER] #{file}"
|
194
|
+
puts "[ERROR EMAIL] #{send_email ? "YES" : "NO"}"
|
195
|
+
puts "[ERROR WEB HOOKS] #{send_web_hooks ? "YES" : "NO"}"
|
196
|
+
puts "[COMPAT MODE] #{ExceptionNotifierHelper::COMPAT_MODE ? "Yes" : "No"}"
|
197
|
+
puts "[THE BLAMED] #{the_blamed}"
|
198
|
+
req = request ? " for request_uri=#{request.request_uri} and env=#{request.env.inspect}" : ""
|
199
|
+
logger.error("render_error(#{status_cd}, #{self.class.http_error_codes[status_cd]}) invoked#{req}") if !logger.nil?
|
200
|
+
end
|
201
|
+
|
202
|
+
def perform_exception_notify_mailing(exception, data, request = nil, the_blamed = nil)
|
203
|
+
if !ExceptionNotifier.config[:exception_recipients].blank?
|
204
|
+
# Send email with ActionMailer
|
205
|
+
ExceptionNotifier.deliver_exception_notification(exception, self,
|
206
|
+
request, data, the_blamed)
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
def should_notify_on_exception?(exception, status_cd = nil)
|
211
|
+
# First honor the custom settings from environment
|
212
|
+
return false if ExceptionNotifier.config[:render_only]
|
213
|
+
# don't mail exceptions raised locally
|
214
|
+
return false if ExceptionNotifier.config[:skip_local_notification] && is_local?
|
215
|
+
# don't mail exceptions raised that match ExceptionNotifiable.silent_exceptions
|
216
|
+
return false if self.class.silent_exceptions.any? {|klass| klass === exception }
|
217
|
+
return true if ExceptionNotifier.config[:send_email_error_classes].include?(exception)
|
218
|
+
return true if !status_cd.nil? && ExceptionNotifier.config[:send_email_error_codes].include?(status_cd)
|
219
|
+
return ExceptionNotifier.config[:send_email_other_errors]
|
220
|
+
end
|
221
|
+
|
222
|
+
def is_local?
|
223
|
+
(consider_all_requests_local || local_request?)
|
224
|
+
end
|
225
|
+
|
226
|
+
def status_code_for_exception(exception)
|
227
|
+
self.class.rails_error_classes[exception.class].nil? ? '500' : self.class.rails_error_classes[exception.class].blank? ? '200' : self.class.rails_error_classes[exception.class]
|
228
|
+
end
|
229
|
+
|
230
|
+
def exception_to_filename(exception)
|
231
|
+
exception.to_s.delete(':').gsub( /([A-Za-z])([A-Z])/, '\1' << '_' << '\2' ).downcase
|
232
|
+
end
|
233
|
+
|
234
|
+
def lay_blame(exception)
|
235
|
+
error = {}
|
236
|
+
unless(ExceptionNotifier.config[:git_repo_path].nil?)
|
237
|
+
if(exception.class == ActionView::TemplateError)
|
238
|
+
blame = blame_output(exception.line_number, "app/views/#{exception.file_name}")
|
239
|
+
error[:author] = blame[/^author\s.+$/].gsub(/author\s/,'')
|
240
|
+
error[:line] = exception.line_number
|
241
|
+
error[:file] = exception.file_name
|
242
|
+
else
|
243
|
+
exception.backtrace.each do |line|
|
244
|
+
file = exception_in_project?(line[/^.+?(?=:)/])
|
245
|
+
unless(file.nil?)
|
246
|
+
line_number = line[/:\d+:/].gsub(/[^\d]/,'')
|
247
|
+
# Use relative path or weird stuff happens
|
248
|
+
blame = blame_output(line_number, file.gsub(Regexp.new("#{RAILS_ROOT}/"),''))
|
249
|
+
error[:author] = blame[/^author\s.+$/].sub(/author\s/,'')
|
250
|
+
error[:line] = line_number
|
251
|
+
error[:file] = file
|
252
|
+
break
|
253
|
+
end
|
254
|
+
end
|
255
|
+
end
|
256
|
+
end
|
257
|
+
error
|
258
|
+
end
|
259
|
+
|
260
|
+
def blame_output(line_number, path)
|
261
|
+
app_directory = Dir.pwd
|
262
|
+
Dir.chdir ExceptionNotifier.config[:git_repo_path]
|
263
|
+
blame = `git blame -p -L #{line_number},#{line_number} #{path}`
|
264
|
+
Dir.chdir app_directory
|
265
|
+
|
266
|
+
blame
|
267
|
+
end
|
268
|
+
|
269
|
+
def exception_in_project?(path) # should be a path like /path/to/broken/thingy.rb
|
270
|
+
dir = File.split(path).first rescue ''
|
271
|
+
if(File.directory?(dir) and !(path =~ /vendor\/plugins/) and path.include?(RAILS_ROOT))
|
272
|
+
path
|
273
|
+
else
|
274
|
+
nil
|
275
|
+
end
|
276
|
+
end
|
277
|
+
|
278
|
+
end
|
@@ -0,0 +1,108 @@
|
|
1
|
+
require 'pathname'
|
2
|
+
|
3
|
+
class ExceptionNotifier < ActionMailer::Base
|
4
|
+
|
5
|
+
@@config = {
|
6
|
+
# If left empty web hooks will not be engaged
|
7
|
+
:web_hooks => [],
|
8
|
+
:app_name => "[MYAPP]",
|
9
|
+
:version => "0.0.0",
|
10
|
+
:sender_address => %("#{(defined?(Rails) ? Rails.env : RAILS_ENV).capitalize} Error" <super.exception.notifier@example.com>),
|
11
|
+
:exception_recipients => [],
|
12
|
+
# Customize the subject line
|
13
|
+
:subject_prepend => "[#{(defined?(Rails) ? Rails.env : RAILS_ENV).capitalize} ERROR] ",
|
14
|
+
:subject_append => nil,
|
15
|
+
# Include which sections of the exception email?
|
16
|
+
:sections => %w(request session environment backtrace),
|
17
|
+
# Only use this gem to render, never email
|
18
|
+
:render_only => false,
|
19
|
+
:skip_local_notification => true,
|
20
|
+
:view_path => nil,
|
21
|
+
#Error Notification will be sent if the HTTP response code for the error matches one of the following error codes
|
22
|
+
:send_email_error_codes => %W( 405 500 503 ),
|
23
|
+
#Error Notification will be sent if the error class matches one of the following error error classes
|
24
|
+
:send_email_error_classes => %W( ),
|
25
|
+
:send_email_other_errors => true,
|
26
|
+
:git_repo_path => nil,
|
27
|
+
:template_root => "#{File.dirname(__FILE__)}/../views"
|
28
|
+
}
|
29
|
+
|
30
|
+
cattr_accessor :config
|
31
|
+
|
32
|
+
def self.configure_exception_notifier(&block)
|
33
|
+
yield @@config
|
34
|
+
end
|
35
|
+
|
36
|
+
self.template_root = config[:template_root]
|
37
|
+
|
38
|
+
def self.reloadable?() false end
|
39
|
+
|
40
|
+
# What is the path of the file we will render to the user?
|
41
|
+
def self.get_view_path(status_cd)
|
42
|
+
if File.exist?("#{RAILS_ROOT}/public/#{status_cd}.html")
|
43
|
+
"#{RAILS_ROOT}/public/#{status_cd}.html"
|
44
|
+
elsif !config[:view_path].nil? && File.exist?("#{RAILS_ROOT}/#{config[:view_path]}/#{status_cd}.html")
|
45
|
+
"#{RAILS_ROOT}/#{config[:view_path]}/#{status_cd}.html"
|
46
|
+
elsif File.exist?("#{File.dirname(__FILE__)}/../rails/app/views/exception_notifiable/#{status_cd}.html")
|
47
|
+
"#{File.dirname(__FILE__)}/../rails/app/views/exception_notifiable/#{status_cd}.html"
|
48
|
+
else
|
49
|
+
"#{File.dirname(__FILE__)}/../rails/app/views/exception_notifiable/500.html"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def exception_notification(exception, controller = nil, request = nil, data={}, the_blamed=nil)
|
54
|
+
body_hash = error_environment_data_hash(exception, controller, request, data, the_blamed)
|
55
|
+
#Prefer to have custom, potentially HTML email templates available
|
56
|
+
#content_type "text/plain"
|
57
|
+
recipients config[:exception_recipients]
|
58
|
+
from config[:sender_address]
|
59
|
+
|
60
|
+
request.session.inspect unless request.nil? # Ensure session data is loaded (Rails 2.3 lazy-loading)
|
61
|
+
|
62
|
+
subject "#{config[:subject_prepend]}#{body_hash[:location]} (#{exception.class}) #{exception.message.inspect}#{config[:subject_append]}"
|
63
|
+
body body_hash
|
64
|
+
end
|
65
|
+
|
66
|
+
def background_exception_notification(exception, data = {}, the_blamed = nil)
|
67
|
+
exception_notification(exception, nil, nil, data, the_blamed)
|
68
|
+
end
|
69
|
+
|
70
|
+
private
|
71
|
+
|
72
|
+
def error_environment_data_hash(exception, controller = nil, request = nil, data={}, the_blamed=nil)
|
73
|
+
data.merge!({
|
74
|
+
:exception => exception,
|
75
|
+
:backtrace => sanitize_backtrace(exception.backtrace),
|
76
|
+
:rails_root => rails_root,
|
77
|
+
:data => data,
|
78
|
+
:the_blamed => the_blamed
|
79
|
+
})
|
80
|
+
|
81
|
+
if controller && request
|
82
|
+
data.merge!({
|
83
|
+
:location => "#{controller.controller_name}##{controller.action_name}",
|
84
|
+
:controller => controller,
|
85
|
+
:request => request,
|
86
|
+
:host => (request.env['HTTP_X_REAL_IP'] || request.env["HTTP_X_FORWARDED_HOST"] || request.env["HTTP_HOST"]),
|
87
|
+
:sections => config[:sections]
|
88
|
+
})
|
89
|
+
else
|
90
|
+
# TODO: with refactoring, the environment section could show useful ENV data even without a request
|
91
|
+
data.merge!({
|
92
|
+
:location => sanitize_backtrace([exception.backtrace.first]).first,
|
93
|
+
:sections => config[:sections] - %w(request session environment)
|
94
|
+
})
|
95
|
+
end
|
96
|
+
return data
|
97
|
+
end
|
98
|
+
|
99
|
+
def sanitize_backtrace(trace)
|
100
|
+
re = Regexp.new(/^#{Regexp.escape(rails_root)}/)
|
101
|
+
trace.map { |line| Pathname.new(line.gsub(re, "[RAILS_ROOT]")).cleanpath.to_s }
|
102
|
+
end
|
103
|
+
|
104
|
+
def rails_root
|
105
|
+
@rails_root ||= Pathname.new(RAILS_ROOT).cleanpath.to_s
|
106
|
+
end
|
107
|
+
|
108
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'pp'
|
2
|
+
|
3
|
+
module ExceptionNotifierHelper
|
4
|
+
VIEW_PATH = "views/exception_notifier" unless defined?(VIEW_PATH)
|
5
|
+
APP_PATH = "#{RAILS_ROOT}/app/#{VIEW_PATH}" unless defined?(APP_PATH)
|
6
|
+
PARAM_FILTER_REPLACEMENT = "[FILTERED]" unless defined?(PARAM_FILTER_REPLACEMENT)
|
7
|
+
COMPAT_MODE = defined?(RAILS_GEM_VERSION) ? RAILS_GEM_VERSION < '2' : false unless defined?(COMPAT_MODE)
|
8
|
+
|
9
|
+
def render_section(section)
|
10
|
+
RAILS_DEFAULT_LOGGER.info("rendering section #{section.inspect}")
|
11
|
+
summary = render_overridable(section).strip
|
12
|
+
unless summary.blank?
|
13
|
+
title = render_overridable(:title, :locals => { :title => section }).strip
|
14
|
+
"#{title}\n\n#{summary.gsub(/^/, " ")}\n\n"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def render_overridable(partial, options={})
|
19
|
+
if File.exist?(path = "#{APP_PATH}/_#{partial}.html.erb") ||
|
20
|
+
File.exist?(path = "#{File.dirname(__FILE__)}/../#{VIEW_PATH}/_#{partial}.html.erb") ||
|
21
|
+
File.exist?(path = "#{APP_PATH}/_#{partial}.rhtml") ||
|
22
|
+
File.exist?(path = "#{File.dirname(__FILE__)}/../#{VIEW_PATH}/_#{partial}.rhtml")
|
23
|
+
render(options.merge(:file => path, :use_full_path => false))
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def inspect_model_object(model, locals={})
|
28
|
+
render_overridable(:inspect_model,
|
29
|
+
:locals => { :inspect_model => model,
|
30
|
+
:show_instance_variables => true,
|
31
|
+
:show_attributes => true }.merge(locals))
|
32
|
+
end
|
33
|
+
|
34
|
+
def inspect_value(value)
|
35
|
+
len = 512
|
36
|
+
result = object_to_yaml(value).gsub(/\n/, "\n ").strip
|
37
|
+
result = result[0,len] + "... (#{result.length-len} bytes more)" if result.length > len+20
|
38
|
+
result
|
39
|
+
end
|
40
|
+
|
41
|
+
def object_to_yaml(object)
|
42
|
+
object.to_yaml.sub(/^---\s*/m, "")
|
43
|
+
end
|
44
|
+
|
45
|
+
def exclude_raw_post_parameters?
|
46
|
+
@controller && @controller.respond_to?(:filter_parameters)
|
47
|
+
end
|
48
|
+
|
49
|
+
def filter_sensitive_post_data_parameters(parameters)
|
50
|
+
exclude_raw_post_parameters? ? COMPAT_MODE ? @controller.filter_parameters(parameters) : @controller.__send__(:filter_parameters, parameters) : parameters
|
51
|
+
end
|
52
|
+
|
53
|
+
def filter_sensitive_post_data_from_env(env_key, env_value)
|
54
|
+
return env_value unless exclude_raw_post_parameters?
|
55
|
+
return PARAM_FILTER_REPLACEMENT if (env_key =~ /RAW_POST_DATA/i)
|
56
|
+
return COMPAT_MODE ? @controller.filter_parameters({env_key => env_value}).values[0] : @controller.__send__(:filter_parameters, {env_key => env_value}).values[0]
|
57
|
+
end
|
58
|
+
end
|