exception_notification 4.6.0 → 5.0.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 (59) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.rdoc +16 -0
  3. data/CONTRIBUTING.md +23 -51
  4. data/Gemfile +1 -1
  5. data/Gemfile.lock +27 -33
  6. data/README.md +65 -31
  7. data/Rakefile +14 -7
  8. data/exception_notification.gemspec +27 -30
  9. data/gemfiles/pinned_dependencies.gemfile +8 -0
  10. data/gemfiles/rails7_1.gemfile +5 -0
  11. data/gemfiles/rails7_2.gemfile +5 -0
  12. data/gemfiles/rails8_0.gemfile +5 -0
  13. data/lib/exception_notification/rack.rb +4 -4
  14. data/lib/exception_notification/rails.rb +2 -2
  15. data/lib/exception_notification/rake.rb +3 -7
  16. data/lib/exception_notification/resque.rb +2 -2
  17. data/lib/exception_notification/sidekiq.rb +8 -23
  18. data/lib/exception_notification/version.rb +1 -1
  19. data/lib/exception_notification.rb +3 -3
  20. data/lib/exception_notifier/datadog_notifier.rb +26 -26
  21. data/lib/exception_notifier/email_notifier.rb +34 -30
  22. data/lib/exception_notifier/google_chat_notifier.rb +9 -9
  23. data/lib/exception_notifier/hipchat_notifier.rb +12 -12
  24. data/lib/exception_notifier/irc_notifier.rb +6 -6
  25. data/lib/exception_notifier/mattermost_notifier.rb +13 -13
  26. data/lib/exception_notifier/modules/error_grouping.rb +5 -5
  27. data/lib/exception_notifier/modules/formatter.rb +12 -12
  28. data/lib/exception_notifier/notifier.rb +3 -3
  29. data/lib/exception_notifier/slack_notifier.rb +16 -16
  30. data/lib/exception_notifier/sns_notifier.rb +9 -9
  31. data/lib/exception_notifier/teams_notifier.rb +61 -57
  32. data/lib/exception_notifier/webhook_notifier.rb +3 -3
  33. data/lib/exception_notifier.rb +27 -26
  34. data/lib/generators/exception_notification/install_generator.rb +7 -7
  35. data/lib/generators/exception_notification/templates/exception_notification.rb.erb +26 -27
  36. data/test/exception_notification/rack_test.rb +14 -14
  37. data/test/exception_notification/rake_test.rb +13 -13
  38. data/test/exception_notification/resque_test.rb +14 -14
  39. data/test/exception_notifier/datadog_notifier_test.rb +47 -46
  40. data/test/exception_notifier/email_notifier_test.rb +89 -98
  41. data/test/exception_notifier/google_chat_notifier_test.rb +77 -77
  42. data/test/exception_notifier/hipchat_notifier_test.rb +76 -74
  43. data/test/exception_notifier/irc_notifier_test.rb +26 -26
  44. data/test/exception_notifier/mattermost_notifier_test.rb +77 -77
  45. data/test/exception_notifier/modules/error_grouping_test.rb +39 -39
  46. data/test/exception_notifier/modules/formatter_test.rb +51 -49
  47. data/test/exception_notifier/sidekiq_test.rb +17 -10
  48. data/test/exception_notifier/slack_notifier_test.rb +66 -67
  49. data/test/exception_notifier/sns_notifier_test.rb +73 -70
  50. data/test/exception_notifier/teams_notifier_test.rb +33 -33
  51. data/test/exception_notifier/webhook_notifier_test.rb +34 -34
  52. data/test/exception_notifier_test.rb +51 -41
  53. data/test/test_helper.rb +8 -11
  54. metadata +45 -85
  55. data/Appraisals +0 -9
  56. data/gemfiles/rails5_2.gemfile +0 -7
  57. data/gemfiles/rails6_0.gemfile +0 -7
  58. data/gemfiles/rails6_1.gemfile +0 -7
  59. data/gemfiles/rails7_0.gemfile +0 -7
@@ -1,22 +1,21 @@
1
1
  # Move this require to your `config/application.rb` if you want to be notified from runner commands too.
2
- require 'exception_notification/rails'
3
- require 'exception_notification/rake'
2
+ require "exception_notification/rails"
3
+ require "exception_notification/rake"
4
4
  <% if options.sidekiq? %>
5
- require 'exception_notification/sidekiq'
6
- <% end %>
7
- <% if options.resque? %>
8
- require 'resque/failure/multiple'
9
- require 'resque/failure/redis'
10
- require 'exception_notification/resque'
5
+ require "exception_notification/sidekiq"<% end %><% if options.resque? %>
6
+ require "resque/failure/multiple"
7
+ require "resque/failure/redis"
8
+ require "exception_notification/resque"
11
9
 
12
- Resque::Failure::Multiple.classes = [Resque::Failure::Redis, ExceptionNotification::Resque]
13
- Resque::Failure.backend = Resque::Failure::Multiple
14
- <% end %>
10
+ Resque::Failure::Multiple.classes = [ Resque::Failure::Redis, ExceptionNotification::Resque ]
11
+ Resque::Failure.backend = Resque::Failure::Multiple<% end %>
15
12
 
16
13
  ExceptionNotification.configure do |config|
17
- # Ignore additional exception types.
18
- # ActiveRecord::RecordNotFound, Mongoid::Errors::DocumentNotFound, AbstractController::ActionNotFound and ActionController::RoutingError are already added.
19
- # config.ignored_exceptions += %w{ActionView::TemplateError CustomError}
14
+ # Ignore additional exception types. The default list of exception classes is:
15
+ # ActiveRecord::RecordNotFound Mongoid::Errors::DocumentNotFound AbstractController::ActionNotFound
16
+ # ActionController::RoutingError ActionController::UnknownFormat ActionController::UrlGenerationError
17
+ # ActionDispatch::Http::MimeNegotiation::InvalidType Rack::Utils::InvalidParameterError
18
+ # config.ignored_exceptions += %w[ActionView::TemplateError CustomError]
20
19
 
21
20
  # Adds a condition to decide when an exception must be ignored or not.
22
21
  # The ignore_if method can be invoked multiple times to add extra conditions.
@@ -25,33 +24,33 @@ ExceptionNotification.configure do |config|
25
24
  # end
26
25
 
27
26
  # Ignore exceptions generated by crawlers
28
- # config.ignore_crawlers %w{Googlebot bingbot}
27
+ # config.ignore_crawlers %w[Googlebot bingbot]
29
28
 
30
29
  # Notifiers =================================================================
31
30
 
32
31
  # Email notifier sends notifications by email.
33
32
  config.add_notifier :email, {
34
- email_prefix: '[ERROR] ',
35
- sender_address: %{"Notifier" <notifier@example.com>},
36
- exception_recipients: %w{exceptions@example.com}
33
+ email_prefix: "[ERROR] ",
34
+ sender_address: %("Notifier" <notifier@example.com>),
35
+ exception_recipients: %w[exceptions@example.com]
37
36
  }
38
37
 
39
- # Campfire notifier sends notifications to your Campfire room. Requires 'tinder' gem.
38
+ # Campfire notifier sends notifications to your Campfire room. Requires "tinder" gem.
40
39
  # config.add_notifier :campfire, {
41
- # subdomain: 'my_subdomain',
42
- # token: 'my_token',
43
- # room_name: 'my_room'
40
+ # subdomain: "my_subdomain",
41
+ # token: "my_token",
42
+ # room_name: "my_room"
44
43
  # }
45
44
 
46
- # HipChat notifier sends notifications to your HipChat room. Requires 'hipchat' gem.
45
+ # HipChat notifier sends notifications to your HipChat room. Requires "hipchat" gem.
47
46
  # config.add_notifier :hipchat, {
48
- # api_token: 'my_token',
49
- # room_name: 'my_room'
47
+ # api_token: "my_token",
48
+ # room_name: "my_room"
50
49
  # }
51
50
 
52
- # Webhook notifier sends notifications over HTTP protocol. Requires 'httparty' gem.
51
+ # Webhook notifier sends notifications over HTTP protocol. Requires "httparty" gem.
53
52
  # config.add_notifier :webhook, {
54
- # url: 'http://example.com:5555/hubot/path',
53
+ # url: "http://example.com:5555/hubot/path",
55
54
  # http_method: :post
56
55
  # }
57
56
  end
@@ -1,11 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'test_helper'
3
+ require "test_helper"
4
4
 
5
5
  class RackTest < ActiveSupport::TestCase
6
6
  setup do
7
7
  @pass_app = Object.new
8
- @pass_app.stubs(:call).returns([nil, { 'X-Cascade' => 'pass' }, nil])
8
+ @pass_app.stubs(:call).returns([nil, {"X-Cascade" => "pass"}, nil])
9
9
 
10
10
  @normal_app = Object.new
11
11
  @normal_app.stubs(:call).returns([nil, {}, nil])
@@ -25,41 +25,41 @@ class RackTest < ActiveSupport::TestCase
25
25
  ExceptionNotification::Rack.new(@pass_app, ignore_cascade_pass: false).call({})
26
26
  end
27
27
 
28
- test 'should assign error_grouping if error_grouping is specified' do
28
+ test "should assign error_grouping if error_grouping is specified" do
29
29
  refute ExceptionNotifier.error_grouping
30
30
  ExceptionNotification::Rack.new(@normal_app, error_grouping: true).call({})
31
31
  assert ExceptionNotifier.error_grouping
32
32
  end
33
33
 
34
- test 'should assign notification_trigger if notification_trigger is specified' do
34
+ test "should assign notification_trigger if notification_trigger is specified" do
35
35
  assert_nil ExceptionNotifier.notification_trigger
36
36
  ExceptionNotification::Rack.new(@normal_app, notification_trigger: ->(_i) { true }).call({})
37
37
  assert_respond_to ExceptionNotifier.notification_trigger, :call
38
38
  end
39
39
 
40
40
  if defined?(Rails) && Rails.respond_to?(:cache)
41
- test 'should set default cache to Rails cache' do
41
+ test "should set default cache to Rails cache" do
42
42
  ExceptionNotification::Rack.new(@normal_app, error_grouping: true).call({})
43
43
  assert_equal Rails.cache, ExceptionNotifier.error_grouping_cache
44
44
  end
45
45
  end
46
46
 
47
- test 'should ignore exceptions with Usar Agent in ignore_crawlers' do
47
+ test "should ignore exceptions with Usar Agent in ignore_crawlers" do
48
48
  exception_app = Object.new
49
49
  exception_app.stubs(:call).raises(RuntimeError)
50
50
 
51
- env = { 'HTTP_USER_AGENT' => 'Mozilla/5.0 (compatible; Crawlerbot/2.1;)' }
51
+ env = {"HTTP_USER_AGENT" => "Mozilla/5.0 (compatible; Crawlerbot/2.1;)"}
52
52
 
53
53
  begin
54
54
  ExceptionNotification::Rack.new(exception_app, ignore_crawlers: %w[Crawlerbot]).call(env)
55
55
 
56
56
  flunk
57
- rescue StandardError
58
- refute env['exception_notifier.delivered']
57
+ rescue
58
+ refute env["exception_notifier.delivered"]
59
59
  end
60
60
  end
61
61
 
62
- test 'should ignore exceptions if ignore_if condition is met' do
62
+ test "should ignore exceptions if ignore_if condition is met" do
63
63
  exception_app = Object.new
64
64
  exception_app.stubs(:call).raises(RuntimeError)
65
65
 
@@ -72,12 +72,12 @@ class RackTest < ActiveSupport::TestCase
72
72
  ).call(env)
73
73
 
74
74
  flunk
75
- rescue StandardError
76
- refute env['exception_notifier.delivered']
75
+ rescue
76
+ refute env["exception_notifier.delivered"]
77
77
  end
78
78
  end
79
79
 
80
- test 'should ignore exceptions with notifiers that satisfies ignore_notifier_if condition' do
80
+ test "should ignore exceptions with notifiers that satisfies ignore_notifier_if condition" do
81
81
  exception_app = Object.new
82
82
  exception_app.stubs(:call).raises(RuntimeError)
83
83
 
@@ -98,7 +98,7 @@ class RackTest < ActiveSupport::TestCase
98
98
  ).call(env)
99
99
 
100
100
  flunk
101
- rescue StandardError
101
+ rescue
102
102
  refute notifier1_called
103
103
  assert notifier2_called
104
104
  end
@@ -1,33 +1,33 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'test_helper'
3
+ require "test_helper"
4
4
 
5
- require 'rake'
6
- require 'exception_notification/rake'
5
+ require "rake"
6
+ require "exception_notification/rake"
7
7
 
8
8
  class RakeTest < ActiveSupport::TestCase
9
9
  setup do
10
10
  Rake::Task.define_task :dependency_1 do
11
- puts :dependency_1
11
+ nil # noop but could puts for debugging
12
12
  end
13
13
  Rake::Task.define_task raise_exception: :dependency_1 do
14
- raise 'test exception'
14
+ raise "test exception"
15
15
  end
16
16
  @task = Rake::Task[:raise_exception]
17
17
  end
18
18
 
19
- test 'notifies of exception' do
19
+ test "notifies of exception" do
20
20
  ExceptionNotifier.expects(:notify_exception).with do |ex, opts|
21
21
  data = opts[:data]
22
22
  ex.is_a?(RuntimeError) &&
23
- ex.message == 'test exception' &&
24
- data[:error_class] == 'RuntimeError' &&
25
- data[:error_message] == 'test exception' &&
26
- data[:rake][:rake_command_line] == 'rake ' &&
27
- data[:rake][:name] == 'raise_exception' &&
23
+ ex.message == "test exception" &&
24
+ data[:error_class] == "RuntimeError" &&
25
+ data[:error_message] == "test exception" &&
26
+ data[:rake][:rake_command_line] == "rake " &&
27
+ data[:rake][:name] == "raise_exception" &&
28
28
  data[:rake][:timestamp] &&
29
- data[:rake][:sources] == ['dependency_1'] &&
30
- data[:rake][:prerequisite_tasks][0][:name] == 'dependency_1'
29
+ data[:rake][:sources] == ["dependency_1"] &&
30
+ data[:rake][:prerequisite_tasks][0][:name] == "dependency_1"
31
31
  end
32
32
 
33
33
  # The original error is re-raised
@@ -1,12 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'test_helper'
3
+ require "test_helper"
4
4
 
5
- require 'exception_notification/resque'
6
- require 'resque'
7
- require 'mock_redis'
8
- require 'resque/failure/multiple'
9
- require 'resque/failure/redis'
5
+ require "exception_notification/resque"
6
+ require "resque"
7
+ require "mock_redis"
8
+ require "resque/failure/multiple"
9
+ require "resque/failure/redis"
10
10
 
11
11
  class ResqueTest < ActiveSupport::TestCase
12
12
  setup do
@@ -21,22 +21,22 @@ class ResqueTest < ActiveSupport::TestCase
21
21
  @worker.cant_fork = true
22
22
  end
23
23
 
24
- test 'count returns the number of failures' do
24
+ test "count returns the number of failures" do
25
25
  Resque::Job.create(:jobs, BadJob)
26
26
  @worker.work(0)
27
27
  assert_equal 1, ExceptionNotification::Resque.count
28
28
  end
29
29
 
30
- test 'notifies exception when job fails' do
30
+ test "notifies exception when job fails" do
31
31
  ExceptionNotifier.expects(:notify_exception).with do |ex, opts|
32
32
  ex.is_a?(RuntimeError) &&
33
- ex.message == 'Bad job!' &&
34
- opts[:data][:resque][:error_class] == 'RuntimeError' &&
35
- opts[:data][:resque][:error_message] == 'Bad job!' &&
33
+ ex.message == "Bad job!" &&
34
+ opts[:data][:resque][:error_class] == "RuntimeError" &&
35
+ opts[:data][:resque][:error_message] == "Bad job!" &&
36
36
  opts[:data][:resque][:failed_at].present? &&
37
37
  opts[:data][:resque][:payload] == {
38
- 'class' => 'ResqueTest::BadJob',
39
- 'args' => []
38
+ "class" => "ResqueTest::BadJob",
39
+ "args" => []
40
40
  } &&
41
41
  opts[:data][:resque][:queue] == :jobs &&
42
42
  opts[:data][:resque][:worker].present?
@@ -48,7 +48,7 @@ class ResqueTest < ActiveSupport::TestCase
48
48
 
49
49
  class BadJob
50
50
  def self.perform
51
- raise 'Bad job!'
51
+ raise "Bad job!"
52
52
  end
53
53
  end
54
54
  end
@@ -1,8 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'test_helper'
4
- require 'dogapi/common'
5
- require 'dogapi/event'
3
+ require "test_helper"
4
+ require "dogapi/common"
5
+ require "dogapi/event"
6
6
 
7
7
  class DatadogNotifierTest < ActiveSupport::TestCase
8
8
  def setup
@@ -16,7 +16,7 @@ class DatadogNotifierTest < ActiveSupport::TestCase
16
16
  @request = FakeRequest.new
17
17
  end
18
18
 
19
- test 'should send an event to datadog' do
19
+ test "should send an event to datadog" do
20
20
  fake_event = Dogapi::Event.any_instance
21
21
  @client.expects(:emit_event).with(fake_event)
22
22
 
@@ -24,15 +24,15 @@ class DatadogNotifierTest < ActiveSupport::TestCase
24
24
  @notifier.call(@exception)
25
25
  end
26
26
 
27
- test 'should include exception class in event title' do
27
+ test "should include exception class in event title" do
28
28
  event = @notifier.datadog_event(@exception)
29
- assert_includes event.msg_title, 'FakeException'
29
+ assert_includes event.msg_title, "FakeException"
30
30
  end
31
31
 
32
- test 'should include prefix in event title and not append previous events' do
32
+ test "should include prefix in event title and not append previous events" do
33
33
  options = {
34
34
  client: @client,
35
- title_prefix: 'prefix'
35
+ title_prefix: "prefix"
36
36
  }
37
37
 
38
38
  notifier = ExceptionNotifier::DatadogNotifier.new(options)
@@ -43,43 +43,43 @@ class DatadogNotifierTest < ActiveSupport::TestCase
43
43
  assert_equal event2.msg_title, 'prefix (DatadogNotifierTest::FakeException) "Fake exception message"'
44
44
  end
45
45
 
46
- test 'should include exception message in event title' do
46
+ test "should include exception message in event title" do
47
47
  event = @notifier.datadog_event(@exception)
48
- assert_includes event.msg_title, 'Fake exception message'
48
+ assert_includes event.msg_title, "Fake exception message"
49
49
  end
50
50
 
51
- test 'should include controller info in event title if controller information is available' do
51
+ test "should include controller info in event title if controller information is available" do
52
52
  event = @notifier.datadog_event(@exception,
53
- env: {
54
- 'action_controller.instance' => @controller,
55
- 'REQUEST_METHOD' => 'GET',
56
- 'rack.input' => ''
57
- })
58
- assert_includes event.msg_title, 'Fake controller'
59
- assert_includes event.msg_title, 'Fake action'
53
+ env: {
54
+ "action_controller.instance" => @controller,
55
+ "REQUEST_METHOD" => "GET",
56
+ "rack.input" => ""
57
+ })
58
+ assert_includes event.msg_title, "Fake controller"
59
+ assert_includes event.msg_title, "Fake action"
60
60
  end
61
61
 
62
- test 'should include backtrace info in event body' do
62
+ test "should include backtrace info in event body" do
63
63
  event = @notifier.datadog_event(@exception)
64
64
  assert_includes event.msg_text, "backtrace line 1\nbacktrace line 2\nbacktrace line 3"
65
65
  end
66
66
 
67
- test 'should include request info in event body' do
67
+ test "should include request info in event body" do
68
68
  ActionDispatch::Request.stubs(:new).returns(@request)
69
69
 
70
70
  event = @notifier.datadog_event(@exception,
71
- env: {
72
- 'action_controller.instance' => @controller,
73
- 'REQUEST_METHOD' => 'GET',
74
- 'rack.input' => ''
75
- })
76
- assert_includes event.msg_text, 'http://localhost:8080'
77
- assert_includes event.msg_text, 'GET'
78
- assert_includes event.msg_text, '127.0.0.1'
79
- assert_includes event.msg_text, '{"param 1"=>"value 1", "param 2"=>"value 2"}'
71
+ env: {
72
+ "action_controller.instance" => @controller,
73
+ "REQUEST_METHOD" => "GET",
74
+ "rack.input" => ""
75
+ })
76
+ assert_includes event.msg_text, "http://localhost:8080"
77
+ assert_includes event.msg_text, "GET"
78
+ assert_includes event.msg_text, "127.0.0.1"
79
+ assert_includes event.msg_text, {"param 1" => "value 1", "param 2" => "value 2"}.to_s
80
80
  end
81
81
 
82
- test 'should include tags in event' do
82
+ test "should include tags in event" do
83
83
  options = {
84
84
  client: @client,
85
85
  tags: %w[error production]
@@ -89,64 +89,65 @@ class DatadogNotifierTest < ActiveSupport::TestCase
89
89
  assert_equal event.tags, %w[error production]
90
90
  end
91
91
 
92
- test 'should include event title in event aggregation key' do
92
+ test "should include event title in event aggregation key" do
93
93
  event = @notifier.datadog_event(@exception)
94
94
  assert_equal event.aggregation_key, [event.msg_title]
95
95
  end
96
96
 
97
97
  class FakeDatadogClient
98
- def emit_event(event); end
98
+ def emit_event(event)
99
+ end
99
100
  end
100
101
 
101
102
  class FakeController
102
103
  def controller_name
103
- 'Fake controller'
104
+ "Fake controller"
104
105
  end
105
106
 
106
107
  def action_name
107
- 'Fake action'
108
+ "Fake action"
108
109
  end
109
110
  end
110
111
 
111
112
  class FakeException
112
113
  def backtrace
113
114
  [
114
- 'backtrace line 1',
115
- 'backtrace line 2',
116
- 'backtrace line 3',
117
- 'backtrace line 4',
118
- 'backtrace line 5'
115
+ "backtrace line 1",
116
+ "backtrace line 2",
117
+ "backtrace line 3",
118
+ "backtrace line 4",
119
+ "backtrace line 5"
119
120
  ]
120
121
  end
121
122
 
122
123
  def message
123
- 'Fake exception message'
124
+ "Fake exception message"
124
125
  end
125
126
  end
126
127
 
127
128
  class FakeRequest
128
129
  def url
129
- 'http://localhost:8080'
130
+ "http://localhost:8080"
130
131
  end
131
132
 
132
133
  def request_method
133
- 'GET'
134
+ "GET"
134
135
  end
135
136
 
136
137
  def remote_ip
137
- '127.0.0.1'
138
+ "127.0.0.1"
138
139
  end
139
140
 
140
141
  def filtered_parameters
141
142
  {
142
- 'param 1' => 'value 1',
143
- 'param 2' => 'value 2'
143
+ "param 1" => "value 1",
144
+ "param 2" => "value 2"
144
145
  }
145
146
  end
146
147
 
147
148
  def session
148
149
  {
149
- 'session_id' => '1234'
150
+ "session_id" => "1234"
150
151
  }
151
152
  end
152
153
  end