exception_notification 4.3.0 → 4.5.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.
Files changed (131) hide show
  1. checksums.yaml +5 -5
  2. data/Appraisals +4 -2
  3. data/CHANGELOG.rdoc +47 -0
  4. data/CONTRIBUTING.md +18 -0
  5. data/Gemfile +3 -1
  6. data/README.md +97 -945
  7. data/Rakefile +4 -2
  8. data/docs/notifiers/campfire.md +50 -0
  9. data/docs/notifiers/custom.md +42 -0
  10. data/docs/notifiers/datadog.md +51 -0
  11. data/docs/notifiers/email.md +195 -0
  12. data/docs/notifiers/google_chat.md +31 -0
  13. data/docs/notifiers/hipchat.md +66 -0
  14. data/docs/notifiers/irc.md +97 -0
  15. data/docs/notifiers/mattermost.md +115 -0
  16. data/docs/notifiers/slack.md +161 -0
  17. data/docs/notifiers/sns.md +37 -0
  18. data/docs/notifiers/teams.md +54 -0
  19. data/docs/notifiers/webhook.md +60 -0
  20. data/examples/sample_app.rb +56 -0
  21. data/examples/sinatra/Gemfile +8 -6
  22. data/examples/sinatra/config.ru +3 -1
  23. data/examples/sinatra/sinatra_app.rb +19 -11
  24. data/exception_notification.gemspec +30 -24
  25. data/gemfiles/{rails4_0.gemfile → rails5_2.gemfile} +2 -2
  26. data/gemfiles/{rails4_1.gemfile → rails6_0.gemfile} +2 -2
  27. data/gemfiles/{rails4_2.gemfile → rails6_1.gemfile} +2 -2
  28. data/gemfiles/{rails5_0.gemfile → rails7_0.gemfile} +2 -2
  29. data/lib/exception_notification/rack.rb +28 -30
  30. data/lib/exception_notification/rails.rb +2 -0
  31. data/lib/exception_notification/resque.rb +10 -10
  32. data/lib/exception_notification/sidekiq.rb +10 -12
  33. data/lib/exception_notification/version.rb +5 -0
  34. data/lib/exception_notification.rb +3 -0
  35. data/lib/exception_notifier/base_notifier.rb +10 -5
  36. data/lib/exception_notifier/datadog_notifier.rb +156 -0
  37. data/lib/exception_notifier/email_notifier.rb +73 -88
  38. data/lib/exception_notifier/google_chat_notifier.rb +27 -119
  39. data/lib/exception_notifier/hipchat_notifier.rb +13 -12
  40. data/lib/exception_notifier/irc_notifier.rb +36 -33
  41. data/lib/exception_notifier/mattermost_notifier.rb +54 -137
  42. data/lib/exception_notifier/modules/backtrace_cleaner.rb +2 -2
  43. data/lib/exception_notifier/modules/error_grouping.rb +24 -13
  44. data/lib/exception_notifier/modules/formatter.rb +125 -0
  45. data/lib/exception_notifier/notifier.rb +9 -6
  46. data/lib/exception_notifier/slack_notifier.rb +65 -40
  47. data/lib/exception_notifier/sns_notifier.rb +23 -13
  48. data/lib/exception_notifier/teams_notifier.rb +67 -46
  49. data/lib/exception_notifier/views/exception_notifier/_backtrace.html.erb +1 -1
  50. data/lib/exception_notifier/views/exception_notifier/_environment.text.erb +1 -1
  51. data/lib/exception_notifier/views/exception_notifier/_request.text.erb +1 -1
  52. data/lib/exception_notifier/views/exception_notifier/exception_notification.html.erb +2 -2
  53. data/lib/exception_notifier/views/exception_notifier/exception_notification.text.erb +2 -2
  54. data/lib/exception_notifier/webhook_notifier.rb +17 -14
  55. data/lib/exception_notifier.rb +65 -10
  56. data/lib/generators/exception_notification/install_generator.rb +11 -5
  57. data/lib/generators/exception_notification/templates/{exception_notification.rb → exception_notification.rb.erb} +13 -11
  58. data/test/exception_notification/rack_test.rb +75 -13
  59. data/test/exception_notification/resque_test.rb +54 -0
  60. data/test/exception_notifier/datadog_notifier_test.rb +153 -0
  61. data/test/exception_notifier/email_notifier_test.rb +275 -153
  62. data/test/exception_notifier/google_chat_notifier_test.rb +158 -101
  63. data/test/exception_notifier/hipchat_notifier_test.rb +84 -81
  64. data/test/exception_notifier/irc_notifier_test.rb +36 -34
  65. data/test/exception_notifier/mattermost_notifier_test.rb +213 -67
  66. data/test/exception_notifier/modules/error_grouping_test.rb +41 -40
  67. data/test/exception_notifier/modules/formatter_test.rb +152 -0
  68. data/test/exception_notifier/sidekiq_test.rb +9 -17
  69. data/test/exception_notifier/slack_notifier_test.rb +66 -63
  70. data/test/exception_notifier/sns_notifier_test.rb +84 -32
  71. data/test/exception_notifier/teams_notifier_test.rb +25 -26
  72. data/test/exception_notifier/webhook_notifier_test.rb +52 -48
  73. data/test/exception_notifier_test.rb +150 -41
  74. data/test/support/exception_notifier_helper.rb +14 -0
  75. data/test/{dummy/app → support}/views/exception_notifier/_new_bkg_section.html.erb +0 -0
  76. data/test/{dummy/app → support}/views/exception_notifier/_new_bkg_section.text.erb +0 -0
  77. data/test/{dummy/app → support}/views/exception_notifier/_new_section.html.erb +0 -0
  78. data/test/{dummy/app → support}/views/exception_notifier/_new_section.text.erb +0 -0
  79. data/test/test_helper.rb +14 -13
  80. metadata +134 -175
  81. data/gemfiles/rails5_1.gemfile +0 -7
  82. data/lib/exception_notifier/campfire_notifier.rb +0 -40
  83. data/test/dummy/.gitignore +0 -4
  84. data/test/dummy/Rakefile +0 -7
  85. data/test/dummy/app/controllers/application_controller.rb +0 -3
  86. data/test/dummy/app/controllers/posts_controller.rb +0 -30
  87. data/test/dummy/app/helpers/application_helper.rb +0 -2
  88. data/test/dummy/app/helpers/posts_helper.rb +0 -2
  89. data/test/dummy/app/models/post.rb +0 -2
  90. data/test/dummy/app/views/layouts/application.html.erb +0 -14
  91. data/test/dummy/app/views/posts/_form.html.erb +0 -0
  92. data/test/dummy/app/views/posts/new.html.erb +0 -0
  93. data/test/dummy/app/views/posts/show.html.erb +0 -0
  94. data/test/dummy/config/application.rb +0 -42
  95. data/test/dummy/config/boot.rb +0 -6
  96. data/test/dummy/config/database.yml +0 -22
  97. data/test/dummy/config/environment.rb +0 -17
  98. data/test/dummy/config/environments/development.rb +0 -25
  99. data/test/dummy/config/environments/production.rb +0 -50
  100. data/test/dummy/config/environments/test.rb +0 -35
  101. data/test/dummy/config/initializers/backtrace_silencers.rb +0 -7
  102. data/test/dummy/config/initializers/inflections.rb +0 -10
  103. data/test/dummy/config/initializers/mime_types.rb +0 -5
  104. data/test/dummy/config/initializers/secret_token.rb +0 -8
  105. data/test/dummy/config/initializers/session_store.rb +0 -8
  106. data/test/dummy/config/locales/en.yml +0 -5
  107. data/test/dummy/config/routes.rb +0 -3
  108. data/test/dummy/config.ru +0 -4
  109. data/test/dummy/db/migrate/20110729022608_create_posts.rb +0 -15
  110. data/test/dummy/db/schema.rb +0 -24
  111. data/test/dummy/db/seeds.rb +0 -7
  112. data/test/dummy/lib/tasks/.gitkeep +0 -0
  113. data/test/dummy/public/404.html +0 -26
  114. data/test/dummy/public/422.html +0 -26
  115. data/test/dummy/public/500.html +0 -26
  116. data/test/dummy/public/favicon.ico +0 -0
  117. data/test/dummy/public/images/rails.png +0 -0
  118. data/test/dummy/public/index.html +0 -239
  119. data/test/dummy/public/javascripts/application.js +0 -2
  120. data/test/dummy/public/javascripts/controls.js +0 -965
  121. data/test/dummy/public/javascripts/dragdrop.js +0 -974
  122. data/test/dummy/public/javascripts/effects.js +0 -1123
  123. data/test/dummy/public/javascripts/prototype.js +0 -6001
  124. data/test/dummy/public/javascripts/rails.js +0 -191
  125. data/test/dummy/public/robots.txt +0 -5
  126. data/test/dummy/public/stylesheets/.gitkeep +0 -0
  127. data/test/dummy/public/stylesheets/scaffold.css +0 -56
  128. data/test/dummy/script/rails +0 -6
  129. data/test/dummy/test/functional/posts_controller_test.rb +0 -237
  130. data/test/dummy/test/test_helper.rb +0 -7
  131. data/test/exception_notifier/campfire_notifier_test.rb +0 -120
@@ -1,24 +1,24 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'resque/failure/base'
2
4
 
3
5
  module ExceptionNotification
4
6
  class Resque < Resque::Failure::Base
5
-
6
7
  def self.count
7
- Stat[:failed]
8
+ ::Resque::Stat[:failed]
8
9
  end
9
10
 
10
11
  def save
11
12
  data = {
12
- :failed_at => Time.now.to_s,
13
- :queue => queue,
14
- :worker => worker.to_s,
15
- :payload => payload,
16
- :error_class => exception.class.name,
17
- :error_message => exception.message
13
+ error_class: exception.class.name,
14
+ error_message: exception.message,
15
+ failed_at: Time.now.to_s,
16
+ payload: payload,
17
+ queue: queue,
18
+ worker: worker.to_s
18
19
  }
19
20
 
20
- ExceptionNotifier.notify_exception(exception, :data => { :resque => data })
21
+ ExceptionNotifier.notify_exception(exception, data: { resque: data })
21
22
  end
22
-
23
23
  end
24
24
  end
@@ -1,18 +1,16 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'sidekiq'
2
4
 
3
5
  # Note: this class is only needed for Sidekiq version < 3.
4
6
  module ExceptionNotification
5
7
  class Sidekiq
6
-
7
- def call(worker, msg, queue)
8
- begin
9
- yield
10
- rescue Exception => exception
11
- ExceptionNotifier.notify_exception(exception, :data => { :sidekiq => msg })
12
- raise exception
13
- end
8
+ def call(_worker, msg, _queue)
9
+ yield
10
+ rescue Exception => e
11
+ ExceptionNotifier.notify_exception(e, data: { sidekiq: msg })
12
+ raise e
14
13
  end
15
-
16
14
  end
17
15
  end
18
16
 
@@ -24,8 +22,8 @@ if ::Sidekiq::VERSION < '3'
24
22
  end
25
23
  else
26
24
  ::Sidekiq.configure_server do |config|
27
- config.error_handlers << Proc.new { |ex, context|
28
- ExceptionNotifier.notify_exception(ex, :data => { :sidekiq => context })
29
- }
25
+ config.error_handlers << proc do |ex, context|
26
+ ExceptionNotifier.notify_exception(ex, data: { sidekiq: context })
27
+ end
30
28
  end
31
29
  end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ExceptionNotification
4
+ VERSION = '4.5.0'
5
+ end
@@ -1,5 +1,8 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'exception_notifier'
2
4
  require 'exception_notification/rack'
5
+ require 'exception_notification/version'
3
6
 
4
7
  module ExceptionNotification
5
8
  # Alternative way to setup ExceptionNotification.
@@ -1,12 +1,14 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ExceptionNotifier
2
4
  class BaseNotifier
3
5
  attr_accessor :base_options
4
6
 
5
- def initialize(options={})
7
+ def initialize(options = {})
6
8
  @base_options = options
7
9
  end
8
10
 
9
- def send_notice(exception, options, message, message_opts=nil)
11
+ def send_notice(exception, options, message, message_opts = nil)
10
12
  _pre_callback(exception, options, message, message_opts)
11
13
  result = yield(message, message_opts)
12
14
  _post_callback(exception, options, message, message_opts)
@@ -14,12 +16,15 @@ module ExceptionNotifier
14
16
  end
15
17
 
16
18
  def _pre_callback(exception, options, message, message_opts)
17
- @base_options[:pre_callback].call(options, self, exception.backtrace, message, message_opts) if @base_options[:pre_callback].respond_to?(:call)
19
+ return unless @base_options[:pre_callback].respond_to?(:call)
20
+
21
+ @base_options[:pre_callback].call(options, self, exception.backtrace, message, message_opts)
18
22
  end
19
23
 
20
24
  def _post_callback(exception, options, message, message_opts)
21
- @base_options[:post_callback].call(options, self, exception.backtrace, message, message_opts) if @base_options[:post_callback].respond_to?(:call)
22
- end
25
+ return unless @base_options[:post_callback].respond_to?(:call)
23
26
 
27
+ @base_options[:post_callback].call(options, self, exception.backtrace, message, message_opts)
28
+ end
24
29
  end
25
30
  end
@@ -0,0 +1,156 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'action_dispatch'
4
+
5
+ module ExceptionNotifier
6
+ class DatadogNotifier < BaseNotifier
7
+ attr_reader :client,
8
+ :default_options
9
+
10
+ def initialize(options)
11
+ super
12
+ @client = options.fetch(:client)
13
+ @default_options = options
14
+ end
15
+
16
+ def call(exception, options = {})
17
+ client.emit_event(
18
+ datadog_event(exception, options)
19
+ )
20
+ end
21
+
22
+ def datadog_event(exception, options = {})
23
+ DatadogExceptionEvent.new(
24
+ exception,
25
+ options.reverse_merge(default_options)
26
+ ).event
27
+ end
28
+
29
+ class DatadogExceptionEvent
30
+ include ExceptionNotifier::BacktraceCleaner
31
+
32
+ MAX_TITLE_LENGTH = 120
33
+ MAX_VALUE_LENGTH = 300
34
+ MAX_BACKTRACE_SIZE = 3
35
+ ALERT_TYPE = 'error'
36
+
37
+ attr_reader :exception,
38
+ :options
39
+
40
+ def initialize(exception, options)
41
+ @exception = exception
42
+ @options = options
43
+ end
44
+
45
+ def request
46
+ @request ||= ActionDispatch::Request.new(options[:env]) if options[:env]
47
+ end
48
+
49
+ def controller
50
+ @controller ||= options[:env] && options[:env]['action_controller.instance']
51
+ end
52
+
53
+ def backtrace
54
+ @backtrace ||= exception.backtrace ? clean_backtrace(exception) : []
55
+ end
56
+
57
+ def tags
58
+ options[:tags] || []
59
+ end
60
+
61
+ def title_prefix
62
+ options[:title_prefix] || ''
63
+ end
64
+
65
+ def event
66
+ title = formatted_title
67
+ body = formatted_body
68
+
69
+ Dogapi::Event.new(
70
+ body,
71
+ msg_title: title,
72
+ alert_type: ALERT_TYPE,
73
+ tags: tags,
74
+ aggregation_key: [title]
75
+ )
76
+ end
77
+
78
+ def formatted_title
79
+ title =
80
+ "#{title_prefix}#{controller_subtitle} (#{exception.class}) #{exception.message.inspect}"
81
+
82
+ truncate(title, MAX_TITLE_LENGTH)
83
+ end
84
+
85
+ def formatted_body
86
+ text = []
87
+
88
+ text << '%%%'
89
+ text << formatted_request if request
90
+ text << formatted_session if request
91
+ text << formatted_backtrace
92
+ text << '%%%'
93
+
94
+ text.join("\n")
95
+ end
96
+
97
+ def formatted_key_value(key, value)
98
+ "**#{key}:** #{value}"
99
+ end
100
+
101
+ def formatted_request
102
+ text = []
103
+ text << '### **Request**'
104
+ text << formatted_key_value('URL', request.url)
105
+ text << formatted_key_value('HTTP Method', request.request_method)
106
+ text << formatted_key_value('IP Address', request.remote_ip)
107
+ text << formatted_key_value('Parameters', request.filtered_parameters.inspect)
108
+ text << formatted_key_value('Timestamp', Time.current)
109
+ text << formatted_key_value('Server', Socket.gethostname)
110
+ text << formatted_key_value('Rails root', Rails.root) if defined?(Rails) && Rails.respond_to?(:root)
111
+ text << formatted_key_value('Process', $PROCESS_ID)
112
+ text << '___'
113
+ text.join("\n")
114
+ end
115
+
116
+ def formatted_session
117
+ text = []
118
+ text << '### **Session**'
119
+ text << formatted_key_value('Data', request.session.to_hash)
120
+ text << '___'
121
+ text.join("\n")
122
+ end
123
+
124
+ def formatted_backtrace
125
+ size = [backtrace.size, MAX_BACKTRACE_SIZE].min
126
+
127
+ text = []
128
+ text << '### **Backtrace**'
129
+ text << '````'
130
+ size.times { |i| text << backtrace[i] }
131
+ text << '````'
132
+ text << '___'
133
+ text.join("\n")
134
+ end
135
+
136
+ def truncate(string, max)
137
+ string.length > max ? "#{string[0...max]}..." : string
138
+ end
139
+
140
+ def inspect_object(object)
141
+ case object
142
+ when Hash, Array
143
+ truncate(object.inspect, MAX_VALUE_LENGTH)
144
+ else
145
+ object.to_s
146
+ end
147
+ end
148
+
149
+ private
150
+
151
+ def controller_subtitle
152
+ "#{controller.controller_name} #{controller.action_name}" if controller
153
+ end
154
+ end
155
+ end
156
+ end
@@ -1,4 +1,5 @@
1
- require "active_support/core_ext/hash/reverse_merge"
1
+ # frozen_string_literal: true
2
+
2
3
  require 'active_support/core_ext/time'
3
4
  require 'action_mailer'
4
5
  require 'action_dispatch'
@@ -6,47 +7,61 @@ require 'pp'
6
7
 
7
8
  module ExceptionNotifier
8
9
  class EmailNotifier < BaseNotifier
9
- attr_accessor(:sender_address, :exception_recipients,
10
- :pre_callback, :post_callback,
11
- :email_prefix, :email_format, :sections, :background_sections,
12
- :verbose_subject, :normalize_subject, :include_controller_and_action_names_in_subject,
13
- :delivery_method, :mailer_settings, :email_headers, :mailer_parent, :template_path, :deliver_with)
10
+ DEFAULT_OPTIONS = {
11
+ sender_address: %("Exception Notifier" <exception.notifier@example.com>),
12
+ exception_recipients: [],
13
+ email_prefix: '[ERROR] ',
14
+ email_format: :text,
15
+ sections: %w[request session environment backtrace],
16
+ background_sections: %w[backtrace data],
17
+ verbose_subject: true,
18
+ normalize_subject: false,
19
+ include_controller_and_action_names_in_subject: true,
20
+ delivery_method: nil,
21
+ mailer_settings: nil,
22
+ email_headers: {},
23
+ mailer_parent: 'ActionMailer::Base',
24
+ template_path: 'exception_notifier',
25
+ deliver_with: nil
26
+ }.freeze
14
27
 
15
28
  module Mailer
16
29
  class MissingController
17
- def method_missing(*args, &block)
18
- end
30
+ def method_missing(*args, &block); end
19
31
  end
20
32
 
21
33
  def self.extended(base)
22
34
  base.class_eval do
23
- self.send(:include, ExceptionNotifier::BacktraceCleaner)
35
+ send(:include, ExceptionNotifier::BacktraceCleaner)
24
36
 
25
37
  # Append application view path to the ExceptionNotifier lookup context.
26
- self.append_view_path "#{File.dirname(__FILE__)}/views"
38
+ append_view_path "#{File.dirname(__FILE__)}/views"
27
39
 
28
- def exception_notification(env, exception, options={}, default_options={})
40
+ def exception_notification(env, exception, options = {}, default_options = {})
29
41
  load_custom_views
30
42
 
31
43
  @env = env
32
44
  @exception = exception
33
- @options = options.reverse_merge(env['exception_notifier.options'] || {}).reverse_merge(default_options)
45
+
46
+ env_options = env['exception_notifier.options'] || {}
47
+ @options = default_options.merge(env_options).merge(options)
48
+
34
49
  @kontroller = env['action_controller.instance'] || MissingController.new
35
50
  @request = ActionDispatch::Request.new(env)
36
51
  @backtrace = exception.backtrace ? clean_backtrace(exception) : []
37
52
  @timestamp = Time.current
38
53
  @sections = @options[:sections]
39
54
  @data = (env['exception_notifier.exception_data'] || {}).merge(options[:data] || {})
40
- @sections = @sections + %w(data) unless @data.empty?
55
+ @sections += %w[data] unless @data.empty?
41
56
 
42
57
  compose_email
43
58
  end
44
59
 
45
- def background_exception_notification(exception, options={}, default_options={})
60
+ def background_exception_notification(exception, options = {}, default_options = {})
46
61
  load_custom_views
47
62
 
48
63
  @exception = exception
49
- @options = options.reverse_merge(default_options).symbolize_keys
64
+ @options = default_options.merge(options).symbolize_keys
50
65
  @backtrace = exception.backtrace || []
51
66
  @timestamp = Time.current
52
67
  @sections = @options[:background_sections]
@@ -59,13 +74,17 @@ module ExceptionNotifier
59
74
  private
60
75
 
61
76
  def compose_subject
62
- subject = "#{@options[:email_prefix]}"
77
+ subject = @options[:email_prefix].to_s.dup
63
78
  subject << "(#{@options[:accumulated_errors_count]} times)" if @options[:accumulated_errors_count].to_i > 1
64
- subject << "#{@kontroller.controller_name} #{@kontroller.action_name}" if @kontroller && @options[:include_controller_and_action_names_in_subject]
79
+ subject << "#{@kontroller.controller_name}##{@kontroller.action_name}" if include_controller?
65
80
  subject << " (#{@exception.class})"
66
81
  subject << " #{@exception.message.inspect}" if @options[:verbose_subject]
67
82
  subject = EmailNotifier.normalize_digits(subject) if @options[:normalize_subject]
68
- subject.length > 120 ? subject[0...120] + "..." : subject
83
+ subject.length > 120 ? subject[0...120] + '...' : subject
84
+ end
85
+
86
+ def include_controller?
87
+ @kontroller && @options[:include_controller_and_action_names_in_subject]
69
88
  end
70
89
 
71
90
  def set_data_variables
@@ -82,17 +101,17 @@ module ExceptionNotifier
82
101
 
83
102
  def inspect_object(object)
84
103
  case object
85
- when Hash, Array
86
- truncate(object.inspect, 300)
87
- else
88
- object.to_s
104
+ when Hash, Array
105
+ truncate(object.inspect, 300)
106
+ else
107
+ object.to_s
89
108
  end
90
109
  end
91
110
 
92
111
  helper_method :safe_encode
93
112
 
94
113
  def safe_encode(value)
95
- value.encode("utf-8", invalid: :replace, undef: :replace, replace: "_")
114
+ value.encode('utf-8', invalid: :replace, undef: :replace, replace: '_')
96
115
  end
97
116
 
98
117
  def html_mail?
@@ -106,11 +125,11 @@ module ExceptionNotifier
106
125
  exception_recipients = maybe_call(@options[:exception_recipients])
107
126
 
108
127
  headers = {
109
- :delivery_method => @options[:delivery_method],
110
- :to => exception_recipients,
111
- :from => @options[:sender_address],
112
- :subject => subject,
113
- :template_name => name
128
+ delivery_method: @options[:delivery_method],
129
+ to: exception_recipients,
130
+ from: @options[:sender_address],
131
+ subject: subject,
132
+ template_name: name
114
133
  }.merge(@options[:email_headers])
115
134
 
116
135
  mail = mail(headers) do |format|
@@ -124,9 +143,9 @@ module ExceptionNotifier
124
143
  end
125
144
 
126
145
  def load_custom_views
127
- if defined?(Rails) && Rails.respond_to?(:root)
128
- self.prepend_view_path Rails.root.nil? ? "app/views" : "#{Rails.root}/app/views"
129
- end
146
+ return unless defined?(Rails) && Rails.respond_to?(:root)
147
+
148
+ prepend_view_path Rails.root.nil? ? 'app/views' : "#{Rails.root}/app/views"
130
149
  end
131
150
 
132
151
  def maybe_call(maybe_proc)
@@ -138,82 +157,48 @@ module ExceptionNotifier
138
157
 
139
158
  def initialize(options)
140
159
  super
160
+
141
161
  delivery_method = (options[:delivery_method] || :smtp)
142
162
  mailer_settings_key = "#{delivery_method}_settings".to_sym
143
163
  options[:mailer_settings] = options.delete(mailer_settings_key)
144
164
 
145
- options.reverse_merge(EmailNotifier.default_options).select{|k,v|[
146
- :sender_address, :exception_recipients, :pre_callback,
147
- :post_callback, :email_prefix, :email_format,
148
- :sections, :background_sections, :verbose_subject, :normalize_subject,
149
- :include_controller_and_action_names_in_subject, :delivery_method, :mailer_settings,
150
- :email_headers, :mailer_parent, :template_path, :deliver_with].include?(k)}.each{|k,v| send("#{k}=", v)}
165
+ @base_options = DEFAULT_OPTIONS.merge(options)
151
166
  end
152
167
 
153
- def options
154
- @options ||= {}.tap do |opts|
155
- self.instance_variables.each { |var| opts[var[1..-1].to_sym] = self.instance_variable_get(var) }
156
- end
157
- end
158
-
159
- def mailer
160
- @mailer ||= Class.new(mailer_parent.constantize).tap do |mailer|
161
- mailer.extend(EmailNotifier::Mailer)
162
- mailer.mailer_name = template_path
163
- end
164
- end
165
-
166
- def call(exception, options={})
168
+ def call(exception, options = {})
167
169
  message = create_email(exception, options)
168
170
 
169
- # FIXME: use `if Gem::Version.new(ActionMailer::VERSION::STRING) < Gem::Version.new('4.1')`
170
- if deliver_with == :default
171
- if message.respond_to?(:deliver_now)
172
- message.deliver_now
173
- else
174
- message.deliver
175
- end
176
- else
177
- message.send(deliver_with)
178
- end
171
+ message.send(base_options[:deliver_with] || default_deliver_with(message))
179
172
  end
180
173
 
181
- def create_email(exception, options={})
174
+ def create_email(exception, options = {})
182
175
  env = options[:env]
183
- default_options = self.options
184
- if env.nil?
185
- send_notice(exception, options, nil, default_options) do |_, default_opts|
176
+
177
+ send_notice(exception, options, nil, base_options) do |_, default_opts|
178
+ if env.nil?
186
179
  mailer.background_exception_notification(exception, options, default_opts)
187
- end
188
- else
189
- send_notice(exception, options, nil, default_options) do |_, default_opts|
180
+ else
190
181
  mailer.exception_notification(env, exception, options, default_opts)
191
182
  end
192
183
  end
193
184
  end
194
185
 
195
- def self.default_options
196
- {
197
- :sender_address => %("Exception Notifier" <exception.notifier@example.com>),
198
- :exception_recipients => [],
199
- :email_prefix => "[ERROR] ",
200
- :email_format => :text,
201
- :sections => %w(request session environment backtrace),
202
- :background_sections => %w(backtrace data),
203
- :verbose_subject => true,
204
- :normalize_subject => false,
205
- :include_controller_and_action_names_in_subject => true,
206
- :delivery_method => nil,
207
- :mailer_settings => nil,
208
- :email_headers => {},
209
- :mailer_parent => 'ActionMailer::Base',
210
- :template_path => 'exception_notifier',
211
- :deliver_with => :default
212
- }
213
- end
214
-
215
186
  def self.normalize_digits(string)
216
187
  string.gsub(/[0-9]+/, 'N')
217
188
  end
189
+
190
+ private
191
+
192
+ def mailer
193
+ @mailer ||= Class.new(base_options[:mailer_parent].constantize).tap do |mailer|
194
+ mailer.extend(EmailNotifier::Mailer)
195
+ mailer.mailer_name = base_options[:template_path]
196
+ end
197
+ end
198
+
199
+ def default_deliver_with(message)
200
+ # FIXME: use `if Gem::Version.new(ActionMailer::VERSION::STRING) < Gem::Version.new('4.1')`
201
+ message.respond_to?(:deliver_now) ? :deliver_now : :deliver
202
+ end
218
203
  end
219
204
  end