exception_notification 4.3.0 → 4.5.0

Sign up to get free protection for your applications and to get access to all the features.
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