panmind-exception_notification 2.3.10

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.
@@ -0,0 +1,148 @@
1
+ = Purpose of this fork
2
+
3
+ Do not escape exception e-mails text as HTML. Plain and simple.
4
+
5
+ = Exception Notifier Plugin for Rails
6
+
7
+ The Exception Notifier plugin provides a mailer object and a default set of
8
+ templates for sending email notifications when errors occur in a Rails
9
+ application. The plugin is configurable, allowing programmers to specify:
10
+
11
+ * the sender address of the email
12
+ * the recipient addresses
13
+ * the text used to prefix the subject line
14
+
15
+ The email includes information about the current request, session, and
16
+ environment, and also gives a backtrace of the exception.
17
+
18
+ == Usage
19
+
20
+ First, include the ExceptionNotifiable mixin in whichever controller you want
21
+ to generate error emails (typically ApplicationController):
22
+
23
+ class ApplicationController < ActionController::Base
24
+ include ExceptionNotification::Notifiable
25
+ ...
26
+ end
27
+
28
+ Then, specify the email recipients in your environment:
29
+
30
+ ExceptionNotification::Notifier.exception_recipients = %w(joe@schmoe.com bill@schmoe.com)
31
+
32
+ And that's it! The defaults take care of the rest.
33
+
34
+ == Configuration
35
+
36
+ You can tweak other values to your liking, as well. In your environment file,
37
+ just set any or all of the following values:
38
+
39
+ # defaults to exception.notifier@default.com
40
+ ExceptionNotification::Notifier.sender_address =
41
+ %("Application Error" <app.error@myapp.com>)
42
+
43
+ # defaults to "[ERROR] "
44
+ ExceptionNotification::Notifier.email_prefix = "[APP] "
45
+
46
+ Even if you have mixed into ApplicationController you can skip notification in
47
+ some controllers by
48
+
49
+ class MyController < ApplicationController
50
+ skip_exception_notifications
51
+ end
52
+
53
+ == Deprecated local_request? overriding
54
+
55
+ Email notifications will only occur when the IP address is determined not to
56
+ be local. You can specify certain addresses to always be local so that you'll
57
+ get a detailed error instead of the generic error page. You do this in your
58
+ controller (or even per-controller):
59
+
60
+ consider_local "64.72.18.143", "14.17.21.25"
61
+
62
+ You can specify subnet masks as well, so that all matching addresses are
63
+ considered local:
64
+
65
+ consider_local "64.72.18.143/24"
66
+
67
+ The address "127.0.0.1" is always considered local. If you want to completely
68
+ reset the list of all addresses (for instance, if you wanted "127.0.0.1" to
69
+ NOT be considered local), you can simply do, somewhere in your controller:
70
+
71
+ local_addresses.clear
72
+
73
+ NOTE: The above functionality has has been pulled out to consider_local.rb,
74
+ as interfering with rails local determination is orthogonal to notification,
75
+ unnecessarily clutters backtraces, and even occasionally errs on odd ip or
76
+ requests bugs. To return original functionality add an initializer with:
77
+
78
+ ActionController::Base.send :include, ConsiderLocal
79
+
80
+ or just include it per controller that wants it
81
+
82
+ class MyController < ApplicationController
83
+ include ExceptionNotification::ConsiderLocal
84
+ end
85
+
86
+ == Customization
87
+
88
+ By default, the notification email includes four parts: request, session,
89
+ environment, and backtrace (in that order). You can customize how each of those
90
+ sections are rendered by placing a partial named for that part in your
91
+ app/views/exception_notifier directory (e.g., _session.rhtml). Each partial has
92
+ access to the following variables:
93
+
94
+ * @controller: the controller that caused the error
95
+ * @request: the current request object
96
+ * @exception: the exception that was raised
97
+ * @host: the name of the host that made the request
98
+ * @backtrace: a sanitized version of the exception's backtrace
99
+ * @rails_root: a sanitized version of RAILS_ROOT
100
+ * @data: a hash of optional data values that were passed to the notifier
101
+ * @sections: the array of sections to include in the email
102
+
103
+ You can reorder the sections, or exclude sections completely, by altering the
104
+ ExceptionNotification::Notifier.sections variable. You can even add new sections that
105
+ describe application-specific data--just add the section's name to the list
106
+ (whereever you'd like), and define the corresponding partial. Then, if your
107
+ new section requires information that isn't available by default, make sure
108
+ it is made available to the email using the exception_data macro:
109
+
110
+ class ApplicationController < ActionController::Base
111
+ ...
112
+ protected
113
+ exception_data :additional_data
114
+
115
+ def additional_data
116
+ { :document => @document,
117
+ :person => @person }
118
+ end
119
+ ...
120
+ end
121
+
122
+ In the above case, @document and @person would be made available to the email
123
+ renderer, allowing your new section(s) to access and display them. See the
124
+ existing sections defined by the plugin for examples of how to write your own.
125
+
126
+ == 404s errors
127
+
128
+ Notification is skipped if you return a 404 status, which happens by default
129
+ for an ActiveRecord::RecordNotFound or ActionController::UnknownAction error.
130
+
131
+ == Manually notifying of error in a rescue block
132
+
133
+ If your controller action manually handles an error, the notifier will never be
134
+ run. To manually notify of an error call notify_about_exception from within the
135
+ rescue block
136
+
137
+ def index
138
+ #risky operation here
139
+ rescue StandardError => error
140
+ #custom error handling here
141
+ notify_about_exception(error)
142
+ end
143
+
144
+ == Support and tickets
145
+
146
+ https://rails.lighthouseapp.com/projects/8995-rails-plugins
147
+
148
+ Copyright (c) 2005 Jamis Buck, released under the MIT license
@@ -0,0 +1,7 @@
1
+ require "action_mailer"
2
+ module ExceptionNotification
3
+ autoload :Notifiable, 'exception_notification/notifiable'
4
+ autoload :Notifier, 'exception_notification/notifier'
5
+ #autoload :NotifierHelper, 'exception_notification/notifier_helper'
6
+ autoload :ConsiderLocal, 'exception_notification/consider_local'
7
+ end
@@ -0,0 +1,31 @@
1
+ #This didn't belong on ExceptionNotifier and made backtraces worse. To keep original functionality in place
2
+ #'ActionController::Base.send :include, ExceptionNotification::ConsiderLocal' or just include in your controller
3
+ module ExceptionNotification::ConsiderLocal
4
+ module ClassMethods
5
+ def self.included(target)
6
+ require 'ipaddr'
7
+ target.extend(ClassMethods)
8
+ end
9
+
10
+ def consider_local(*args)
11
+ local_addresses.concat(args.flatten.map { |a| IPAddr.new(a) })
12
+ end
13
+
14
+ def local_addresses
15
+ addresses = read_inheritable_attribute(:local_addresses)
16
+ unless addresses
17
+ addresses = [IPAddr.new("127.0.0.1")]
18
+ write_inheritable_attribute(:local_addresses, addresses)
19
+ end
20
+ addresses
21
+ end
22
+ end
23
+
24
+ private
25
+
26
+ def local_request?
27
+ remote = IPAddr.new(request.remote_ip)
28
+ !self.class.local_addresses.detect { |addr| addr.include?(remote) }.nil?
29
+ end
30
+
31
+ end
@@ -0,0 +1,66 @@
1
+ # Copyright (c) 2005 Jamis Buck
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.
21
+ module ExceptionNotification::Notifiable
22
+ def self.included(target)
23
+ target.extend(ClassMethods)
24
+ target.skip_exception_notifications false
25
+ end
26
+
27
+ module ClassMethods
28
+ def exception_data(deliverer=self)
29
+ if deliverer == self
30
+ read_inheritable_attribute(:exception_data)
31
+ else
32
+ write_inheritable_attribute(:exception_data, deliverer)
33
+ end
34
+ end
35
+
36
+ def skip_exception_notifications(boolean=true)
37
+ write_inheritable_attribute(:skip_exception_notifications, boolean)
38
+ end
39
+
40
+ def skip_exception_notifications?
41
+ read_inheritable_attribute(:skip_exception_notifications)
42
+ end
43
+ end
44
+
45
+ private
46
+
47
+ def rescue_action_in_public(exception)
48
+ super
49
+ notify_about_exception(exception) if deliver_exception_notification?
50
+ end
51
+
52
+ def deliver_exception_notification?
53
+ !self.class.skip_exception_notifications? && ![404, "404 Not Found"].include?(response.status)
54
+ end
55
+
56
+ def notify_about_exception(exception)
57
+ deliverer = self.class.exception_data
58
+ data = case deliverer
59
+ when nil then {}
60
+ when Symbol then send(deliverer)
61
+ when Proc then deliverer.call(self)
62
+ end
63
+
64
+ ExceptionNotification::Notifier.deliver_exception_notification(exception, self, request, data)
65
+ end
66
+ end
@@ -0,0 +1,75 @@
1
+ require 'pathname'
2
+
3
+ # Copyright (c) 2005 Jamis Buck
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining
6
+ # a copy of this software and associated documentation files (the
7
+ # "Software"), to deal in the Software without restriction, including
8
+ # without limitation the rights to use, copy, modify, merge, publish,
9
+ # distribute, sublicense, and/or sell copies of the Software, and to
10
+ # permit persons to whom the Software is furnished to do so, subject to
11
+ # the following conditions:
12
+ #
13
+ # The above copyright notice and this permission notice shall be
14
+ # included in all copies or substantial portions of the Software.
15
+ #
16
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
+ class ExceptionNotification::Notifier < ActionMailer::Base
24
+ self.mailer_name = 'exception_notifier'
25
+ self.view_paths << "#{File.dirname(__FILE__)}/../../views"
26
+
27
+ @@sender_address = %("Exception Notifier" <exception.notifier@default.com>)
28
+ cattr_accessor :sender_address
29
+
30
+ @@exception_recipients = []
31
+ cattr_accessor :exception_recipients
32
+
33
+ @@email_prefix = "[ERROR] "
34
+ cattr_accessor :email_prefix
35
+
36
+ @@sections = %w(request session environment backtrace)
37
+ cattr_accessor :sections
38
+
39
+ def self.reloadable?() false end
40
+
41
+ def exception_notification(exception, controller, request, data={})
42
+ source = self.class.exception_source(controller)
43
+ content_type "text/plain"
44
+
45
+ subject "#{email_prefix}#{source} (#{exception.class}) #{exception.message.inspect}"
46
+
47
+ recipients exception_recipients
48
+ from sender_address
49
+
50
+ body data.merge({ :controller => controller, :request => request,
51
+ :exception => exception, :exception_source => source, :host => (request.env["HTTP_X_FORWARDED_HOST"] || request.env["HTTP_HOST"]),
52
+ :backtrace => sanitize_backtrace(exception.backtrace),
53
+ :rails_root => rails_root, :data => data,
54
+ :sections => sections })
55
+ end
56
+
57
+ def self.exception_source(controller)
58
+ if controller.respond_to?(:controller_name)
59
+ "in #{controller.controller_name}##{controller.action_name}"
60
+ else
61
+ "outside of a controller"
62
+ end
63
+ end
64
+
65
+ private
66
+
67
+ def sanitize_backtrace(trace)
68
+ re = Regexp.new(/^#{Regexp.escape(rails_root)}/)
69
+ trace.map { |line| Pathname.new(line.gsub(re, "[RAILS_ROOT]")).cleanpath.to_s }
70
+ end
71
+
72
+ def rails_root
73
+ @rails_root ||= Pathname.new(RAILS_ROOT).cleanpath.to_s
74
+ end
75
+ end
@@ -0,0 +1,66 @@
1
+ require 'pp'
2
+
3
+ # Copyright (c) 2005 Jamis Buck
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining
6
+ # a copy of this software and associated documentation files (the
7
+ # "Software"), to deal in the Software without restriction, including
8
+ # without limitation the rights to use, copy, modify, merge, publish,
9
+ # distribute, sublicense, and/or sell copies of the Software, and to
10
+ # permit persons to whom the Software is furnished to do so, subject to
11
+ # the following conditions:
12
+ #
13
+ # The above copyright notice and this permission notice shall be
14
+ # included in all copies or substantial portions of the Software.
15
+ #
16
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
+ module ExceptionNotification::NotifierHelper
24
+ PARAM_FILTER_REPLACEMENT = "[FILTERED]"
25
+
26
+ def render_section(section)
27
+ summary = render("exception_notifier/#{section}").strip
28
+ unless summary.blank?
29
+ title = render("exception_notifier/title", :title => section).strip
30
+ "#{title}\n\n#{summary.gsub(/^/, " ")}\n\n"
31
+ end
32
+ end
33
+
34
+ def inspect_model_object(model, locals={})
35
+ render('exception_notifier/inspect_model',
36
+ :locals => { :inspect_model => model,
37
+ :show_instance_variables => true,
38
+ :show_attributes => true }.merge(locals))
39
+ end
40
+
41
+ def inspect_value(value)
42
+ len = 512
43
+ result = object_to_yaml(value).gsub(/\n/, "\n ").strip
44
+ result = result[0,len] + "... (#{result.length-len} bytes more)" if result.length > len+20
45
+ result
46
+ end
47
+
48
+ def object_to_yaml(object)
49
+ object.to_yaml.sub(/^---\s*/m, "")
50
+ end
51
+
52
+ def exclude_raw_post_parameters?
53
+ @controller && @controller.respond_to?(:filter_parameters)
54
+ end
55
+
56
+ def filter_sensitive_post_data_parameters(parameters)
57
+ exclude_raw_post_parameters? ? @controller.__send__(:filter_parameters, parameters) : parameters
58
+ end
59
+
60
+ def filter_sensitive_post_data_from_env(env_key, env_value)
61
+ return env_value unless exclude_raw_post_parameters?
62
+ return PARAM_FILTER_REPLACEMENT if (env_key =~ /RAW_POST_DATA/i)
63
+ return @controller.__send__(:filter_parameters, {env_key => env_value}).values[0]
64
+ end
65
+
66
+ end
@@ -0,0 +1 @@
1
+ <%=raw @backtrace.join "\n" %>
@@ -0,0 +1,7 @@
1
+ <% max = @request.env.keys.max { |a,b| a.length <=> b.length } -%>
2
+ <% @request.env.keys.sort.each do |key| -%>
3
+ * <%=raw "%-*s: %s" % [max.length, key, filter_sensitive_post_data_from_env(key, @request.env[key].to_s.strip)] %>
4
+ <% end -%>
5
+
6
+ * Process: <%=raw $$ %>
7
+ * Server : <%=raw `hostname -s`.chomp %>
@@ -0,0 +1,16 @@
1
+ <% if show_attributes -%>
2
+ [attributes]
3
+ <% attrs = inspect_model.attributes -%>
4
+ <% max = attrs.keys.max { |a,b| a.length <=> b.length } -%>
5
+ <% attrs.keys.sort.each do |attr| -%>
6
+ * <%= "%*-s: %s" % [max.length, attr, object_to_yaml(attrs[attr]).gsub(/\n/, "\n ").strip] %>
7
+ <% end -%>
8
+ <% end -%>
9
+
10
+ <% if show_instance_variables -%>
11
+ [instance variables]
12
+ <% inspect_model.instance_variables.sort.each do |variable| -%>
13
+ <%- next if variable == "@attributes" -%>
14
+ * <%= variable %>: <%= inspect_value(inspect_model.instance_variable_get(variable)) %>
15
+ <% end -%>
16
+ <% end -%>
@@ -0,0 +1,4 @@
1
+ * URL : <%=raw @request.url %>
2
+ * IP address: <%=raw @request.remote_ip %>
3
+ * Parameters: <%=raw filter_sensitive_post_data_parameters(@request.parameters).inspect %>
4
+ * Rails root: <%=raw Rails.root %>
@@ -0,0 +1,2 @@
1
+ * session id: <%=raw @request.session_options[:id] %>
2
+ * data: <%=raw PP.pp @request.session.inspect.gsub(/\n/, "\n ").strip.html_safe %>
@@ -0,0 +1,3 @@
1
+ -------------------------------
2
+ <%=raw title.to_s.humanize %>:
3
+ -------------------------------
@@ -0,0 +1,6 @@
1
+ A <%= @exception.class %> occurred <%= @exception_source %>:
2
+
3
+ <%=raw @exception.message %>
4
+ <%=raw @backtrace.first %>
5
+
6
+ <%=raw @sections.map { |section| render_section(section) }.join %>
metadata ADDED
@@ -0,0 +1,81 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: panmind-exception_notification
3
+ version: !ruby/object:Gem::Version
4
+ hash: 23
5
+ prerelease: false
6
+ segments:
7
+ - 2
8
+ - 3
9
+ - 10
10
+ version: 2.3.10
11
+ platform: ruby
12
+ authors:
13
+ - Jamis Buck
14
+ - Josh Peek
15
+ - Tim Connor
16
+ autorequire:
17
+ bindir: bin
18
+ cert_chain: []
19
+
20
+ date: 2010-11-03 00:00:00 +01:00
21
+ default_executable:
22
+ dependencies: []
23
+
24
+ description:
25
+ email: timocratic@gmail.com
26
+ executables: []
27
+
28
+ extensions: []
29
+
30
+ extra_rdoc_files: []
31
+
32
+ files:
33
+ - README.rdoc
34
+ - lib/exception_notification/consider_local.rb
35
+ - lib/exception_notification/notifiable.rb
36
+ - lib/exception_notification/notifier.rb
37
+ - lib/exception_notification/notifier_helper.rb
38
+ - lib/exception_notification.rb
39
+ - views/exception_notifier/_backtrace.rhtml
40
+ - views/exception_notifier/_environment.rhtml
41
+ - views/exception_notifier/_inspect_model.rhtml
42
+ - views/exception_notifier/_request.rhtml
43
+ - views/exception_notifier/_session.rhtml
44
+ - views/exception_notifier/_title.rhtml
45
+ - views/exception_notifier/exception_notification.rhtml
46
+ has_rdoc: true
47
+ homepage:
48
+ licenses: []
49
+
50
+ post_install_message:
51
+ rdoc_options: []
52
+
53
+ require_paths:
54
+ - lib
55
+ required_ruby_version: !ruby/object:Gem::Requirement
56
+ none: false
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ hash: 3
61
+ segments:
62
+ - 0
63
+ version: "0"
64
+ required_rubygems_version: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ">="
68
+ - !ruby/object:Gem::Version
69
+ hash: 3
70
+ segments:
71
+ - 0
72
+ version: "0"
73
+ requirements: []
74
+
75
+ rubyforge_project:
76
+ rubygems_version: 1.3.7
77
+ signing_key:
78
+ specification_version: 3
79
+ summary: Exception notification by email for Rails apps - 2.3-stable compatible version
80
+ test_files: []
81
+