exception_handling 2.17.0.pre.tstarck.1 → 3.0.pre.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/.gitignore +0 -3
- data/.ruby-version +1 -1
- data/Gemfile +16 -12
- data/Gemfile.lock +138 -153
- data/README.md +21 -90
- data/Rakefile +11 -8
- data/exception_handling.gemspec +10 -14
- data/lib/exception_handling/exception_info.rb +11 -15
- data/lib/exception_handling/honeybadger_callbacks.rb +59 -0
- data/lib/exception_handling/log_stub_error.rb +1 -2
- data/lib/exception_handling/methods.rb +53 -6
- data/lib/exception_handling/testing.rb +10 -20
- data/lib/exception_handling/version.rb +1 -1
- data/lib/exception_handling.rb +34 -135
- data/semaphore_ci/setup.sh +3 -0
- data/{spec → test}/helpers/exception_helpers.rb +2 -2
- data/{spec/spec_helper.rb → test/test_helper.rb} +45 -75
- data/test/unit/exception_handling/exception_catalog_test.rb +85 -0
- data/test/unit/exception_handling/exception_description_test.rb +82 -0
- data/{spec/unit/exception_handling/exception_info_spec.rb → test/unit/exception_handling/exception_info_test.rb} +114 -170
- data/test/unit/exception_handling/honeybadger_callbacks_test.rb +122 -0
- data/{spec/unit/exception_handling/log_error_stub_spec.rb → test/unit/exception_handling/log_error_stub_test.rb} +22 -38
- data/{spec/unit/exception_handling/mailer_spec.rb → test/unit/exception_handling/mailer_test.rb} +18 -17
- data/test/unit/exception_handling/methods_test.rb +84 -0
- data/test/unit/exception_handling/sensu_test.rb +52 -0
- data/test/unit/exception_handling_test.rb +1109 -0
- metadata +59 -99
- data/.github/CODEOWNERS +0 -1
- data/.github/workflows/pipeline.yml +0 -36
- data/.rspec +0 -3
- data/.tool-versions +0 -1
- data/Appraisals +0 -19
- data/CHANGELOG.md +0 -149
- data/gemfiles/rails_5.gemfile +0 -18
- data/gemfiles/rails_6.gemfile +0 -18
- data/gemfiles/rails_7.gemfile +0 -18
- data/lib/exception_handling/escalate_callback.rb +0 -19
- data/lib/exception_handling/logging_methods.rb +0 -27
- data/spec/rake_test_warning_false.rb +0 -20
- data/spec/unit/exception_handling/escalate_callback_spec.rb +0 -81
- data/spec/unit/exception_handling/exception_catalog_spec.rb +0 -85
- data/spec/unit/exception_handling/exception_description_spec.rb +0 -82
- data/spec/unit/exception_handling/logging_methods_spec.rb +0 -38
- data/spec/unit/exception_handling/methods_spec.rb +0 -105
- data/spec/unit/exception_handling/sensu_spec.rb +0 -51
- data/spec/unit/exception_handling_spec.rb +0 -1465
- /data/{spec → test}/helpers/controller_helpers.rb +0 -0
@@ -3,7 +3,7 @@
|
|
3
3
|
module ExceptionHandling
|
4
4
|
class ExceptionInfo
|
5
5
|
|
6
|
-
|
6
|
+
ENVIRONMENT_WHITELIST = [
|
7
7
|
/^HTTP_/,
|
8
8
|
/^QUERY_/,
|
9
9
|
/^REQUEST_/,
|
@@ -46,20 +46,16 @@ module ExceptionHandling
|
|
46
46
|
EOS
|
47
47
|
|
48
48
|
SECTIONS = [:request, :session, :environment, :backtrace, :event_response].freeze
|
49
|
-
HONEYBADGER_CONTEXT_SECTIONS = [:timestamp, :error_class, :exception_context, :server, :scm_revision, :notes,
|
50
|
-
:user_details, :request, :session, :environment, :backtrace, :event_response, :log_context].freeze
|
49
|
+
HONEYBADGER_CONTEXT_SECTIONS = [:timestamp, :error_class, :exception_context, :server, :scm_revision, :notes, :user_details, :request, :session, :environment, :backtrace, :event_response].freeze
|
51
50
|
|
52
|
-
attr_reader :exception, :controller, :exception_context, :timestamp
|
51
|
+
attr_reader :exception, :controller, :exception_context, :timestamp
|
53
52
|
|
54
|
-
def initialize(exception, exception_context, timestamp, controller
|
53
|
+
def initialize(exception, exception_context, timestamp, controller = nil, data_callback = nil)
|
55
54
|
@exception = exception
|
56
55
|
@exception_context = exception_context
|
57
56
|
@timestamp = timestamp
|
58
57
|
@controller = controller || controller_from_context(exception_context)
|
59
58
|
@data_callback = data_callback
|
60
|
-
# merge into the surrounding context just like ContextualLogger does when logging
|
61
|
-
@merged_log_context = ExceptionHandling.logger.current_context_for_thread.deep_merge(log_context || {})
|
62
|
-
@honeybadger_tags = Array(@merged_log_context[:honeybadger_tags] || [])
|
63
59
|
end
|
64
60
|
|
65
61
|
def data
|
@@ -83,10 +79,9 @@ module ExceptionHandling
|
|
83
79
|
end
|
84
80
|
|
85
81
|
def controller_name
|
86
|
-
@controller_name ||=
|
87
|
-
|
88
|
-
|
89
|
-
).to_s
|
82
|
+
@controller_name ||= if @controller
|
83
|
+
@controller.request.parameters.with_indifferent_access[:controller]
|
84
|
+
end.to_s
|
90
85
|
end
|
91
86
|
|
92
87
|
private
|
@@ -181,7 +176,7 @@ module ExceptionHandling
|
|
181
176
|
|
182
177
|
def clean_environment(env)
|
183
178
|
Hash[ env.map do |k, v|
|
184
|
-
[k, v] if !"#{k}: #{v}".in?(ENVIRONMENT_OMIT) &&
|
179
|
+
[k, v] if !"#{k}: #{v}".in?(ENVIRONMENT_OMIT) && ENVIRONMENT_WHITELIST.any? { |regex| k =~ regex }
|
185
180
|
end.compact ]
|
186
181
|
end
|
187
182
|
|
@@ -272,13 +267,14 @@ module ExceptionHandling
|
|
272
267
|
data = enhanced_data.dup
|
273
268
|
data[:server] = ExceptionHandling.server_name
|
274
269
|
data[:exception_context] = deep_clean_hash(@exception_context) if @exception_context.present?
|
275
|
-
data[:log_context] = @merged_log_context
|
276
270
|
unstringify_sections(data)
|
277
|
-
HONEYBADGER_CONTEXT_SECTIONS.
|
271
|
+
context_data = HONEYBADGER_CONTEXT_SECTIONS.reduce({}) do |context, section|
|
278
272
|
if data[section].present?
|
279
273
|
context[section] = data[section]
|
280
274
|
end
|
275
|
+
context
|
281
276
|
end
|
277
|
+
context_data
|
282
278
|
end
|
283
279
|
end
|
284
280
|
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ExceptionHandling
|
4
|
+
module HoneybadgerCallbacks
|
5
|
+
class << self
|
6
|
+
def register_callbacks
|
7
|
+
if ExceptionHandling.honeybadger_defined?
|
8
|
+
Honeybadger.local_variable_filter(&method(:local_variable_filter))
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def inspect_object(object, filter_keys)
|
15
|
+
inspection_output = object.inspect
|
16
|
+
|
17
|
+
if contains_filter_key?(filter_keys, inspection_output)
|
18
|
+
filtered_object(object)
|
19
|
+
else
|
20
|
+
inspection_output
|
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]>"
|
30
|
+
end
|
31
|
+
|
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
|
45
|
+
|
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
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -1,15 +1,65 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'active_support/concern'
|
4
|
-
require_relative 'logging_methods'
|
5
4
|
|
6
5
|
module ExceptionHandling
|
7
6
|
module Methods # included on models and controllers
|
8
7
|
extend ActiveSupport::Concern
|
9
|
-
include ExceptionHandling::LoggingMethods
|
10
8
|
|
11
9
|
protected
|
12
10
|
|
11
|
+
def log_error(exception_or_string, exception_context = '')
|
12
|
+
controller = self if respond_to?(:request) && respond_to?(:session)
|
13
|
+
ExceptionHandling.log_error(exception_or_string, exception_context, controller)
|
14
|
+
end
|
15
|
+
|
16
|
+
def log_error_rack(exception_or_string, exception_context = '', rack_filter = '')
|
17
|
+
ExceptionHandling.log_error_rack(exception_or_string, exception_context, rack_filter)
|
18
|
+
end
|
19
|
+
|
20
|
+
def log_warning(message)
|
21
|
+
ExceptionHandling.log_warning(message)
|
22
|
+
end
|
23
|
+
|
24
|
+
def log_info(message)
|
25
|
+
ExceptionHandling.logger.info(message)
|
26
|
+
end
|
27
|
+
|
28
|
+
def log_debug(message)
|
29
|
+
ExceptionHandling.logger.debug(message)
|
30
|
+
end
|
31
|
+
|
32
|
+
def ensure_safe(exception_context = "")
|
33
|
+
yield
|
34
|
+
rescue => ex
|
35
|
+
log_error ex, exception_context
|
36
|
+
nil
|
37
|
+
end
|
38
|
+
|
39
|
+
def escalate_error(exception_or_string, email_subject)
|
40
|
+
ExceptionHandling.escalate_error(exception_or_string, email_subject)
|
41
|
+
end
|
42
|
+
|
43
|
+
def escalate_warning(message, email_subject)
|
44
|
+
ExceptionHandling.escalate_warning(message, email_subject)
|
45
|
+
end
|
46
|
+
|
47
|
+
def ensure_escalation(*args)
|
48
|
+
ExceptionHandling.ensure_escalation(*args) do
|
49
|
+
yield
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def alert_warning(*args)
|
54
|
+
ExceptionHandling.alert_warning(*args)
|
55
|
+
end
|
56
|
+
|
57
|
+
def ensure_alert(*args)
|
58
|
+
ExceptionHandling.ensure_alert(*args) do
|
59
|
+
yield
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
13
63
|
def long_controller_action_timeout
|
14
64
|
if defined?(Rails) && Rails.respond_to?(:env) && Rails.env == 'test'
|
15
65
|
300
|
@@ -38,10 +88,7 @@ module ExceptionHandling
|
|
38
88
|
end
|
39
89
|
|
40
90
|
included do
|
41
|
-
|
42
|
-
if respond_to? :around_filter
|
43
|
-
around_filter :set_current_controller
|
44
|
-
end
|
91
|
+
around_filter :set_current_controller if respond_to? :around_filter
|
45
92
|
end
|
46
93
|
|
47
94
|
class_methods do
|
@@ -4,7 +4,7 @@
|
|
4
4
|
|
5
5
|
module ExceptionHandling
|
6
6
|
module Testing
|
7
|
-
class
|
7
|
+
class ControllerStub
|
8
8
|
|
9
9
|
class Request
|
10
10
|
attr_accessor :parameters, :protocol, :host, :request_uri, :env, :session_options
|
@@ -25,7 +25,7 @@ module ExceptionHandling
|
|
25
25
|
attr_accessor :around_filter_method
|
26
26
|
|
27
27
|
def around_filter(method)
|
28
|
-
|
28
|
+
ControllerStub.around_filter_method = method
|
29
29
|
end
|
30
30
|
end
|
31
31
|
|
@@ -44,6 +44,14 @@ module ExceptionHandling
|
|
44
44
|
end
|
45
45
|
end
|
46
46
|
|
47
|
+
def simulate_around_filter(&block)
|
48
|
+
set_current_controller(&block)
|
49
|
+
end
|
50
|
+
|
51
|
+
def controller_name
|
52
|
+
"ControllerStub"
|
53
|
+
end
|
54
|
+
|
47
55
|
def action_name
|
48
56
|
"test_action"
|
49
57
|
end
|
@@ -51,27 +59,9 @@ module ExceptionHandling
|
|
51
59
|
def complete_request_uri
|
52
60
|
"#{@request.protocol}#{@request.host}#{@request.request_uri}"
|
53
61
|
end
|
54
|
-
end
|
55
|
-
|
56
|
-
class LoggingMethodsControllerStub < ControllerStubBase
|
57
|
-
include ExceptionHandling::LoggingMethods
|
58
|
-
|
59
|
-
def controller_name
|
60
|
-
"LoggingMethodsControllerStub"
|
61
|
-
end
|
62
|
-
end
|
63
62
|
|
64
|
-
class MethodsControllerStub < ControllerStubBase
|
65
63
|
include ExceptionHandling::Methods
|
66
64
|
set_long_controller_action_timeout 2
|
67
|
-
|
68
|
-
def simulate_around_filter(&block)
|
69
|
-
set_current_controller(&block)
|
70
|
-
end
|
71
|
-
|
72
|
-
def controller_name
|
73
|
-
"MethodsControllerStub"
|
74
|
-
end
|
75
65
|
end
|
76
66
|
end
|
77
67
|
end
|
data/lib/exception_handling.rb
CHANGED
@@ -1,21 +1,20 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'digest'
|
4
3
|
require 'timeout'
|
5
4
|
require 'active_support'
|
6
|
-
require 'active_support/core_ext'
|
5
|
+
require 'active_support/core_ext/hash'
|
7
6
|
require 'contextual_logger'
|
8
7
|
|
9
8
|
require 'invoca/utils'
|
10
9
|
|
11
|
-
require
|
12
|
-
require
|
13
|
-
require
|
14
|
-
require
|
15
|
-
require
|
16
|
-
require
|
17
|
-
require
|
18
|
-
require
|
10
|
+
require "exception_handling/mailer"
|
11
|
+
require "exception_handling/sensu"
|
12
|
+
require "exception_handling/methods"
|
13
|
+
require "exception_handling/log_stub_error"
|
14
|
+
require "exception_handling/exception_description"
|
15
|
+
require "exception_handling/exception_catalog"
|
16
|
+
require "exception_handling/exception_info"
|
17
|
+
require "exception_handling/honeybadger_callbacks.rb"
|
19
18
|
|
20
19
|
_ = ActiveSupport::HashWithIndifferentAccess
|
21
20
|
|
@@ -30,8 +29,6 @@ module ExceptionHandling # never included
|
|
30
29
|
AUTHENTICATION_HEADERS = ['HTTP_AUTHORIZATION', 'X-HTTP_AUTHORIZATION', 'X_HTTP_AUTHORIZATION', 'REDIRECT_X_HTTP_AUTHORIZATION'].freeze
|
31
30
|
HONEYBADGER_STATUSES = [:success, :failure, :skipped].freeze
|
32
31
|
|
33
|
-
Deprecation3_0 = ActiveSupport::Deprecation.new('3.0', 'exception_handling')
|
34
|
-
|
35
32
|
class << self
|
36
33
|
|
37
34
|
#
|
@@ -53,28 +50,15 @@ module ExceptionHandling # never included
|
|
53
50
|
@exception_recipients or raise ArgumentError, "You must assign a value to #{name}.exception_recipients"
|
54
51
|
end
|
55
52
|
|
56
|
-
def configured?
|
57
|
-
!@logger.nil?
|
58
|
-
end
|
59
|
-
|
60
53
|
def logger
|
61
54
|
@logger or raise ArgumentError, "You must assign a value to #{name}.logger"
|
62
55
|
end
|
63
56
|
|
64
57
|
def logger=(logger)
|
65
|
-
@logger =
|
66
|
-
logger
|
67
|
-
else
|
68
|
-
Deprecation3_0.deprecation_warning('implicit extend with ContextualLogger::LoggerMixin', 'extend your logger instance or include into your logger class first')
|
69
|
-
logger.extend(ContextualLogger::LoggerMixin)
|
70
|
-
end
|
71
|
-
EscalateCallback.register_if_configured!
|
58
|
+
@logger = logger.is_a?(ContextualLogger) ? logger : ContextualLogger.new(logger)
|
72
59
|
end
|
73
60
|
|
74
|
-
def default_metric_name(exception_data, exception, treat_like_warning
|
75
|
-
include_prefix and Deprecation3_0.deprecation_warning("the 'expection_handling.' prefix in ExceptionHandling::default_metric_name",
|
76
|
-
"do not rely on metric names including the 'exception_handling.' prefix.")
|
77
|
-
|
61
|
+
def default_metric_name(exception_data, exception, treat_like_warning)
|
78
62
|
metric_name = if exception_data['metric_name']
|
79
63
|
exception_data['metric_name']
|
80
64
|
elsif exception.is_a?(ExceptionHandling::Warning)
|
@@ -86,7 +70,7 @@ module ExceptionHandling # never included
|
|
86
70
|
"exception"
|
87
71
|
end
|
88
72
|
|
89
|
-
"
|
73
|
+
"exception_handling.#{metric_name}"
|
90
74
|
end
|
91
75
|
|
92
76
|
def default_honeybadger_metric_name(honeybadger_status)
|
@@ -110,12 +94,10 @@ module ExceptionHandling # never included
|
|
110
94
|
attr_accessor :sensu_host
|
111
95
|
attr_accessor :sensu_port
|
112
96
|
attr_accessor :sensu_prefix
|
113
|
-
attr_reader :honeybadger_log_context_tags
|
114
97
|
|
115
98
|
attr_reader :filter_list_filename
|
116
99
|
attr_reader :eventmachine_safe
|
117
100
|
attr_reader :eventmachine_synchrony
|
118
|
-
attr_reader :honeybadger_auto_tagger
|
119
101
|
|
120
102
|
@filter_list_filename = "./config/exception_filters.yml"
|
121
103
|
@email_environment = ""
|
@@ -156,30 +138,6 @@ module ExceptionHandling # never included
|
|
156
138
|
@exception_catalog ||= ExceptionCatalog.new(@filter_list_filename)
|
157
139
|
end
|
158
140
|
|
159
|
-
# rubocop:disable Style/TrivialAccessors
|
160
|
-
# @param value [Proc|nil] Proc that accepts 1 parameter that will be the exception object or nil to disable the auto-tagger.
|
161
|
-
# The proc is always expected to return an array of strings. The array can be empty.
|
162
|
-
def honeybadger_auto_tagger=(value)
|
163
|
-
@honeybadger_auto_tagger = value
|
164
|
-
end
|
165
|
-
# rubocop:enable Style/TrivialAccessors
|
166
|
-
|
167
|
-
# @param tag_name [String]
|
168
|
-
# @param path [Array]
|
169
|
-
def add_honeybadger_tag_from_log_context(tag_name, path:)
|
170
|
-
tag_name.is_a?(String) or raise ArgumentError, "tag_name must be a String, #{tag_name.inspect}"
|
171
|
-
path.is_a?(Array) or raise ArgumentError, "path must be an Array, #{path.inspect}"
|
172
|
-
@honeybadger_log_context_tags ||= {}
|
173
|
-
if @honeybadger_log_context_tags.key?(tag_name)
|
174
|
-
log_warning("Overwriting existing tag path for '#{tag_name}' from #{@honeybadger_log_context_tags[tag_name]} to #{path}")
|
175
|
-
end
|
176
|
-
@honeybadger_log_context_tags[tag_name] = path
|
177
|
-
end
|
178
|
-
|
179
|
-
def clear_honeybadger_tags_from_log_context
|
180
|
-
@honeybadger_log_context_tags = nil
|
181
|
-
end
|
182
|
-
|
183
141
|
#
|
184
142
|
# internal settings (don't set directly)
|
185
143
|
#
|
@@ -219,18 +177,13 @@ module ExceptionHandling # never included
|
|
219
177
|
# Called directly by our code, usually from rescue blocks.
|
220
178
|
# Writes to log file and may send to honeybadger
|
221
179
|
#
|
222
|
-
# TODO: the **log_context means we can never have context named treat_like_warning. In general, keyword args will be conflated with log_context.
|
223
|
-
# Ideally we'd separate to log_context from the other keywords so they don't interfere in any way. Or have no keyword args.
|
224
|
-
#
|
225
180
|
# Functional Test Operation:
|
226
181
|
# Calls into handle_stub_log_error and returns. no log file. no honeybadger
|
227
182
|
#
|
228
|
-
def log_error(exception_or_string, exception_context = '',
|
183
|
+
def log_error(exception_or_string, exception_context = '', treat_like_warning: false, **log_context, &data_callback)
|
229
184
|
ex = make_exception(exception_or_string)
|
230
185
|
timestamp = set_log_error_timestamp
|
231
|
-
exception_info = ExceptionInfo.new(ex, exception_context, timestamp,
|
232
|
-
controller: controller || current_controller, data_callback: data_callback,
|
233
|
-
log_context: log_context)
|
186
|
+
exception_info = ExceptionInfo.new(ex, exception_context, timestamp, current_controller, data_callback)
|
234
187
|
|
235
188
|
if stub_handler
|
236
189
|
stub_handler.handle_stub_log_error(exception_info.data)
|
@@ -257,13 +210,7 @@ module ExceptionHandling # never included
|
|
257
210
|
#
|
258
211
|
def write_exception_to_log(ex, exception_context, timestamp, log_context = {})
|
259
212
|
ActiveSupport::Deprecation.silence do
|
260
|
-
|
261
|
-
|
262
|
-
if ex.is_a?(Warning)
|
263
|
-
ExceptionHandling.logger.warn("\nExceptionHandlingWarning (Warning:#{timestamp}) #{log_message}", **log_context)
|
264
|
-
else
|
265
|
-
ExceptionHandling.logger.fatal("\nExceptionHandlingError (Error:#{timestamp}) #{log_message}", **log_context)
|
266
|
-
end
|
213
|
+
ExceptionHandling.logger.fatal("\nExceptionHandlingError (Error:#{timestamp}) #{ex.class} #{exception_context} (#{encode_utf8(ex.message.to_s)}):\n " + clean_backtrace(ex).join("\n ") + "\n\n", log_context)
|
267
214
|
end
|
268
215
|
end
|
269
216
|
|
@@ -296,16 +243,11 @@ module ExceptionHandling # never included
|
|
296
243
|
def send_exception_to_honeybadger(exception_info)
|
297
244
|
exception = exception_info.exception
|
298
245
|
exception_description = exception_info.exception_description
|
299
|
-
|
300
|
-
# Note: Both commas and spaces are treated as delimiters for the :tags string. Space-delimiters are not officially documented.
|
301
|
-
# https://github.com/honeybadger-io/honeybadger-ruby/pull/422
|
302
|
-
tags = tags_for_honeybadger(exception_info).join(' ')
|
303
246
|
response = Honeybadger.notify(error_class: exception_description ? exception_description.filter_name : exception.class.name,
|
304
247
|
error_message: exception.message.to_s,
|
305
248
|
exception: exception,
|
306
249
|
context: exception_info.honeybadger_context_data,
|
307
|
-
controller: exception_info.controller_name
|
308
|
-
tags: tags)
|
250
|
+
controller: exception_info.controller_name)
|
309
251
|
response ? :success : :failure
|
310
252
|
rescue Exception => ex
|
311
253
|
warn("ExceptionHandling.send_exception_to_honeybadger rescued exception while logging #{exception_info.exception_context}:\n#{exception.class}: #{exception.message}:\n#{ex.class}: #{ex.message}\n#{ex.backtrace.join("\n")}")
|
@@ -323,41 +265,38 @@ module ExceptionHandling # never included
|
|
323
265
|
#
|
324
266
|
# Expects passed in hash to only include keys which be directly set on the Honeybadger config
|
325
267
|
#
|
326
|
-
def enable_honeybadger(
|
268
|
+
def enable_honeybadger(config = {})
|
327
269
|
Bundler.require(:honeybadger)
|
270
|
+
HoneybadgerCallbacks.register_callbacks
|
328
271
|
Honeybadger.configure do |config_klass|
|
329
272
|
config.each do |k, v|
|
330
|
-
|
331
|
-
config_klass.send(k, v)
|
332
|
-
else
|
333
|
-
config_klass.send(:"#{k}=", v)
|
334
|
-
end
|
273
|
+
config_klass.send(:"#{k}=", v)
|
335
274
|
end
|
336
275
|
end
|
337
276
|
end
|
338
277
|
|
339
|
-
def log_warning(message,
|
278
|
+
def log_warning(message, log_context = {})
|
340
279
|
warning = Warning.new(message)
|
341
280
|
warning.set_backtrace([])
|
342
281
|
log_error(warning, **log_context)
|
343
282
|
end
|
344
283
|
|
345
|
-
def log_info(message,
|
346
|
-
ExceptionHandling.logger.info(message,
|
284
|
+
def log_info(message, log_context = {})
|
285
|
+
ExceptionHandling.logger.info(message, log_context)
|
347
286
|
end
|
348
287
|
|
349
|
-
def log_debug(message,
|
350
|
-
ExceptionHandling.logger.debug(message,
|
288
|
+
def log_debug(message, log_context = {})
|
289
|
+
ExceptionHandling.logger.debug(message, log_context)
|
351
290
|
end
|
352
291
|
|
353
|
-
def ensure_safe(exception_context = "",
|
292
|
+
def ensure_safe(exception_context = "", log_context = {})
|
354
293
|
yield
|
355
294
|
rescue => ex
|
356
295
|
log_error(ex, exception_context, **log_context)
|
357
296
|
nil
|
358
297
|
end
|
359
298
|
|
360
|
-
def ensure_completely_safe(exception_context = "",
|
299
|
+
def ensure_completely_safe(exception_context = "", log_context = {})
|
361
300
|
yield
|
362
301
|
rescue SystemExit, SystemStackError, NoMemoryError, SecurityError, SignalException
|
363
302
|
raise
|
@@ -372,29 +311,26 @@ module ExceptionHandling # never included
|
|
372
311
|
escalate(email_subject, ex, last_exception_timestamp, production_support_recipients)
|
373
312
|
end
|
374
313
|
|
375
|
-
def escalate_error(exception_or_string, email_subject, custom_recipients = nil,
|
314
|
+
def escalate_error(exception_or_string, email_subject, custom_recipients = nil, log_context = {})
|
376
315
|
ex = make_exception(exception_or_string)
|
377
316
|
log_error(ex, **log_context)
|
378
317
|
escalate(email_subject, ex, last_exception_timestamp, custom_recipients)
|
379
318
|
end
|
380
319
|
|
381
|
-
def escalate_warning(message, email_subject, custom_recipients = nil,
|
320
|
+
def escalate_warning(message, email_subject, custom_recipients = nil, log_context = {})
|
382
321
|
ex = Warning.new(message)
|
383
322
|
log_error(ex, **log_context)
|
384
323
|
escalate(email_subject, ex, last_exception_timestamp, custom_recipients)
|
385
324
|
end
|
386
325
|
|
387
|
-
def ensure_escalation(email_subject, custom_recipients = nil,
|
326
|
+
def ensure_escalation(email_subject, custom_recipients = nil, log_context = {})
|
388
327
|
yield
|
389
328
|
rescue => ex
|
390
|
-
escalate_error(ex, email_subject, custom_recipients,
|
329
|
+
escalate_error(ex, email_subject, custom_recipients, log_context)
|
391
330
|
nil
|
392
331
|
end
|
393
332
|
|
394
|
-
|
395
|
-
deprecator: ActiveSupport::Deprecation.new('3.0', 'ExceptionHandling')
|
396
|
-
|
397
|
-
def alert_warning(exception_or_string, alert_name, exception_context, **log_context)
|
333
|
+
def alert_warning(exception_or_string, alert_name, exception_context, log_context)
|
398
334
|
ex = make_exception(exception_or_string)
|
399
335
|
log_error(ex, exception_context, **log_context)
|
400
336
|
begin
|
@@ -404,10 +340,10 @@ module ExceptionHandling # never included
|
|
404
340
|
end
|
405
341
|
end
|
406
342
|
|
407
|
-
def ensure_alert(alert_name, exception_context,
|
343
|
+
def ensure_alert(alert_name, exception_context, log_context = {})
|
408
344
|
yield
|
409
345
|
rescue => ex
|
410
|
-
alert_warning(ex, alert_name, exception_context,
|
346
|
+
alert_warning(ex, alert_name, exception_context, log_context)
|
411
347
|
nil
|
412
348
|
end
|
413
349
|
|
@@ -424,7 +360,7 @@ module ExceptionHandling # never included
|
|
424
360
|
result
|
425
361
|
end
|
426
362
|
|
427
|
-
def log_periodically(exception_key, interval, message,
|
363
|
+
def log_periodically(exception_key, interval, message, log_context = {})
|
428
364
|
self.periodic_exception_intervals ||= {}
|
429
365
|
last_logged = self.periodic_exception_intervals[exception_key]
|
430
366
|
if !last_logged || ((last_logged + interval) < Time.now)
|
@@ -461,41 +397,6 @@ module ExceptionHandling # never included
|
|
461
397
|
|
462
398
|
private
|
463
399
|
|
464
|
-
# @param exception_info [ExceptionInfo]
|
465
|
-
#
|
466
|
-
# @return [Array<String>]
|
467
|
-
def tags_for_honeybadger(exception_info)
|
468
|
-
(
|
469
|
-
honeybadger_auto_tags(exception_info.exception) +
|
470
|
-
exception_info.honeybadger_tags +
|
471
|
-
honeybadger_tags_from_log_context(exception_info.honeybadger_context_data)
|
472
|
-
).uniq
|
473
|
-
end
|
474
|
-
|
475
|
-
# @param exception [Exception]
|
476
|
-
#
|
477
|
-
# @return [Array<String>]
|
478
|
-
def honeybadger_auto_tags(exception)
|
479
|
-
@honeybadger_auto_tagger&.call(exception) || []
|
480
|
-
rescue => ex
|
481
|
-
traces = ex.backtrace.join("\n")
|
482
|
-
message = "Unable to execute honeybadger_auto_tags callback. #{ExceptionHandling.encode_utf8(ex.message.to_s)} #{traces}\n"
|
483
|
-
ExceptionHandling.log_info(message)
|
484
|
-
[]
|
485
|
-
end
|
486
|
-
|
487
|
-
def honeybadger_tags_from_log_context(honeybadger_context_data)
|
488
|
-
if @honeybadger_log_context_tags
|
489
|
-
@honeybadger_log_context_tags.map do |tag_name, tag_path|
|
490
|
-
if (value_from_log_context = honeybadger_context_data.dig(:log_context, *tag_path))
|
491
|
-
"#{tag_name}:#{value_from_log_context}"
|
492
|
-
end
|
493
|
-
end.compact
|
494
|
-
else
|
495
|
-
[]
|
496
|
-
end
|
497
|
-
end
|
498
|
-
|
499
400
|
def execute_custom_log_error_callback(exception_data, exception, treat_like_warning, external_notification_results)
|
500
401
|
if ExceptionHandling.post_log_error_hook
|
501
402
|
honeybadger_status = external_notification_results[:honeybadger_status] || :skipped
|
@@ -562,6 +463,4 @@ module ExceptionHandling # never included
|
|
562
463
|
end
|
563
464
|
end
|
564
465
|
end
|
565
|
-
|
566
|
-
EscalateCallback.register_if_configured!
|
567
466
|
end
|
@@ -7,7 +7,7 @@ module ExceptionHelpers
|
|
7
7
|
|
8
8
|
def exception_with_nil_message
|
9
9
|
exception_with_nil_message = RuntimeError.new(nil)
|
10
|
-
|
10
|
+
stub(exception_with_nil_message).message { nil }
|
11
11
|
exception_with_nil_message
|
12
12
|
end
|
13
13
|
|
@@ -15,6 +15,6 @@ module ExceptionHelpers
|
|
15
15
|
|
16
16
|
def capture_notifications
|
17
17
|
@sent_notifications = []
|
18
|
-
|
18
|
+
stub(ExceptionHandling).send_exception_to_honeybadger(anything) { |exception_info| @sent_notifications << exception_info }
|
19
19
|
end
|
20
20
|
end
|