exception_notification 4.4.0 → 4.4.1
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.
- checksums.yaml +5 -5
- data/Appraisals +3 -1
- data/CHANGELOG.rdoc +10 -0
- data/Gemfile +2 -0
- data/README.md +34 -8
- data/Rakefile +2 -0
- data/examples/sample_app.rb +2 -0
- data/examples/sinatra/Gemfile +2 -0
- data/examples/sinatra/config.ru +2 -0
- data/examples/sinatra/sinatra_app.rb +6 -2
- data/exception_notification.gemspec +9 -8
- data/gemfiles/rails4_0.gemfile +3 -3
- data/gemfiles/rails4_1.gemfile +3 -3
- data/gemfiles/rails4_2.gemfile +3 -3
- data/gemfiles/rails5_0.gemfile +3 -3
- data/gemfiles/rails5_1.gemfile +3 -3
- data/gemfiles/rails5_2.gemfile +3 -3
- data/lib/exception_notification.rb +2 -0
- data/lib/exception_notification/rack.rb +24 -13
- data/lib/exception_notification/rails.rb +2 -0
- data/lib/exception_notification/resque.rb +2 -0
- data/lib/exception_notification/sidekiq.rb +5 -3
- data/lib/exception_notification/version.rb +3 -1
- data/lib/exception_notifier.rb +46 -7
- data/lib/exception_notifier/base_notifier.rb +8 -2
- data/lib/exception_notifier/campfire_notifier.rb +2 -0
- data/lib/exception_notifier/datadog_notifier.rb +12 -9
- data/lib/exception_notifier/email_notifier.rb +11 -3
- data/lib/exception_notifier/google_chat_notifier.rb +2 -0
- data/lib/exception_notifier/hipchat_notifier.rb +2 -0
- data/lib/exception_notifier/irc_notifier.rb +4 -3
- data/lib/exception_notifier/mattermost_notifier.rb +10 -0
- data/lib/exception_notifier/modules/backtrace_cleaner.rb +2 -0
- data/lib/exception_notifier/modules/error_grouping.rb +19 -9
- data/lib/exception_notifier/modules/formatter.rb +3 -0
- data/lib/exception_notifier/notifier.rb +5 -1
- data/lib/exception_notifier/slack_notifier.rb +2 -0
- data/lib/exception_notifier/sns_notifier.rb +4 -3
- data/lib/exception_notifier/teams_notifier.rb +10 -3
- data/lib/exception_notifier/webhook_notifier.rb +3 -3
- data/lib/generators/exception_notification/install_generator.rb +8 -2
- data/test/exception_notification/rack_test.rb +48 -2
- data/test/exception_notification/resque_test.rb +2 -0
- data/test/exception_notifier/campfire_notifier_test.rb +8 -1
- data/test/exception_notifier/datadog_notifier_test.rb +2 -0
- data/test/exception_notifier/email_notifier_test.rb +29 -3
- data/test/exception_notifier/google_chat_notifier_test.rb +15 -11
- data/test/exception_notifier/hipchat_notifier_test.rb +8 -2
- data/test/exception_notifier/irc_notifier_test.rb +2 -0
- data/test/exception_notifier/mattermost_notifier_test.rb +73 -24
- data/test/exception_notifier/modules/error_grouping_test.rb +2 -0
- data/test/exception_notifier/modules/formatter_test.rb +2 -0
- data/test/exception_notifier/sidekiq_test.rb +3 -11
- data/test/exception_notifier/slack_notifier_test.rb +12 -10
- data/test/exception_notifier/sns_notifier_test.rb +9 -7
- data/test/exception_notifier/teams_notifier_test.rb +2 -0
- data/test/exception_notifier/webhook_notifier_test.rb +6 -4
- data/test/exception_notifier_test.rb +112 -6
- data/test/support/exception_notifier_helper.rb +14 -0
- data/test/test_helper.rb +5 -1
- metadata +22 -27
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'test_helper'
|
2
4
|
|
3
5
|
# silence_warnings trick around require can be removed once
|
@@ -94,11 +96,16 @@ class CampfireNotifierTest < ActiveSupport::TestCase
|
|
94
96
|
{
|
95
97
|
message: {
|
96
98
|
type: 'PasteMessage',
|
97
|
-
body:
|
99
|
+
body: fake_notification_body
|
98
100
|
}
|
99
101
|
}
|
100
102
|
end
|
101
103
|
|
104
|
+
def fake_notification_body
|
105
|
+
"A new exception occurred: 'divided by 0' on " \
|
106
|
+
"/Users/sebastian/exception_notification/test/campfire_test.rb:45:in `/'"
|
107
|
+
end
|
108
|
+
|
102
109
|
def fake_exception
|
103
110
|
5 / 0
|
104
111
|
rescue StandardError => e
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'test_helper'
|
2
4
|
require 'action_mailer'
|
3
5
|
require 'action_controller'
|
@@ -116,7 +118,7 @@ class EmailNotifierTest < ActiveSupport::TestCase
|
|
116
118
|
env: {
|
117
119
|
'REQUEST_METHOD' => 'GET',
|
118
120
|
'rack.input' => '',
|
119
|
-
'invalid_encoding' => "R\xC3\xA9sum\xC3\xA9".force_encoding(Encoding::ASCII)
|
121
|
+
'invalid_encoding' => "R\xC3\xA9sum\xC3\xA9".dup.force_encoding(Encoding::ASCII)
|
120
122
|
}
|
121
123
|
)
|
122
124
|
|
@@ -220,8 +222,10 @@ class EmailNotifierWithEnvTest < ActiveSupport::TestCase
|
|
220
222
|
email_headers: { 'X-Custom-Header' => 'foobar' },
|
221
223
|
sections: %w[new_section request session environment backtrace],
|
222
224
|
background_sections: %w[new_bkg_section backtrace data],
|
223
|
-
pre_callback:
|
224
|
-
|
225
|
+
pre_callback:
|
226
|
+
proc { |_opts, _notifier, _backtrace, _message, message_opts| message_opts[:pre_callback_called] = 1 },
|
227
|
+
post_callback:
|
228
|
+
proc { |_opts, _notifier, _backtrace, _message, message_opts| message_opts[:post_callback_called] = 1 }
|
225
229
|
)
|
226
230
|
|
227
231
|
@controller = HomeController.new
|
@@ -349,3 +353,25 @@ class EmailNotifierWithEnvTest < ActiveSupport::TestCase
|
|
349
353
|
assert_equal '[ERROR] (ZeroDivisionError) "divided by 0"', mail.subject
|
350
354
|
end
|
351
355
|
end
|
356
|
+
|
357
|
+
class EmailNotifierWithCustomParentClassTest < ActiveSupport::TestCase
|
358
|
+
class ApplicationMailer < ActionMailer::Base
|
359
|
+
default from: 'infrastructure@example.com'
|
360
|
+
end
|
361
|
+
|
362
|
+
setup do
|
363
|
+
@exception = ZeroDivisionError.new('divided by 0')
|
364
|
+
@exception.set_backtrace(["#{__FILE__}:#{__LINE__}"])
|
365
|
+
end
|
366
|
+
|
367
|
+
test 'uses default from configured parent class' do
|
368
|
+
email_notifier = ExceptionNotifier::EmailNotifier.new(
|
369
|
+
mailer_parent: 'EmailNotifierWithCustomParentClassTest::ApplicationMailer',
|
370
|
+
exception_recipients: %w[dummyexceptions@example.com]
|
371
|
+
)
|
372
|
+
mail = email_notifier.call(@exception)
|
373
|
+
|
374
|
+
assert email_notifier.__send__(:mailer) < ApplicationMailer
|
375
|
+
assert_equal ['infrastructure@example.com'], mail.from
|
376
|
+
end
|
377
|
+
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'test_helper'
|
2
4
|
require 'rack'
|
3
5
|
require 'httparty'
|
@@ -5,7 +7,7 @@ require 'timecop'
|
|
5
7
|
require 'json'
|
6
8
|
|
7
9
|
class GoogleChatNotifierTest < ActiveSupport::TestCase
|
8
|
-
URL = 'http://localhost:8000'
|
10
|
+
URL = 'http://localhost:8000'
|
9
11
|
|
10
12
|
def setup
|
11
13
|
Timecop.freeze('2018-12-09 12:07:16 UTC')
|
@@ -59,11 +61,7 @@ class GoogleChatNotifierTest < ActiveSupport::TestCase
|
|
59
61
|
header,
|
60
62
|
body,
|
61
63
|
'',
|
62
|
-
|
63
|
-
'```',
|
64
|
-
"* app/controllers/my_controller.rb:53:in `my_controller_params'",
|
65
|
-
"* app/controllers/my_controller.rb:34:in `update'",
|
66
|
-
'```'
|
64
|
+
backtrace
|
67
65
|
].join("\n")
|
68
66
|
|
69
67
|
HTTParty.expects(:post).with(URL, post_opts(text))
|
@@ -117,11 +115,7 @@ class GoogleChatNotifierTest < ActiveSupport::TestCase
|
|
117
115
|
'* timestamp : 2018-12-09 12:07:16 UTC',
|
118
116
|
'```',
|
119
117
|
'',
|
120
|
-
|
121
|
-
'```',
|
122
|
-
"* app/controllers/my_controller.rb:53:in `my_controller_params'",
|
123
|
-
"* app/controllers/my_controller.rb:34:in `update'",
|
124
|
-
'```'
|
118
|
+
backtrace
|
125
119
|
].join("\n")
|
126
120
|
|
127
121
|
HTTParty.expects(:post).with(URL, post_opts(text))
|
@@ -178,4 +172,14 @@ class GoogleChatNotifierTest < ActiveSupport::TestCase
|
|
178
172
|
def app_name
|
179
173
|
'dummy' if defined?(::Rails) && ::Rails.respond_to?(:application)
|
180
174
|
end
|
175
|
+
|
176
|
+
def backtrace
|
177
|
+
[
|
178
|
+
'*Backtrace:*',
|
179
|
+
'```',
|
180
|
+
"* app/controllers/my_controller.rb:53:in `my_controller_params'",
|
181
|
+
"* app/controllers/my_controller.rb:34:in `update'",
|
182
|
+
'```'
|
183
|
+
]
|
184
|
+
end
|
181
185
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'test_helper'
|
2
4
|
require 'rack'
|
3
5
|
|
@@ -33,7 +35,9 @@ class HipchatNotifierTest < ActiveSupport::TestCase
|
|
33
35
|
post_callback: proc { |*| post_callback_called += 1 }
|
34
36
|
}
|
35
37
|
|
36
|
-
HipChat::Room.any_instance
|
38
|
+
HipChat::Room.any_instance
|
39
|
+
.expects(:send)
|
40
|
+
.with('Exception', fake_body, { color: 'yellow' }.merge(options.except(:api_token, :room_name)))
|
37
41
|
|
38
42
|
hipchat = ExceptionNotifier::HipchatNotifier.new(options)
|
39
43
|
hipchat.call(fake_exception)
|
@@ -105,7 +109,9 @@ class HipchatNotifierTest < ActiveSupport::TestCase
|
|
105
109
|
message_template: ->(exception, _) { "This is custom message: '#{exception.message}'" }
|
106
110
|
}
|
107
111
|
|
108
|
-
HipChat::Room.any_instance
|
112
|
+
HipChat::Room.any_instance
|
113
|
+
.expects(:send)
|
114
|
+
.with('Exception', "This is custom message: '#{fake_exception.message}'", color: 'yellow')
|
109
115
|
|
110
116
|
hipchat = ExceptionNotifier::HipchatNotifier.new(options)
|
111
117
|
hipchat.call(fake_exception)
|
@@ -1,10 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'test_helper'
|
2
4
|
require 'httparty'
|
3
5
|
require 'timecop'
|
4
6
|
require 'json'
|
5
7
|
|
6
8
|
class MattermostNotifierTest < ActiveSupport::TestCase
|
7
|
-
URL = 'http://localhost:8000'
|
9
|
+
URL = 'http://localhost:8000'
|
8
10
|
|
9
11
|
def setup
|
10
12
|
Timecop.freeze('2018-12-09 12:07:16 UTC')
|
@@ -113,27 +115,14 @@ class MattermostNotifierTest < ActiveSupport::TestCase
|
|
113
115
|
end
|
114
116
|
|
115
117
|
test 'should include backtrace and request info' do
|
116
|
-
body = default_body.merge(
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
'* url : http://test.address/?id=foo',
|
125
|
-
'* http_method : GET',
|
126
|
-
'* ip_address : 127.0.0.1',
|
127
|
-
'* parameters : {"id"=>"foo"}',
|
128
|
-
'* timestamp : 2018-12-09 12:07:16 UTC',
|
129
|
-
'```',
|
130
|
-
'### Backtrace',
|
131
|
-
'```',
|
132
|
-
"* app/controllers/my_controller.rb:53:in `my_controller_params'",
|
133
|
-
"* app/controllers/my_controller.rb:34:in `update'",
|
134
|
-
'```'
|
135
|
-
].join("\n")
|
136
|
-
)
|
118
|
+
body = default_body.merge(text: [
|
119
|
+
'@channel',
|
120
|
+
error_occurred_in,
|
121
|
+
'An *ArgumentError* occurred.',
|
122
|
+
'*foo*',
|
123
|
+
request_info,
|
124
|
+
backtrace_info
|
125
|
+
].join("\n"))
|
137
126
|
|
138
127
|
opts = {
|
139
128
|
body: body.to_json,
|
@@ -151,6 +140,31 @@ class MattermostNotifierTest < ActiveSupport::TestCase
|
|
151
140
|
notifier.call(exception, env: test_env)
|
152
141
|
end
|
153
142
|
|
143
|
+
test 'should include exception_data_info' do
|
144
|
+
body = default_body.merge(
|
145
|
+
text: [
|
146
|
+
'@channel',
|
147
|
+
error_occurred_in,
|
148
|
+
'An *ArgumentError* occurred.',
|
149
|
+
'*foo*',
|
150
|
+
request_info,
|
151
|
+
exception_data_info
|
152
|
+
].join("\n")
|
153
|
+
)
|
154
|
+
|
155
|
+
opts = {
|
156
|
+
body: body.to_json,
|
157
|
+
headers: default_headers
|
158
|
+
}
|
159
|
+
|
160
|
+
env = test_env.merge(
|
161
|
+
'exception_notifier.exception_data' => { foo: 'bar', john: 'doe' }
|
162
|
+
)
|
163
|
+
|
164
|
+
HTTParty.expects(:post).with(URL, opts)
|
165
|
+
notifier.call(ArgumentError.new('foo'), env: env)
|
166
|
+
end
|
167
|
+
|
154
168
|
private
|
155
169
|
|
156
170
|
def notifier
|
@@ -193,10 +207,45 @@ class MattermostNotifierTest < ActiveSupport::TestCase
|
|
193
207
|
|
194
208
|
def github_link
|
195
209
|
if defined?(::Rails) && ::Rails.respond_to?(:application)
|
196
|
-
'[Create an issue]
|
210
|
+
'[Create an issue]' \
|
211
|
+
'(github.com/aschen/dummy/issues/new/?issue%5Btitle%5D=%5BBUG%5D+Error+500+%3A++%28ArgumentError%29+foo)'
|
197
212
|
else
|
198
213
|
# TODO: fix missing app name
|
199
|
-
'[Create an issue]
|
214
|
+
'[Create an issue]' \
|
215
|
+
'(github.com/aschen//issues/new/?issue%5Btitle%5D=%5BBUG%5D+Error+500+%3A++%28ArgumentError%29+foo)'
|
200
216
|
end
|
201
217
|
end
|
218
|
+
|
219
|
+
def request_info
|
220
|
+
[
|
221
|
+
'### Request',
|
222
|
+
'```',
|
223
|
+
'* url : http://test.address/?id=foo',
|
224
|
+
'* http_method : GET',
|
225
|
+
'* ip_address : 127.0.0.1',
|
226
|
+
'* parameters : {"id"=>"foo"}',
|
227
|
+
'* timestamp : 2018-12-09 12:07:16 UTC',
|
228
|
+
'```'
|
229
|
+
]
|
230
|
+
end
|
231
|
+
|
232
|
+
def backtrace_info
|
233
|
+
[
|
234
|
+
'### Backtrace',
|
235
|
+
'```',
|
236
|
+
"* app/controllers/my_controller.rb:53:in `my_controller_params'",
|
237
|
+
"* app/controllers/my_controller.rb:34:in `update'",
|
238
|
+
'```'
|
239
|
+
]
|
240
|
+
end
|
241
|
+
|
242
|
+
def exception_data_info
|
243
|
+
[
|
244
|
+
'### Data',
|
245
|
+
'```',
|
246
|
+
'* foo : bar',
|
247
|
+
'* john : doe',
|
248
|
+
'```'
|
249
|
+
]
|
250
|
+
end
|
202
251
|
end
|
@@ -1,9 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'test_helper'
|
2
4
|
|
3
5
|
# To allow sidekiq error handlers to be registered, sidekiq must be in
|
4
6
|
# "server mode". This mode is triggered by loading sidekiq/cli. Note this
|
5
7
|
# has to be loaded before exception_notification/sidekiq.
|
6
8
|
require 'sidekiq/cli'
|
9
|
+
require 'sidekiq/testing'
|
7
10
|
|
8
11
|
require 'exception_notification/sidekiq'
|
9
12
|
|
@@ -12,13 +15,6 @@ class MockSidekiqServer
|
|
12
15
|
end
|
13
16
|
|
14
17
|
class SidekiqTest < ActiveSupport::TestCase
|
15
|
-
setup do
|
16
|
-
@_original_sidekiq_logger = Sidekiq::Logging.logger
|
17
|
-
|
18
|
-
# Silence sidekiq warning to stdout
|
19
|
-
Sidekiq::Logging.logger = nil
|
20
|
-
end
|
21
|
-
|
22
18
|
test 'should call notify_exception when sidekiq raises an error' do
|
23
19
|
server = MockSidekiqServer.new
|
24
20
|
message = {}
|
@@ -31,8 +27,4 @@ class SidekiqTest < ActiveSupport::TestCase
|
|
31
27
|
|
32
28
|
server.handle_exception(exception, message)
|
33
29
|
end
|
34
|
-
|
35
|
-
teardown do
|
36
|
-
Sidekiq::Logging.logger = @_original_sidekiq_logger
|
37
|
-
end
|
38
30
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'test_helper'
|
2
4
|
require 'slack-notifier'
|
3
5
|
|
@@ -128,15 +130,17 @@ class SlackNotifierTest < ActiveSupport::TestCase
|
|
128
130
|
'exception_notifier.exception_data' => { foo: 'bar', john: 'doe' }
|
129
131
|
},
|
130
132
|
data: {
|
131
|
-
'user_id'
|
133
|
+
'user_id' => 5,
|
132
134
|
'key_to_be_ignored' => 'whatever',
|
133
|
-
'ignore_as_well'
|
135
|
+
'ignore_as_well' => { what: 'ever' }
|
134
136
|
}
|
135
137
|
}
|
136
138
|
|
137
139
|
expected_data_string = "foo: bar\njohn: doe\nuser_id: 5"
|
138
140
|
|
139
|
-
Slack::Notifier.any_instance
|
141
|
+
Slack::Notifier.any_instance
|
142
|
+
.expects(:ping)
|
143
|
+
.with('', fake_notification(@exception, notification_options, expected_data_string))
|
140
144
|
slack_notifier = ExceptionNotifier::SlackNotifier.new(options)
|
141
145
|
slack_notifier.call(@exception, notification_options)
|
142
146
|
end
|
@@ -184,12 +188,8 @@ class SlackNotifierTest < ActiveSupport::TestCase
|
|
184
188
|
|
185
189
|
def fake_backtrace
|
186
190
|
[
|
187
|
-
'backtrace line 1',
|
188
|
-
'backtrace line
|
189
|
-
'backtrace line 3',
|
190
|
-
'backtrace line 4',
|
191
|
-
'backtrace line 5',
|
192
|
-
'backtrace line 6'
|
191
|
+
'backtrace line 1', 'backtrace line 2', 'backtrace line 3',
|
192
|
+
'backtrace line 4', 'backtrace line 5', 'backtrace line 6'
|
193
193
|
]
|
194
194
|
end
|
195
195
|
|
@@ -197,7 +197,9 @@ class SlackNotifierTest < ActiveSupport::TestCase
|
|
197
197
|
fake_backtrace[2..-1]
|
198
198
|
end
|
199
199
|
|
200
|
-
def fake_notification(exception = @exception, notification_options = {},
|
200
|
+
def fake_notification(exception = @exception, notification_options = {},
|
201
|
+
data_string = nil, expected_backtrace_lines = 10, additional_fields = [])
|
202
|
+
|
201
203
|
exception_name = "*#{exception.class.to_s =~ /^[aeiou]/i ? 'An' : 'A'}* `#{exception.class}`"
|
202
204
|
if notification_options[:env].nil?
|
203
205
|
text = "#{exception_name} *occured in background*"
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'test_helper'
|
2
4
|
require 'aws-sdk-sns'
|
3
5
|
|
@@ -61,9 +63,9 @@ class SnsNotifierTest < ActiveSupport::TestCase
|
|
61
63
|
test 'should send a sns notification in background' do
|
62
64
|
Aws::SNS::Client.any_instance.expects(:publish).with(
|
63
65
|
topic_arn: 'topicARN',
|
64
|
-
message: "3 MyException occured in background\n"\
|
65
|
-
"Exception: undefined method 'method=' for Empty\n"\
|
66
|
-
"Hostname: example.com\n"\
|
66
|
+
message: "3 MyException occured in background\n" \
|
67
|
+
"Exception: undefined method 'method=' for Empty\n" \
|
68
|
+
"Hostname: example.com\n" \
|
67
69
|
"Backtrace:\n#{fake_backtrace.join("\n")}\n",
|
68
70
|
subject: '[App Exception] - 3 MyException occurred'
|
69
71
|
)
|
@@ -79,10 +81,10 @@ class SnsNotifierTest < ActiveSupport::TestCase
|
|
79
81
|
|
80
82
|
Aws::SNS::Client.any_instance.expects(:publish).with(
|
81
83
|
topic_arn: 'topicARN',
|
82
|
-
message: 'A MyException occurred while GET </examples> '\
|
83
|
-
"was processed by examples#index\n"\
|
84
|
-
"Exception: undefined method 'method=' for Empty\n"\
|
85
|
-
"Hostname: example.com\n"\
|
84
|
+
message: 'A MyException occurred while GET </examples> ' \
|
85
|
+
"was processed by examples#index\n" \
|
86
|
+
"Exception: undefined method 'method=' for Empty\n" \
|
87
|
+
"Hostname: example.com\n" \
|
86
88
|
"Backtrace:\n#{fake_backtrace.join("\n")}\n",
|
87
89
|
subject: '[App Exception] - A MyException occurred'
|
88
90
|
)
|