exception_handling 2.2.1 → 2.3.0.pre.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (34) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +1 -0
  3. data/.rubocop.yml +5 -0
  4. data/Gemfile +7 -6
  5. data/Gemfile.lock +26 -23
  6. data/README.md +0 -1
  7. data/Rakefile +4 -4
  8. data/config/exception_filters.yml +2 -3
  9. data/exception_handling.gemspec +12 -10
  10. data/lib/exception_handling/exception_catalog.rb +5 -4
  11. data/lib/exception_handling/exception_description.rb +28 -28
  12. data/lib/exception_handling/exception_info.rb +80 -72
  13. data/lib/exception_handling/honeybadger_callbacks.rb +41 -24
  14. data/lib/exception_handling/log_stub_error.rb +10 -8
  15. data/lib/exception_handling/mailer.rb +27 -48
  16. data/lib/exception_handling/methods.rb +15 -11
  17. data/lib/exception_handling/sensu.rb +7 -5
  18. data/lib/exception_handling/testing.rb +21 -19
  19. data/lib/exception_handling/version.rb +1 -1
  20. data/lib/exception_handling.rb +105 -200
  21. data/test/helpers/controller_helpers.rb +3 -1
  22. data/test/helpers/exception_helpers.rb +9 -0
  23. data/test/test_helper.rb +26 -21
  24. data/test/unit/exception_handling/exception_catalog_test.rb +15 -14
  25. data/test/unit/exception_handling/exception_description_test.rb +22 -31
  26. data/test/unit/exception_handling/exception_info_test.rb +76 -37
  27. data/test/unit/exception_handling/honeybadger_callbacks_test.rb +46 -9
  28. data/test/unit/exception_handling/log_error_stub_test.rb +6 -4
  29. data/test/unit/exception_handling/mailer_test.rb +8 -14
  30. data/test/unit/exception_handling/methods_test.rb +9 -6
  31. data/test/unit/exception_handling/sensu_test.rb +6 -4
  32. data/test/unit/exception_handling_test.rb +279 -364
  33. metadata +24 -24
  34. data/views/exception_handling/mailer/exception_notification.html.erb +0 -92
@@ -1,41 +1,58 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ExceptionHandling
2
4
  module HoneybadgerCallbacks
3
- def self.register_callbacks
4
- if ExceptionHandling.honeybadger?
5
- Honeybadger.local_variable_filter(&method(:local_variable_filter))
5
+ class << self
6
+ def register_callbacks
7
+ if ExceptionHandling.honeybadger_defined?
8
+ Honeybadger.local_variable_filter(&method(:local_variable_filter))
9
+ end
6
10
  end
7
- end
8
11
 
9
- private
12
+ private
10
13
 
11
- def self.local_variable_filter(symbol, object, filter_keys)
12
- case object
13
- # Honeybadger will filter these data types for us
14
- when String, Hash, Array, Set, Numeric, TrueClass, FalseClass, NilClass
15
- object
16
- else # handle other Ruby objects, intended for POROs
14
+ def inspect_object(object, filter_keys)
17
15
  inspection_output = object.inspect
16
+
18
17
  if contains_filter_key?(filter_keys, inspection_output)
19
18
  filtered_object(object)
20
19
  else
21
20
  inspection_output
22
21
  end
22
+ rescue => ex
23
+ details = if object.respond_to?(:to_pk)
24
+ " @pk=#{object.to_pk}"
25
+ elsif object.respond_to?(:id)
26
+ " @id=#{object.id}"
27
+ end
28
+
29
+ "#<#{object.class.name}#{details} [error '#{ex.class.name}: #{ex.message}' while calling #inspect]>"
23
30
  end
24
- end
25
31
 
26
- def self.contains_filter_key?(filter_keys, string)
27
- filter_keys._?.any? { |key| string.include?(key) }
28
- end
32
+ def local_variable_filter(_symbol, object, filter_keys)
33
+ case object
34
+ # Honeybadger will filter these data types for us
35
+ when String, Hash, Array, Set, Numeric, TrueClass, FalseClass, NilClass
36
+ object
37
+ else # handle other Ruby objects, intended for POROs
38
+ inspect_object(object, filter_keys)
39
+ end
40
+ end
41
+
42
+ def contains_filter_key?(filter_keys, string)
43
+ filter_keys._?.any? { |key| string.include?(key) }
44
+ end
29
45
 
30
- def self.filtered_object(object)
31
- # make the output look similar to inspect
32
- # use [FILTERED], just like honeybadger does
33
- if object.respond_to?(:to_pk)
34
- "#<#{object.class.name} @pk=#{object.to_pk}, [FILTERED]>"
35
- elsif object.respond_to?(:id)
36
- "#<#{object.class.name} @id=#{object.id}, [FILTERED]>"
37
- else
38
- "#<#{object.class.name} [FILTERED]>"
46
+ def filtered_object(object)
47
+ # make the output look similar to inspect
48
+ # use [FILTERED], just like honeybadger does
49
+ if object.respond_to?(:to_pk)
50
+ "#<#{object.class.name} @pk=#{object.to_pk}, [FILTERED]>"
51
+ elsif object.respond_to?(:id)
52
+ "#<#{object.class.name} @id=#{object.id}, [FILTERED]>"
53
+ else
54
+ "#<#{object.class.name} [FILTERED]>"
55
+ end
39
56
  end
40
57
  end
41
58
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  #
2
4
  # Used by functional tests to track exceptions.
3
5
  #
@@ -22,7 +24,7 @@ module LogErrorStub
22
24
  message = "log_error expected #{match[:expected]} times with pattern: '#{pattern.is_a?(Regexp) ? pattern.source : pattern}' found #{match[:found]}"
23
25
 
24
26
  if is_mini_test?
25
- flunk(message)
27
+ flunk(message)
26
28
  else
27
29
  add_failure(message)
28
30
  end
@@ -34,8 +36,9 @@ module LogErrorStub
34
36
 
35
37
  # for overriding when testing this module
36
38
  def is_mini_test?
37
- defined?(Minitest::Test) && self.is_a?(Minitest::Test)
39
+ defined?(Minitest::Test) && is_a?(Minitest::Test)
38
40
  end
41
+
39
42
  #
40
43
  # Call this function in your functional tests - usually first line after a "should" statement
41
44
  # once called, you can then call expects_exception
@@ -60,7 +63,7 @@ module LogErrorStub
60
63
  # Did the calling code call expects_exception on this exception?
61
64
  #
62
65
  def exception_filtered?(exception_data)
63
- @exception_whitelist && @exception_whitelist.any? do |expectation|
66
+ @exception_whitelist&.any? do |expectation|
64
67
  if expectation[0] === exception_data[:error]
65
68
  expectation[1][:found] += 1
66
69
  true
@@ -74,8 +77,8 @@ module LogErrorStub
74
77
  def expects_exception(pattern, options = {})
75
78
  @exception_whitelist ||= []
76
79
  expected_count = options[:count] || 1
77
- options = {:expected => expected_count, :found => 0}
78
- if to_increment = @exception_whitelist.find {|ex| ex[0] == pattern}
80
+ options = { expected: expected_count, found: 0 }
81
+ if to_increment = @exception_whitelist.find { |ex| ex[0] == pattern }
79
82
  to_increment[1][:expected] += expected_count
80
83
  else
81
84
  @exception_whitelist << [pattern, options]
@@ -90,10 +93,9 @@ module LogErrorStub
90
93
 
91
94
  def raise_unexpected_exception(exception_data)
92
95
  raise(UnexpectedExceptionLogged,
93
- exception_data[:error] + "\n" +
96
+ exception_data[:error] + "\n" \
94
97
  "---original backtrace---\n" +
95
- exception_data[:backtrace].join("\n") + "\n" +
98
+ exception_data[:backtrace].join("\n") + "\n" \
96
99
  "------")
97
100
  end
98
-
99
101
  end
@@ -1,10 +1,12 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'action_mailer'
2
4
 
3
5
  module ExceptionHandling
4
6
  class Mailer < ActionMailer::Base
5
- default :content_type => "text/html"
7
+ default content_type: "text/html"
6
8
 
7
- self.append_view_path "#{File.dirname(__FILE__)}/../../views"
9
+ append_view_path "#{File.dirname(__FILE__)}/../../views"
8
10
 
9
11
  [:email_environment, :server_name, :sender_address, :exception_recipients, :escalation_recipients].each do |method|
10
12
  define_method method do
@@ -16,76 +18,53 @@ module ExceptionHandling
16
18
  "#{email_environment} exception: "
17
19
  end
18
20
 
19
- def self.reloadable?() false end
20
-
21
- def exception_notification( cleaned_data, first_seen_at = nil, occurrences = 0 )
22
- if cleaned_data.is_a?(Hash)
23
- cleaned_data.merge!({:occurrences => occurrences, :first_seen_at => first_seen_at}) if first_seen_at
24
- cleaned_data.merge!({:server => server_name })
21
+ class << self
22
+ def reloadable?
23
+ false
25
24
  end
26
25
 
27
- subject = "#{email_prefix}#{"[#{occurrences} SUMMARIZED]" if first_seen_at}#{cleaned_data[:error]}"[0,300]
28
- recipients = exception_recipients
29
- from = sender_address
30
- @cleaned_data = cleaned_data
31
-
32
- mail(:from => from,
33
- :to => recipients,
34
- :subject => subject)
35
- end
36
-
37
- def escalation_notification( summary, data)
38
- subject = "#{email_environment} Escalation: #{summary}"
39
- from = sender_address.gsub('xception', 'scalation')
40
- recipients = escalation_recipients rescue exception_recipients
41
-
42
- @summary = summary
43
- @server = ExceptionHandling.server_name
44
- @cleaned_data = data
45
-
46
- mail(:from => from,
47
- :to => recipients,
48
- :subject => subject)
26
+ def mailer_method_category
27
+ {
28
+ log_parser_exception_notification: :NetworkOptout
29
+ }
30
+ end
49
31
  end
50
32
 
51
- def escalate_custom(summary, data, recipients)
33
+ def escalation_notification(summary, data, custom_recipients = nil)
52
34
  subject = "#{email_environment} Escalation: #{summary}"
53
35
  from = sender_address.gsub('xception', 'scalation')
54
- recipients = recipients
36
+ recipients = begin
37
+ custom_recipients || escalation_recipients
38
+ rescue
39
+ exception_recipients
40
+ end
55
41
 
56
42
  @summary = summary
57
43
  @server = ExceptionHandling.server_name
58
44
  @cleaned_data = data
59
45
 
60
- mail(:from => from,
61
- :to => recipients,
62
- :subject => subject)
46
+ mail(from: from,
47
+ to: recipients,
48
+ subject: subject)
63
49
  end
64
50
 
65
- def log_parser_exception_notification( cleaned_data, key )
51
+ def log_parser_exception_notification(cleaned_data, key)
66
52
  if cleaned_data.is_a?(Hash)
67
53
  cleaned_data = cleaned_data.symbolize_keys
68
54
  local_subject = cleaned_data[:error]
69
55
  else
70
56
  local_subject = "#{key}: #{cleaned_data}"
71
- cleaned_data = { :error => cleaned_data.to_s }
57
+ cleaned_data = { error: cleaned_data.to_s }
72
58
  end
73
59
 
74
- @subject = "#{email_prefix}#{local_subject}"[0,300]
60
+ @subject = "#{email_prefix}#{local_subject}"[0, 300]
75
61
  @recipients = exception_recipients
76
62
  from = sender_address
77
63
  @cleaned_data = cleaned_data
78
64
 
79
- mail(:from => from,
80
- :to => @recipients,
81
- :subject => @subject)
82
- end
83
-
84
- def self.mailer_method_category
85
- {
86
- :exception_notification => :NetworkOptout,
87
- :log_parser_exception_notification => :NetworkOptout
88
- }
65
+ mail(from: from,
66
+ to: @recipients,
67
+ subject: @subject)
89
68
  end
90
69
  end
91
70
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'active_support/concern'
2
4
 
3
5
  module ExceptionHandling
@@ -20,20 +22,18 @@ module ExceptionHandling
20
22
  end
21
23
 
22
24
  def log_info(message)
23
- ExceptionHandling.logger.info( message )
25
+ ExceptionHandling.logger.info(message)
24
26
  end
25
27
 
26
28
  def log_debug(message)
27
- ExceptionHandling.logger.debug( message )
29
+ ExceptionHandling.logger.debug(message)
28
30
  end
29
31
 
30
32
  def ensure_safe(exception_context = "")
31
- begin
32
- yield
33
- rescue => ex
34
- log_error ex, exception_context
35
- nil
36
- end
33
+ yield
34
+ rescue => ex
35
+ log_error ex, exception_context
36
+ nil
37
37
  end
38
38
 
39
39
  def escalate_error(exception_or_string, email_subject)
@@ -74,9 +74,13 @@ module ExceptionHandling
74
74
  time = Benchmark.measure do
75
75
  result = yield
76
76
  end
77
- if time.real > self.long_controller_action_timeout && !['development', 'test'].include?(ExceptionHandling.email_environment)
78
- name = " in #{controller_name}::#{action_name}" rescue " "
79
- log_error( "Long controller action detected#{name} %.4fs " % time.real )
77
+ if time.real > long_controller_action_timeout && !['development', 'test'].include?(ExceptionHandling.email_environment)
78
+ name = begin
79
+ " in #{controller_name}::#{action_name}"
80
+ rescue
81
+ " "
82
+ end
83
+ log_error("Long controller action detected#{name} %.4fs " % time.real)
80
84
  end
81
85
  result
82
86
  ensure
@@ -1,17 +1,19 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "socket"
2
4
 
3
5
  module ExceptionHandling
4
6
  module Sensu
5
7
  LEVELS = {
6
- warning: 1,
7
- critical: 2
8
- }
8
+ warning: 1,
9
+ critical: 2
10
+ }.freeze
9
11
 
10
12
  class << self
11
13
  def generate_event(name, message, level = :warning)
12
14
  status = LEVELS[level] or raise "Invalid alert level #{level}"
13
15
 
14
- event = {name: ExceptionHandling.sensu_prefix.to_s + name, output: message, status: status}
16
+ event = { name: ExceptionHandling.sensu_prefix.to_s + name, output: message, status: status }
15
17
 
16
18
  send_event(event)
17
19
  end
@@ -23,4 +25,4 @@ module ExceptionHandling
23
25
  end
24
26
  end
25
27
  end
26
- end
28
+ end
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
 
2
3
  # some useful test objects
3
4
 
@@ -7,38 +8,44 @@ module ExceptionHandling
7
8
 
8
9
  class Request
9
10
  attr_accessor :parameters, :protocol, :host, :request_uri, :env, :session_options
11
+
10
12
  def initialize
11
- @parameters = {:id => "1"}
13
+ @parameters = { id: "1" }
12
14
  @protocol = 'http'
13
15
  @host = 'localhost'
14
16
  @request_uri = "/fun/testing.html?foo=bar"
15
- @env = {:HOST => "local"}
16
- @session_options = { :id => '93951506217301' }
17
+ @env = { HOST: "local" }
18
+ @session_options = { id: '93951506217301' }
17
19
  end
18
20
  end
19
21
 
20
22
  attr_accessor :request, :session
23
+
21
24
  class << self
22
25
  attr_accessor :around_filter_method
26
+
27
+ def around_filter(method)
28
+ ControllerStub.around_filter_method = method
29
+ end
23
30
  end
24
31
 
25
32
  def initialize
26
33
  @request = Request.new
27
34
  @session_id = "ZKL95"
28
35
  @session =
29
- if defined?(Username)
30
- {
31
- :login_count => 22,
32
- :username_id => Username.first.id,
33
- :user_id => User.first.id,
34
- }
35
- else
36
- { }
37
- end
36
+ if defined?(Username)
37
+ {
38
+ login_count: 22,
39
+ username_id: Username.first.id,
40
+ user_id: User.first.id,
41
+ }
42
+ else
43
+ {}
44
+ end
38
45
  end
39
46
 
40
- def simulate_around_filter( &block )
41
- set_current_controller( &block )
47
+ def simulate_around_filter(&block)
48
+ set_current_controller(&block)
42
49
  end
43
50
 
44
51
  def controller_name
@@ -49,10 +56,6 @@ module ExceptionHandling
49
56
  "test_action"
50
57
  end
51
58
 
52
- def self.around_filter( method )
53
- ControllerStub.around_filter_method = method
54
- end
55
-
56
59
  def complete_request_uri
57
60
  "#{@request.protocol}#{@request.host}#{@request.request_uri}"
58
61
  end
@@ -60,6 +63,5 @@ module ExceptionHandling
60
63
  include ExceptionHandling::Methods
61
64
  set_long_controller_action_timeout 2
62
65
  end
63
-
64
66
  end
65
67
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ExceptionHandling
4
- VERSION = '2.2.1'
4
+ VERSION = '2.3.0.pre.1'
5
5
  end