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,136 +1,44 @@
1
- require 'action_dispatch'
2
- require 'active_support/core_ext/time'
1
+ # frozen_string_literal: true
3
2
 
4
- module ExceptionNotifier
5
- class GoogleChatNotifier
6
- include ExceptionNotifier::BacktraceCleaner
7
-
8
- class MissingController
9
- def method_missing(*args, &block)
10
- end
11
- end
12
-
13
- attr_accessor :httparty
14
-
15
- def initialize(options = {})
16
- super()
17
- @default_options = options
18
- @httparty = HTTParty
19
- end
20
-
21
- def call(exception, options = {})
22
- @options = options.merge(@default_options)
23
- @exception = exception
24
- @backtrace = exception.backtrace ? clean_backtrace(exception) : nil
25
-
26
- @env = @options.delete(:env)
27
-
28
- @application_name = @options.delete(:app_name) || Rails.application.class.parent_name.underscore
29
-
30
- @webhook_url = @options.delete(:webhook_url)
31
- raise ArgumentError.new "You must provide 'webhook_url' parameter." unless @webhook_url
3
+ require 'httparty'
32
4
 
33
- unless @env.nil?
34
- @controller = @env['action_controller.instance'] || MissingController.new
35
-
36
- request = ActionDispatch::Request.new(@env)
37
-
38
- @request_items = { url: request.original_url,
39
- http_method: request.method,
40
- ip_address: request.remote_ip,
41
- parameters: request.filtered_parameters,
42
- timestamp: Time.current }
43
- else
44
- @controller = @request_items = nil
45
- end
46
-
47
-
48
- @options[:body] = payload.to_json
49
- @options[:headers] ||= {}
50
- @options[:headers].merge!({ 'Content-Type' => 'application/json' })
5
+ module ExceptionNotifier
6
+ class GoogleChatNotifier < BaseNotifier
7
+ def call(exception, opts = {})
8
+ options = base_options.merge(opts)
9
+ formatter = Formatter.new(exception, options)
51
10
 
52
- @httparty.post(@webhook_url, @options)
11
+ HTTParty.post(
12
+ options[:webhook_url],
13
+ body: { text: body(exception, formatter) }.to_json,
14
+ headers: { 'Content-Type' => 'application/json' }
15
+ )
53
16
  end
54
17
 
55
18
  private
56
19
 
57
- def payload
58
- {
59
- text: exception_text
60
- }
61
- end
62
-
63
- def header
64
- errors_count = @options[:accumulated_errors_count].to_i
65
- text = ['']
20
+ def body(exception, formatter)
21
+ text = [
22
+ "\nApplication: *#{formatter.app_name}*",
23
+ formatter.subtitle,
24
+ '',
25
+ formatter.title,
26
+ "*#{exception.message.tr('`', "'")}*"
27
+ ]
66
28
 
67
- text << "Application: *#{@application_name}*"
68
- text << "#{errors_count > 1 ? errors_count : 'An'} *#{@exception.class}* occured" + if @controller then " in *#{controller_and_method}*." else "." end
69
-
70
- text
71
- end
72
-
73
- def exception_text
74
- text = []
75
-
76
- text << header
77
- text << ''
78
-
79
- text << "⚠️ Error 500 in #{Rails.env} ⚠️"
80
- text << "*#{@exception.message.gsub('`', %q('))}*"
81
-
82
- if @request_items
29
+ if (request = formatter.request_message.presence)
83
30
  text << ''
84
- text += message_request
31
+ text << '*Request:*'
32
+ text << request
85
33
  end
86
34
 
87
- if @backtrace
35
+ if (backtrace = formatter.backtrace_message.presence)
88
36
  text << ''
89
- text += message_backtrace
90
- end
91
-
92
- text.join("\n")
93
- end
94
-
95
- def message_request
96
- text = []
97
-
98
- text << "*Request:*"
99
- text << "```"
100
- text << hash_presentation(@request_items)
101
- text << "```"
102
-
103
- text
104
- end
105
-
106
- def hash_presentation(hash)
107
- text = []
108
-
109
- hash.each do |key, value|
110
- text << "* #{key} : #{value}"
37
+ text << '*Backtrace:*'
38
+ text << backtrace
111
39
  end
112
40
 
113
- text.join("\n")
114
- end
115
-
116
- def message_backtrace(size = 3)
117
- text = []
118
-
119
- size = @backtrace.size < size ? @backtrace.size : size
120
- text << "*Backtrace:*"
121
- text << "```"
122
- size.times { |i| text << "* " + @backtrace[i] }
123
- text << "```"
124
-
125
- text
126
- end
127
-
128
- def controller_and_method
129
- if @controller
130
- "#{@controller.controller_name}##{@controller.action_name}"
131
- else
132
- ""
133
- end
41
+ text.compact.join("\n")
134
42
  end
135
43
  end
136
44
  end
@@ -1,6 +1,7 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ExceptionNotifier
2
4
  class HipchatNotifier < BaseNotifier
3
-
4
5
  attr_accessor :from
5
6
  attr_accessor :room
6
7
  attr_accessor :message_options
@@ -11,29 +12,29 @@ module ExceptionNotifier
11
12
  api_token = options.delete(:api_token)
12
13
  room_name = options.delete(:room_name)
13
14
  opts = {
14
- :api_version => options.delete(:api_version) || 'v1'
15
- }
15
+ api_version: options.delete(:api_version) || 'v1'
16
+ }
16
17
  opts[:server_url] = options.delete(:server_url) if options[:server_url]
17
18
  @from = options.delete(:from) || 'Exception'
18
19
  @room = HipChat::Client.new(api_token, opts)[room_name]
19
- @message_template = options.delete(:message_template) || ->(exception, errors_count) {
20
+ @message_template = options.delete(:message_template) || lambda { |exception, errors_count|
20
21
  msg = if errors_count > 1
21
- "The exception occurred #{errors_count} times: '#{Rack::Utils.escape_html(exception.message)}'"
22
- else
23
- "A new exception occurred: '#{Rack::Utils.escape_html(exception.message)}'"
24
- end
22
+ "The exception occurred #{errors_count} times: '#{Rack::Utils.escape_html(exception.message)}'"
23
+ else
24
+ "A new exception occurred: '#{Rack::Utils.escape_html(exception.message)}'"
25
+ end
25
26
  msg += " on '#{exception.backtrace.first}'" if exception.backtrace
26
27
  msg
27
28
  }
28
- @message_options = options
29
+ @message_options = options
29
30
  @message_options[:color] ||= 'red'
30
- rescue
31
+ rescue StandardError
31
32
  @room = nil
32
33
  end
33
34
  end
34
35
 
35
- def call(exception, options={})
36
- return if !active?
36
+ def call(exception, options = {})
37
+ return unless active?
37
38
 
38
39
  message = @message_template.call(exception, options[:accumulated_errors_count].to_i)
39
40
  send_notice(exception, options, message, @message_options) do |msg, message_opts|
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ExceptionNotifier
2
4
  class IrcNotifier < BaseNotifier
3
5
  def initialize(options)
@@ -6,50 +8,51 @@ module ExceptionNotifier
6
8
  parse_options(options)
7
9
  end
8
10
 
9
- def call(exception, options={})
11
+ def call(exception, options = {})
10
12
  errors_count = options[:accumulated_errors_count].to_i
11
13
 
12
- message = "'#{exception.message}'"
13
- message.prepend("(#{errors_count} times)") if errors_count > 1
14
-
14
+ occurrences = "(#{errors_count} times)" if errors_count > 1
15
+ message = "#{occurrences}'#{exception.message}'"
15
16
  message += " on '#{exception.backtrace.first}'" if exception.backtrace
16
- if active?
17
- send_notice(exception, options, message) do |msg, _|
18
- send_message([*@config.prefix, *msg].join(' '))
19
- end
17
+
18
+ return unless active?
19
+
20
+ send_notice(exception, options, message) do |msg, _|
21
+ send_message([*@config.prefix, *msg].join(' '))
20
22
  end
21
23
  end
22
24
 
23
25
  def send_message(message)
24
- CarrierPigeon.send @config.irc.merge({message: message})
26
+ CarrierPigeon.send @config.irc.merge(message: message)
25
27
  end
26
28
 
27
29
  private
28
- def parse_options(options)
29
- nick = options.fetch(:nick, 'ExceptionNotifierBot')
30
- password = options[:password] ? ":#{options[:password]}" : nil
31
- domain = options.fetch(:domain, nil)
32
- port = options[:port] ? ":#{options[:port]}" : nil
33
- channel = options.fetch(:channel, '#log')
34
- notice = options.fetch(:notice, false)
35
- ssl = options.fetch(:ssl, false)
36
- join = options.fetch(:join, false)
37
- uri = "irc://#{nick}#{password}@#{domain}#{port}/#{channel}"
38
- prefix = options.fetch(:prefix, nil)
39
- recipients = options[:recipients] ? options[:recipients].join(', ') + ':' : nil
40
-
41
- @config.prefix = [*prefix, *recipients].join(' ')
42
- @config.irc = { uri: uri, ssl: ssl, notice: notice, join: join }
43
- end
44
30
 
45
- def active?
46
- valid_uri? @config.irc[:uri]
47
- end
31
+ def parse_options(options)
32
+ nick = options.fetch(:nick, 'ExceptionNotifierBot')
33
+ password = options[:password] ? ":#{options[:password]}" : nil
34
+ domain = options.fetch(:domain, nil)
35
+ port = options[:port] ? ":#{options[:port]}" : nil
36
+ channel = options.fetch(:channel, '#log')
37
+ notice = options.fetch(:notice, false)
38
+ ssl = options.fetch(:ssl, false)
39
+ join = options.fetch(:join, false)
40
+ uri = "irc://#{nick}#{password}@#{domain}#{port}/#{channel}"
41
+ prefix = options.fetch(:prefix, nil)
42
+ recipients = options[:recipients] ? options[:recipients].join(', ') + ':' : nil
43
+
44
+ @config.prefix = [*prefix, *recipients].join(' ')
45
+ @config.irc = { uri: uri, ssl: ssl, notice: notice, join: join }
46
+ end
48
47
 
49
- def valid_uri?(uri)
50
- !!URI.parse(uri)
51
- rescue URI::InvalidURIError
52
- false
53
- end
48
+ def active?
49
+ valid_uri? @config.irc[:uri]
50
+ end
51
+
52
+ def valid_uri?(uri)
53
+ URI.parse(uri)
54
+ rescue URI::InvalidURIError
55
+ false
56
+ end
54
57
  end
55
58
  end
@@ -1,165 +1,82 @@
1
- require 'action_dispatch'
2
- require 'active_support/core_ext/time'
1
+ # frozen_string_literal: true
3
2
 
4
- module ExceptionNotifier
5
- class MattermostNotifier
6
- include ExceptionNotifier::BacktraceCleaner
7
-
8
- class MissingController
9
- def method_missing(*args, &block)
10
- end
11
- end
12
-
13
- attr_accessor :httparty
3
+ require 'httparty'
14
4
 
15
- def initialize(options = {})
16
- super()
17
- @default_options = options
18
- @httparty = HTTParty
19
- end
20
-
21
- def call(exception, options = {})
22
- @options = options.merge(@default_options)
5
+ module ExceptionNotifier
6
+ class MattermostNotifier < BaseNotifier
7
+ def call(exception, opts = {})
8
+ options = opts.merge(base_options)
23
9
  @exception = exception
24
- @backtrace = exception.backtrace ? clean_backtrace(exception) : nil
25
-
26
- @env = @options.delete(:env)
27
10
 
28
- @application_name = @options.delete(:app_name) || Rails.application.class.parent_name.underscore
29
- @gitlab_url = @options.delete(:git_url)
30
- @username = @options.delete(:username) || "Exception Notifier"
31
- @avatar = @options.delete(:avatar)
11
+ @formatter = Formatter.new(exception, options)
32
12
 
33
- @channel = @options.delete(:channel)
34
- @webhook_url = @options.delete(:webhook_url)
35
- raise ArgumentError.new "You must provide 'webhook_url' parameter." unless @webhook_url
13
+ @gitlab_url = options[:git_url]
36
14
 
37
- unless @env.nil?
38
- @controller = @env['action_controller.instance'] || MissingController.new
15
+ @env = options[:env] || {}
39
16
 
40
- request = ActionDispatch::Request.new(@env)
17
+ payload = {
18
+ text: message_text.compact.join("\n"),
19
+ username: options[:username] || 'Exception Notifier'
20
+ }
41
21
 
42
- @request_items = { url: request.original_url,
43
- http_method: request.method,
44
- ip_address: request.remote_ip,
45
- parameters: request.filtered_parameters,
46
- timestamp: Time.current }
22
+ payload[:icon_url] = options[:avatar] if options[:avatar]
23
+ payload[:channel] = options[:channel] if options[:channel]
47
24
 
48
- if request.session["warden.user.user.key"]
49
- current_user = User.find(request.session["warden.user.user.key"][0][0])
50
- @request_items.merge!({ current_user: { id: current_user.id, email: current_user.email } })
51
- end
52
- else
53
- @controller = @request_items = nil
54
- end
55
-
56
- payload = message_text.merge(user_info).merge(channel_info)
25
+ httparty_options = options.except(
26
+ :avatar, :channel, :username, :git_url, :webhook_url,
27
+ :env, :accumulated_errors_count, :app_name
28
+ )
57
29
 
58
- @options[:body] = payload.to_json
59
- @options[:headers] ||= {}
60
- @options[:headers].merge!({ 'Content-Type' => 'application/json' })
30
+ httparty_options[:body] = payload.to_json
31
+ httparty_options[:headers] ||= {}
32
+ httparty_options[:headers]['Content-Type'] = 'application/json'
61
33
 
62
- @httparty.post(@webhook_url, @options)
34
+ HTTParty.post(options[:webhook_url], httparty_options)
63
35
  end
64
36
 
65
37
  private
66
38
 
67
- def channel_info
68
- if @channel
69
- { channel: @channel }
70
- else
71
- {}
72
- end
73
- end
39
+ attr_reader :formatter
74
40
 
75
- def user_info
76
- infos = {}
41
+ def message_text
42
+ text = [
43
+ '@channel',
44
+ "### #{formatter.title}",
45
+ formatter.subtitle,
46
+ "*#{@exception.message}*"
47
+ ]
77
48
 
78
- infos.merge!({ username: @username }) if @username
79
- infos.merge!({ icon_url: @avatar }) if @avatar
80
-
81
- infos
49
+ if (request = formatter.request_message.presence)
50
+ text << '### Request'
51
+ text << request
82
52
  end
83
53
 
84
- def message_text
85
- text = []
86
-
87
- text += ["@channel"]
88
- text += message_header
89
- text += message_request if @request_items
90
- text += message_backtrace if @backtrace
91
- text += message_issue_link if @gitlab_url
92
-
93
- { text: text.join("\n") }
54
+ if (backtrace = formatter.backtrace_message.presence)
55
+ text << '### Backtrace'
56
+ text << backtrace
94
57
  end
95
58
 
96
- def message_header
97
- text = []
98
-
99
- errors_count = @options[:accumulated_errors_count].to_i
100
- text << "### :warning: Error 500 in #{Rails.env} :warning:"
101
- text << "#{errors_count > 1 ? errors_count : 'An'} *#{@exception.class}* occured" + if @controller then " in *#{controller_and_method}*." else "." end
102
- text << "*#{@exception.message}*"
103
-
104
- text
59
+ if (exception_data = @env['exception_notifier.exception_data'])
60
+ text << '### Data'
61
+ data_string = exception_data.map { |k, v| "* #{k} : #{v}" }.join("\n")
62
+ text << "```\n#{data_string}\n```"
105
63
  end
106
64
 
107
- def message_request
108
- text = []
109
-
110
- text << "### Request"
111
- text << "```"
112
- text << hash_presentation(@request_items)
113
- text << "```"
65
+ text << message_issue_link if @gitlab_url
114
66
 
115
- text
116
- end
117
-
118
- def message_backtrace(size = 3)
119
- text = []
120
-
121
- size = @backtrace.size < size ? @backtrace.size : size
122
- text << "### Backtrace"
123
- text << "```"
124
- size.times { |i| text << "* " + @backtrace[i] }
125
- text << "```"
126
-
127
- text
128
- end
129
-
130
- def message_issue_link
131
- text = []
132
-
133
- link = [@gitlab_url, @application_name, "issues", "new"].join("/")
134
- params = {
135
- "issue[title]" => ["[BUG] Error 500 :",
136
- controller_and_method,
137
- "(#{@exception.class})",
138
- @exception.message].compact.join(" ")
139
- }.to_query
140
-
141
- text << "[Create an issue](#{link}/?#{params})"
142
-
143
- text
144
- end
145
-
146
- def controller_and_method
147
- if @controller
148
- "#{@controller.controller_name}##{@controller.action_name}"
149
- else
150
- ""
151
- end
152
- end
153
-
154
- def hash_presentation(hash)
155
- text = []
156
-
157
- hash.each do |key, value|
158
- text << "* #{key} : #{value}"
159
- end
67
+ text
68
+ end
160
69
 
161
- text.join("\n")
162
- end
70
+ def message_issue_link
71
+ link = [@gitlab_url, formatter.app_name, 'issues', 'new'].join('/')
72
+ params = {
73
+ 'issue[title]' => ['[BUG] Error 500 :',
74
+ formatter.controller_and_action || '',
75
+ "(#{@exception.class})",
76
+ @exception.message].compact.join(' ')
77
+ }.to_query
163
78
 
79
+ "[Create an issue](#{link}/?#{params})"
80
+ end
164
81
  end
165
82
  end
@@ -1,6 +1,7 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ExceptionNotifier
2
4
  module BacktraceCleaner
3
-
4
5
  def clean_backtrace(exception)
5
6
  if defined?(Rails) && Rails.respond_to?(:backtrace_cleaner)
6
7
  Rails.backtrace_cleaner.send(:filter, exception.backtrace)
@@ -8,6 +9,5 @@ module ExceptionNotifier
8
9
  exception.backtrace
9
10
  end
10
11
  end
11
-
12
12
  end
13
13
  end
@@ -1,3 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'active_support'
1
4
  require 'active_support/core_ext/numeric/time'
2
5
  require 'active_support/concern'
3
6
 
@@ -25,20 +28,21 @@ module ExceptionNotifier
25
28
  end
26
29
 
27
30
  def error_count(error_key)
28
- count = begin
29
- error_grouping_cache.read(error_key)
30
- rescue => e
31
- ExceptionNotifier.logger.warn("#{error_grouping_cache.inspect} failed to read, reason: #{e.message}. Falling back to memory cache store.")
32
- fallback_cache_store.read(error_key)
33
- end
31
+ count =
32
+ begin
33
+ error_grouping_cache.read(error_key)
34
+ rescue StandardError => e
35
+ log_cache_error(error_grouping_cache, e, :read)
36
+ fallback_cache_store.read(error_key)
37
+ end
34
38
 
35
- count.to_i if count
39
+ count&.to_i
36
40
  end
37
41
 
38
42
  def save_error_count(error_key, count)
39
43
  error_grouping_cache.write(error_key, count, expires_in: error_grouping_period)
40
- rescue => e
41
- ExceptionNotifier.logger.warn("#{error_grouping_cache.inspect} failed to write, reason: #{e.message}. Falling back to memory cache store.")
44
+ rescue StandardError => e
45
+ log_cache_error(error_grouping_cache, e, :write)
42
46
  fallback_cache_store.write(error_key, count, expires_in: error_grouping_period)
43
47
  end
44
48
 
@@ -46,13 +50,14 @@ module ExceptionNotifier
46
50
  message_based_key = "exception:#{Zlib.crc32("#{exception.class.name}\nmessage:#{exception.message}")}"
47
51
  accumulated_errors_count = 1
48
52
 
49
- if count = error_count(message_based_key)
53
+ if (count = error_count(message_based_key))
50
54
  accumulated_errors_count = count + 1
51
55
  save_error_count(message_based_key, accumulated_errors_count)
52
56
  else
53
- backtrace_based_key = "exception:#{Zlib.crc32("#{exception.class.name}\npath:#{exception.backtrace.try(:first)}")}"
57
+ backtrace_based_key =
58
+ "exception:#{Zlib.crc32("#{exception.class.name}\npath:#{exception.backtrace.try(:first)}")}"
54
59
 
55
- if count = error_grouping_cache.read(backtrace_based_key)
60
+ if (count = error_grouping_cache.read(backtrace_based_key))
56
61
  accumulated_errors_count = count + 1
57
62
  save_error_count(backtrace_based_key, accumulated_errors_count)
58
63
  else
@@ -72,6 +77,12 @@ module ExceptionNotifier
72
77
  factor.to_i == factor
73
78
  end
74
79
  end
80
+
81
+ private
82
+
83
+ def log_cache_error(cache, exception, action)
84
+ "#{cache.inspect} failed to #{action}, reason: #{exception.message}. Falling back to memory cache store."
85
+ end
75
86
  end
76
87
  end
77
- end
88
+ end