exception_handling 2.4.4.pre.1 → 2.5.1.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 +4 -4
- data/CHANGELOG.md +16 -1
- data/Gemfile.lock +2 -2
- data/Rakefile +2 -0
- data/lib/exception_handling.rb +7 -5
- data/lib/exception_handling/exception_info.rb +9 -4
- data/lib/exception_handling/version.rb +1 -1
- data/test/rake_test_warning_false.rb +20 -0
- data/test/test_helper.rb +7 -3
- data/test/unit/exception_handling/exception_info_test.rb +15 -15
- data/test/unit/exception_handling/honeybadger_callbacks_test.rb +1 -1
- data/test/unit/exception_handling_test.rb +160 -65
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5c3561b45435bb79e5ee48f090362ea006a0d522ab5b61809af57a56951d5aff
|
4
|
+
data.tar.gz: b711a085d3a0049dd5dfbf6e454cb4e948f5f20b2a5d561d6b05a40f0d5c33d8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a98fa1af28748a12facbe69b35d56641204db4f43d700970115a476b6689f591e9cc9cd5301a6d8709751f386642f51dd07657efb27f85de1e6ad61173a0e08d
|
7
|
+
data.tar.gz: 143f2f54b21e73299b2486ddff7532e4142fa01e5e92544f1cf4c07d8fd2f5d6de53cacace2089816ae81ccad850e820569e8a60efebb3196e7524e3dd8f26bd
|
data/CHANGELOG.md
CHANGED
@@ -4,10 +4,23 @@ Inspired by [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
|
4
4
|
|
5
5
|
Note: this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
6
6
|
|
7
|
-
## [2.
|
7
|
+
## [2.5.1] - Unreleased
|
8
8
|
### Changed
|
9
9
|
- Calling `log_warning` will now log with Severity::WARNING rather than FATAL.
|
10
10
|
|
11
|
+
## [2.5.0] - 2020-08-19
|
12
|
+
### Added
|
13
|
+
- The `**log_context` passed to `log_error`/`log_warning`/`log_info` is now
|
14
|
+
passed into `Honeybadger.notify()`, in `context: { log_context: ... }`.
|
15
|
+
|
16
|
+
### Fixed
|
17
|
+
- Silenced test warning noise by no longer running ruby -w.
|
18
|
+
- Renamed a constant to ALLOWLIST.
|
19
|
+
|
20
|
+
## [2.4.4] - 2020-08-10
|
21
|
+
### Fixed
|
22
|
+
- `ExceptionHandling.logger = nil` no longer displays an "implicit extend" deprecation warning.
|
23
|
+
|
11
24
|
## [2.4.3] - 2020-05-14
|
12
25
|
### Deprecated
|
13
26
|
- In `ExceptionHandling.logger=`, implicit `logger.extend ContextualLogger::LoggerMixin` is now deprecated.
|
@@ -28,6 +41,8 @@ Note: this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0
|
|
28
41
|
### Changed
|
29
42
|
- No longer depends on hobo_support. Uses invoca-utils 0.3 instead.
|
30
43
|
|
44
|
+
[2.5.1]: https://github.com/Invoca/exception_handling/compare/v2.5.0...v2.5.1
|
45
|
+
[2.5.0]: https://github.com/Invoca/exception_handling/compare/v2.4.4...v2.5.0
|
31
46
|
[2.4.4]: https://github.com/Invoca/exception_handling/compare/v2.4.3...v2.4.4
|
32
47
|
[2.4.3]: https://github.com/Invoca/exception_handling/compare/v2.4.2...v2.4.3
|
33
48
|
[2.4.2]: https://github.com/Invoca/exception_handling/compare/v2.4.1...v2.4.2
|
data/Gemfile.lock
CHANGED
@@ -8,7 +8,7 @@ GIT
|
|
8
8
|
PATH
|
9
9
|
remote: .
|
10
10
|
specs:
|
11
|
-
exception_handling (2.
|
11
|
+
exception_handling (2.5.1.pre.1)
|
12
12
|
actionmailer (>= 4.2, < 7.0)
|
13
13
|
actionpack (>= 4.2, < 7.0)
|
14
14
|
activesupport (>= 4.2, < 7.0)
|
@@ -55,7 +55,7 @@ GEM
|
|
55
55
|
builder (3.2.3)
|
56
56
|
coderay (1.1.2)
|
57
57
|
concurrent-ruby (1.1.5)
|
58
|
-
contextual_logger (0.9.
|
58
|
+
contextual_logger (0.9.1)
|
59
59
|
activesupport
|
60
60
|
json
|
61
61
|
crass (1.0.6)
|
data/Rakefile
CHANGED
data/lib/exception_handling.rb
CHANGED
@@ -57,7 +57,7 @@ module ExceptionHandling # never included
|
|
57
57
|
Deprecation3_0 = ActiveSupport::Deprecation.new('3.0', 'exception_handling')
|
58
58
|
|
59
59
|
def logger=(logger)
|
60
|
-
@logger = if logger.is_a?(ContextualLogger::LoggerMixin)
|
60
|
+
@logger = if logger.nil? || logger.is_a?(ContextualLogger::LoggerMixin)
|
61
61
|
logger
|
62
62
|
else
|
63
63
|
Deprecation3_0.deprecation_warning('implicit extend with ContextualLogger::LoggerMixin', 'extend your logger instance or include into your logger class first')
|
@@ -193,7 +193,9 @@ module ExceptionHandling # never included
|
|
193
193
|
def log_error(exception_or_string, exception_context = '', controller = nil, treat_like_warning: false, **log_context, &data_callback)
|
194
194
|
ex = make_exception(exception_or_string)
|
195
195
|
timestamp = set_log_error_timestamp
|
196
|
-
exception_info = ExceptionInfo.new(ex, exception_context, timestamp,
|
196
|
+
exception_info = ExceptionInfo.new(ex, exception_context, timestamp,
|
197
|
+
controller: controller || current_controller, data_callback: data_callback,
|
198
|
+
log_context: log_context)
|
197
199
|
|
198
200
|
if stub_handler
|
199
201
|
stub_handler.handle_stub_log_error(exception_info.data)
|
@@ -220,12 +222,12 @@ module ExceptionHandling # never included
|
|
220
222
|
#
|
221
223
|
def write_exception_to_log(ex, exception_context, timestamp, log_context = {})
|
222
224
|
ActiveSupport::Deprecation.silence do
|
223
|
-
log_message = "
|
225
|
+
log_message = "#{exception_context}\n#{ex.class}: (#{encode_utf8(ex.message.to_s)}):\n " + clean_backtrace(ex).join("\n ") + "\n\n"
|
224
226
|
|
225
227
|
if ex.is_a?(Warning)
|
226
|
-
ExceptionHandling.logger.warn(log_message, log_context)
|
228
|
+
ExceptionHandling.logger.warn("\nExceptionHandlingWarning (Warning:#{timestamp}) #{log_message}", log_context)
|
227
229
|
else
|
228
|
-
ExceptionHandling.logger.fatal(log_message, log_context)
|
230
|
+
ExceptionHandling.logger.fatal("\nExceptionHandlingError (Error:#{timestamp}) #{log_message}", log_context)
|
229
231
|
end
|
230
232
|
end
|
231
233
|
end
|
@@ -3,7 +3,7 @@
|
|
3
3
|
module ExceptionHandling
|
4
4
|
class ExceptionInfo
|
5
5
|
|
6
|
-
|
6
|
+
ENVIRONMENT_ALLOWLIST = [
|
7
7
|
/^HTTP_/,
|
8
8
|
/^QUERY_/,
|
9
9
|
/^REQUEST_/,
|
@@ -46,16 +46,20 @@ 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,
|
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
|
50
51
|
|
51
52
|
attr_reader :exception, :controller, :exception_context, :timestamp
|
52
53
|
|
53
|
-
def initialize(exception, exception_context, timestamp, controller
|
54
|
+
def initialize(exception, exception_context, timestamp, controller: nil, data_callback: nil, log_context: nil)
|
54
55
|
@exception = exception
|
55
56
|
@exception_context = exception_context
|
56
57
|
@timestamp = timestamp
|
57
58
|
@controller = controller || controller_from_context(exception_context)
|
58
59
|
@data_callback = data_callback
|
60
|
+
@merged_log_context = if log_context # merge into the surrounding context just like ContextualLogger does when logging
|
61
|
+
ExceptionHandling.logger.current_context_for_thread.deep_merge(log_context)
|
62
|
+
end
|
59
63
|
end
|
60
64
|
|
61
65
|
def data
|
@@ -176,7 +180,7 @@ module ExceptionHandling
|
|
176
180
|
|
177
181
|
def clean_environment(env)
|
178
182
|
Hash[ env.map do |k, v|
|
179
|
-
[k, v] if !"#{k}: #{v}".in?(ENVIRONMENT_OMIT) &&
|
183
|
+
[k, v] if !"#{k}: #{v}".in?(ENVIRONMENT_OMIT) && ENVIRONMENT_ALLOWLIST.any? { |regex| k =~ regex }
|
180
184
|
end.compact ]
|
181
185
|
end
|
182
186
|
|
@@ -267,6 +271,7 @@ module ExceptionHandling
|
|
267
271
|
data = enhanced_data.dup
|
268
272
|
data[:server] = ExceptionHandling.server_name
|
269
273
|
data[:exception_context] = deep_clean_hash(@exception_context) if @exception_context.present?
|
274
|
+
data[:log_context] = @merged_log_context
|
270
275
|
unstringify_sections(data)
|
271
276
|
context_data = HONEYBADGER_CONTEXT_SECTIONS.reduce({}) do |context, section|
|
272
277
|
if data[section].present?
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Rake 11+ has a misfeature where @warning = true by default
|
4
|
+
# See https://github.com/ruby/rake/pull/97/files
|
5
|
+
# This causes all tests to be run with `ruby -w`, causing a huge number of warnings
|
6
|
+
# from gems we don't control and overwhelming our test output.
|
7
|
+
# This patch reverts that.
|
8
|
+
|
9
|
+
_ = Rake::TestTask
|
10
|
+
|
11
|
+
class Rake::TestTask
|
12
|
+
module SetWarningFalseMixin
|
13
|
+
def initialize(*args)
|
14
|
+
super
|
15
|
+
self.warning = false
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
prepend SetWarningFalseMixin
|
20
|
+
end
|
data/test/test_helper.rb
CHANGED
@@ -33,16 +33,20 @@ class LoggerStub
|
|
33
33
|
clear
|
34
34
|
end
|
35
35
|
|
36
|
+
def debug(message, log_context = {})
|
37
|
+
logged << { message: message, context: log_context, severity: 'DEBUG' }
|
38
|
+
end
|
39
|
+
|
36
40
|
def info(message, log_context = {})
|
37
|
-
logged << { message: message, context: log_context }
|
41
|
+
logged << { message: message, context: log_context, severity: 'INFO' }
|
38
42
|
end
|
39
43
|
|
40
44
|
def warn(message, log_context = {})
|
41
|
-
logged << { message: message, context: log_context }
|
45
|
+
logged << { message: message, context: log_context, severity: 'WARN' }
|
42
46
|
end
|
43
47
|
|
44
48
|
def fatal(message, log_context = {})
|
45
|
-
logged << { message: message, context: log_context }
|
49
|
+
logged << { message: message, context: log_context, severity: 'FATAL' }
|
46
50
|
end
|
47
51
|
|
48
52
|
def clear
|
@@ -29,7 +29,7 @@ module ExceptionHandling
|
|
29
29
|
exception_context = {
|
30
30
|
"action_controller.instance" => Object.new
|
31
31
|
}
|
32
|
-
exception_info = ExceptionInfo.new(@exception, exception_context, @timestamp, @controller)
|
32
|
+
exception_info = ExceptionInfo.new(@exception, exception_context, @timestamp, controller: @controller)
|
33
33
|
assert_equal @controller, exception_info.controller
|
34
34
|
assert_not_equal exception_context["action_controller.instance"], exception_info.controller
|
35
35
|
end
|
@@ -107,7 +107,7 @@ module ExceptionHandling
|
|
107
107
|
request_uri = "host/path"
|
108
108
|
controller = create_dummy_controller(env, parameters, session, request_uri)
|
109
109
|
data_callback = ->(data) { data[:custom_section] = "value" }
|
110
|
-
exception_info = ExceptionInfo.new(@exception, "custom context data", @timestamp, controller, data_callback)
|
110
|
+
exception_info = ExceptionInfo.new(@exception, "custom context data", @timestamp, controller: controller, data_callback: data_callback)
|
111
111
|
|
112
112
|
dont_allow(exception_info).extract_and_merge_controller_data
|
113
113
|
dont_allow(exception_info).customize_from_data_callback
|
@@ -177,7 +177,7 @@ module ExceptionHandling
|
|
177
177
|
end
|
178
178
|
|
179
179
|
should "include controller data when available" do
|
180
|
-
exception_info = ExceptionInfo.new(@exception, @exception_context, @timestamp, @controller)
|
180
|
+
exception_info = ExceptionInfo.new(@exception, @exception_context, @timestamp, controller: @controller)
|
181
181
|
expected_data = {
|
182
182
|
"error_class" => "StandardError",
|
183
183
|
"error_string" => "StandardError: something went wrong",
|
@@ -220,7 +220,7 @@ module ExceptionHandling
|
|
220
220
|
end
|
221
221
|
|
222
222
|
should "add to_s attribute to specific sections that have their content in hash format" do
|
223
|
-
exception_info = ExceptionInfo.new(@exception, @exception_context, @timestamp, @controller)
|
223
|
+
exception_info = ExceptionInfo.new(@exception, @exception_context, @timestamp, controller: @controller)
|
224
224
|
expected_data = {
|
225
225
|
"error_class" => "StandardError",
|
226
226
|
"error_string" => "StandardError: something went wrong",
|
@@ -251,7 +251,7 @@ module ExceptionHandling
|
|
251
251
|
should "filter out sensitive parameters like passwords" do
|
252
252
|
@controller.request.parameters[:password] = "super_secret"
|
253
253
|
@controller.request.parameters[:user] = { "password" => "also super secret", "password_confirmation" => "also super secret" }
|
254
|
-
exception_info = ExceptionInfo.new(@exception, @exception_context, @timestamp, @controller)
|
254
|
+
exception_info = ExceptionInfo.new(@exception, @exception_context, @timestamp, controller: @controller)
|
255
255
|
expected_params = {
|
256
256
|
"password" => "[FILTERED]",
|
257
257
|
"advertiser_id" => 435, "controller" => "dummy",
|
@@ -265,7 +265,7 @@ module ExceptionHandling
|
|
265
265
|
end
|
266
266
|
|
267
267
|
should "include the changes from the custom data callback" do
|
268
|
-
exception_info = ExceptionInfo.new(@exception, @exception_context, @timestamp, nil, @data_callback)
|
268
|
+
exception_info = ExceptionInfo.new(@exception, @exception_context, @timestamp, controller: nil, data_callback: @data_callback)
|
269
269
|
expected_data = {
|
270
270
|
"error_class" => "StandardError",
|
271
271
|
"error_string" => "StandardError: something went wrong",
|
@@ -331,7 +331,7 @@ module ExceptionHandling
|
|
331
331
|
request_uri = "host/path"
|
332
332
|
controller = create_dummy_controller(env, parameters, session, request_uri)
|
333
333
|
exception = StandardError.new("Request to click domain rejected")
|
334
|
-
exception_info = ExceptionInfo.new(exception,
|
334
|
+
exception_info = ExceptionInfo.new(exception, nil, Time.now, controller: controller)
|
335
335
|
assert_equal true, exception_info.enhanced_data[:request].is_a?(Hash)
|
336
336
|
description = exception_info.exception_description
|
337
337
|
assert_not_nil description
|
@@ -340,11 +340,11 @@ module ExceptionHandling
|
|
340
340
|
|
341
341
|
should "return same description object for related errors (avoid reloading exception catalog from disk)" do
|
342
342
|
exception = StandardError.new("No route matches")
|
343
|
-
exception_info = ExceptionInfo.new(exception,
|
343
|
+
exception_info = ExceptionInfo.new(exception, nil, Time.now)
|
344
344
|
description = exception_info.exception_description
|
345
345
|
|
346
346
|
repeat_ex = StandardError.new("No route matches 2")
|
347
|
-
repeat_ex_info = ExceptionInfo.new(repeat_ex,
|
347
|
+
repeat_ex_info = ExceptionInfo.new(repeat_ex, nil, Time.now)
|
348
348
|
assert_equal description.object_id, repeat_ex_info.exception_description.object_id
|
349
349
|
end
|
350
350
|
end
|
@@ -368,7 +368,7 @@ module ExceptionHandling
|
|
368
368
|
session = { username: 'smith' }
|
369
369
|
request_uri = "host/path"
|
370
370
|
controller = create_dummy_controller(env, parameters, session, request_uri)
|
371
|
-
exception_info = ExceptionInfo.new(@exception, @exception_context, @timestamp, controller)
|
371
|
+
exception_info = ExceptionInfo.new(@exception, @exception_context, @timestamp, controller: controller)
|
372
372
|
|
373
373
|
assert_equal 'some_controller', exception_info.controller_name
|
374
374
|
end
|
@@ -384,7 +384,7 @@ module ExceptionHandling
|
|
384
384
|
should "be enabled when Honeybadger is defined and exception is not in the filter list" do
|
385
385
|
stub(ExceptionHandling).honeybadger_defined? { true }
|
386
386
|
exception = StandardError.new("something went wrong")
|
387
|
-
exception_info = ExceptionInfo.new(exception,
|
387
|
+
exception_info = ExceptionInfo.new(exception, nil, Time.now)
|
388
388
|
assert_nil exception_info.exception_description
|
389
389
|
assert_equal true, exception_info.send_to_honeybadger?
|
390
390
|
end
|
@@ -392,7 +392,7 @@ module ExceptionHandling
|
|
392
392
|
should "be enabled when Honeybadger is defined and exception is on the filter list with the flag turned on" do
|
393
393
|
stub(ExceptionHandling).honeybadger_defined? { true }
|
394
394
|
exception = StandardError.new("No route matches")
|
395
|
-
exception_info = ExceptionInfo.new(exception,
|
395
|
+
exception_info = ExceptionInfo.new(exception, nil, Time.now)
|
396
396
|
assert_not_nil exception_info.exception_description
|
397
397
|
assert_equal true, exception_info.exception_description.send_to_honeybadger
|
398
398
|
assert_equal true, exception_info.send_to_honeybadger?
|
@@ -401,7 +401,7 @@ module ExceptionHandling
|
|
401
401
|
should "be disabled when Honeybadger is defined and exception is on the filter list with the flag turned off" do
|
402
402
|
stub(ExceptionHandling).honeybadger_defined? { true }
|
403
403
|
exception = StandardError.new("No route matches")
|
404
|
-
exception_info = ExceptionInfo.new(exception,
|
404
|
+
exception_info = ExceptionInfo.new(exception, nil, Time.now)
|
405
405
|
assert_not_nil exception_info.exception_description
|
406
406
|
stub(exception_info.exception_description).send_to_honeybadger { false }
|
407
407
|
assert_equal false, exception_info.send_to_honeybadger?
|
@@ -410,7 +410,7 @@ module ExceptionHandling
|
|
410
410
|
should "be disabled when Honeybadger is not defined" do
|
411
411
|
stub(ExceptionHandling).honeybadger_defined? { false }
|
412
412
|
exception = StandardError.new("something went wrong")
|
413
|
-
exception_info = ExceptionInfo.new(exception,
|
413
|
+
exception_info = ExceptionInfo.new(exception, nil, Time.now)
|
414
414
|
assert_nil exception_info.exception_description
|
415
415
|
assert_equal false, exception_info.send_to_honeybadger?
|
416
416
|
end
|
@@ -438,7 +438,7 @@ module ExceptionHandling
|
|
438
438
|
data[:other_section] = "This should not be included in the response"
|
439
439
|
end
|
440
440
|
timestamp = Time.now
|
441
|
-
exception_info = ExceptionInfo.new(exception, exception_context, timestamp, controller, data_callback)
|
441
|
+
exception_info = ExceptionInfo.new(exception, exception_context, timestamp, controller: controller, data_callback: data_callback)
|
442
442
|
|
443
443
|
expected_data = {
|
444
444
|
timestamp: timestamp,
|
@@ -95,7 +95,7 @@ module ExceptionHandling
|
|
95
95
|
assert_equal "#<ExceptionHandling::HoneybadgerCallbacksTest::TestRaiseOnInspectWithId @id=123 [error 'RuntimeError: some error' while calling #inspect]>", result
|
96
96
|
end
|
97
97
|
|
98
|
-
should "handle exceptions for objects responding to
|
98
|
+
should "handle exceptions for objects responding to to_pk" do
|
99
99
|
result = HoneybadgerCallbacks.send(:local_variable_filter, :variable_name, TestRaiseOnInspectWithToPk.new, ['password'])
|
100
100
|
assert_equal "#<ExceptionHandling::HoneybadgerCallbacksTest::TestRaiseOnInspectWithToPk @pk=SomeRecord-123 [error 'RuntimeError: some error' while calling #inspect]>", result
|
101
101
|
end
|
@@ -126,6 +126,11 @@ class ExceptionHandlingTest < ActiveSupport::TestCase
|
|
126
126
|
assert_equal ancestors, ExceptionHandling.logger.singleton_class.ancestors.*.name
|
127
127
|
end
|
128
128
|
|
129
|
+
should "allow logger = nil (no deprecation warning)" do
|
130
|
+
mock(STDERR).puts(/DEPRECATION WARNING/).never
|
131
|
+
ExceptionHandling.logger = nil
|
132
|
+
end
|
133
|
+
|
129
134
|
should "[deprecated] mix in ContextualLogger::Mixin if not there" do
|
130
135
|
mock(STDERR).puts(/DEPRECATION WARNING: implicit extend with ContextualLogger::LoggerMixin is deprecated and will be removed from exception_handling 3\.0/)
|
131
136
|
logger = Logger.new('/dev/null')
|
@@ -144,6 +149,11 @@ class ExceptionHandlingTest < ActiveSupport::TestCase
|
|
144
149
|
assert_not_empty logged_excluding_reload_filter.last[:context]
|
145
150
|
assert_equal logged_excluding_reload_filter.last[:context], service_name: 'exception_handling'
|
146
151
|
end
|
152
|
+
|
153
|
+
should "log with Severity::FATAL" do
|
154
|
+
ExceptionHandling.log_error('This is a Warning', service_name: 'exception_handling')
|
155
|
+
assert_equal logged_excluding_reload_filter.last[:severity], 'FATAL'
|
156
|
+
end
|
147
157
|
end
|
148
158
|
|
149
159
|
context "#log_warning" do
|
@@ -160,24 +170,53 @@ class ExceptionHandlingTest < ActiveSupport::TestCase
|
|
160
170
|
assert_not_empty logged_excluding_reload_filter.last[:context]
|
161
171
|
assert_equal logged_excluding_reload_filter.last[:context], service_name: 'exception_handling'
|
162
172
|
end
|
173
|
+
|
174
|
+
should "log with Severity::WARN" do
|
175
|
+
ExceptionHandling.log_warning('This is a Warning', service_name: 'exception_handling')
|
176
|
+
assert_equal logged_excluding_reload_filter.last[:severity], 'WARN'
|
177
|
+
end
|
163
178
|
end
|
164
179
|
|
165
180
|
context "#log_info" do
|
166
181
|
should "take in additional key word args as logging context and pass them to the logger" do
|
167
|
-
ExceptionHandling.
|
182
|
+
ExceptionHandling.log_info('This is an Info', service_name: 'exception_handling')
|
168
183
|
assert_match(/This is an Info/, logged_excluding_reload_filter.last[:message])
|
169
184
|
assert_not_empty logged_excluding_reload_filter.last[:context]
|
170
185
|
assert_equal logged_excluding_reload_filter.last[:context], service_name: 'exception_handling'
|
171
186
|
end
|
187
|
+
|
188
|
+
should "log with Severity::INFO" do
|
189
|
+
ExceptionHandling.log_info('This is a Warning', service_name: 'exception_handling')
|
190
|
+
assert_equal logged_excluding_reload_filter.last[:severity], 'INFO'
|
191
|
+
end
|
172
192
|
end
|
173
193
|
|
174
194
|
context "#log_debug" do
|
175
195
|
should "take in additional key word args as logging context and pass them to the logger" do
|
176
|
-
ExceptionHandling.
|
196
|
+
ExceptionHandling.log_debug('This is a Debug', service_name: 'exception_handling')
|
177
197
|
assert_match(/This is a Debug/, logged_excluding_reload_filter.last[:message])
|
178
198
|
assert_not_empty logged_excluding_reload_filter.last[:context]
|
179
199
|
assert_equal logged_excluding_reload_filter.last[:context], service_name: 'exception_handling'
|
180
200
|
end
|
201
|
+
|
202
|
+
should "log with Severity::DEBUG" do
|
203
|
+
ExceptionHandling.log_debug('This is a Warning', service_name: 'exception_handling')
|
204
|
+
assert_equal logged_excluding_reload_filter.last[:severity], 'DEBUG'
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
context "#write_exception_to_log" do
|
209
|
+
should "log warnings with Severity::WARN" do
|
210
|
+
warning = ExceptionHandling::Warning.new('This is a Warning')
|
211
|
+
ExceptionHandling.write_exception_to_log(warning, '', Time.now.to_i, service_name: 'exception_handling')
|
212
|
+
assert_equal logged_excluding_reload_filter.last[:severity], 'WARN'
|
213
|
+
end
|
214
|
+
|
215
|
+
should "log everything else with Severity::FATAL" do
|
216
|
+
error = RuntimeError.new('This is a runtime error')
|
217
|
+
ExceptionHandling.write_exception_to_log(error, '', Time.now.to_i, service_name: 'exception_handling')
|
218
|
+
assert_equal logged_excluding_reload_filter.last[:severity], 'FATAL'
|
219
|
+
end
|
181
220
|
end
|
182
221
|
|
183
222
|
context "configuration with custom_data_hook or post_log_error_hook" do
|
@@ -334,7 +373,7 @@ class ExceptionHandlingTest < ActiveSupport::TestCase
|
|
334
373
|
|
335
374
|
if ActionView::VERSION::MAJOR >= 5
|
336
375
|
should "log an exception with call stack if an ActionView template exception is raised." do
|
337
|
-
mock(ExceptionHandling.logger).fatal(/\(Error:\d+\)
|
376
|
+
mock(ExceptionHandling.logger).fatal(/\(Error:\d+\) \nActionView::Template::Error: \(blah\):\n /, anything)
|
338
377
|
ExceptionHandling.ensure_safe do
|
339
378
|
begin
|
340
379
|
# Rails 5 made the switch from ActionView::TemplateError taking in the original exception
|
@@ -347,7 +386,7 @@ class ExceptionHandlingTest < ActiveSupport::TestCase
|
|
347
386
|
end
|
348
387
|
else
|
349
388
|
should "log an exception with call stack if an ActionView template exception is raised." do
|
350
|
-
mock(ExceptionHandling.logger).fatal(/\(Error:\d+\)
|
389
|
+
mock(ExceptionHandling.logger).fatal(/\(Error:\d+\) \nActionView::Template::Error: \(blah\):\n /, anything)
|
351
390
|
ExceptionHandling.ensure_safe { raise ActionView::TemplateError.new({}, ArgumentError.new("blah")) }
|
352
391
|
end
|
353
392
|
end
|
@@ -370,7 +409,7 @@ class ExceptionHandlingTest < ActiveSupport::TestCase
|
|
370
409
|
end
|
371
410
|
|
372
411
|
should "allow a message to be appended to the error when logged." do
|
373
|
-
mock(ExceptionHandling.logger).fatal(/mooo \(blah\):\n.*exception_handling_test\.rb/, anything)
|
412
|
+
mock(ExceptionHandling.logger).fatal(/mooo\nArgumentError: \(blah\):\n.*exception_handling_test\.rb/, anything)
|
374
413
|
b = ExceptionHandling.ensure_safe("mooo") { raise ArgumentError, "blah" }
|
375
414
|
assert_nil b
|
376
415
|
end
|
@@ -378,7 +417,7 @@ class ExceptionHandlingTest < ActiveSupport::TestCase
|
|
378
417
|
should "only rescue StandardError and descendents" do
|
379
418
|
assert_raise(Exception) { ExceptionHandling.ensure_safe("mooo") { raise Exception } }
|
380
419
|
|
381
|
-
mock(ExceptionHandling.logger).fatal(/mooo \(blah\):\n.*exception_handling_test\.rb/, anything)
|
420
|
+
mock(ExceptionHandling.logger).fatal(/mooo\nStandardError: \(blah\):\n.*exception_handling_test\.rb/, anything)
|
382
421
|
|
383
422
|
b = ExceptionHandling.ensure_safe("mooo") { raise StandardError, "blah" }
|
384
423
|
assert_nil b
|
@@ -409,7 +448,7 @@ class ExceptionHandlingTest < ActiveSupport::TestCase
|
|
409
448
|
end
|
410
449
|
|
411
450
|
should "allow a message to be appended to the error when logged." do
|
412
|
-
mock(ExceptionHandling.logger).fatal(/mooo \(blah\):\n.*exception_handling_test\.rb/, anything)
|
451
|
+
mock(ExceptionHandling.logger).fatal(/mooo\nArgumentError: \(blah\):\n.*exception_handling_test\.rb/, anything)
|
413
452
|
b = ExceptionHandling.ensure_completely_safe("mooo") { raise ArgumentError, "blah" }
|
414
453
|
assert_nil b
|
415
454
|
end
|
@@ -466,7 +505,7 @@ class ExceptionHandlingTest < ActiveSupport::TestCase
|
|
466
505
|
ExceptionHandling.ensure_escalation("ensure context") { raise ArgumentError, "first_test_exception" }
|
467
506
|
|
468
507
|
assert_match(/ArgumentError.*first_test_exception/, log_fatals[0].first)
|
469
|
-
assert_match(/safe_email_deliver.*Delivery Error
|
508
|
+
assert_match(/safe_email_deliver.*Delivery Error/m, log_fatals[1].first)
|
470
509
|
|
471
510
|
assert_equal 2, log_fatals.size, log_fatals.inspect
|
472
511
|
|
@@ -536,7 +575,7 @@ class ExceptionHandlingTest < ActiveSupport::TestCase
|
|
536
575
|
should "include the timestamp when the exception is logged" do
|
537
576
|
capture_notifications
|
538
577
|
|
539
|
-
mock(ExceptionHandling.logger).fatal(/\(Error:517033020\)
|
578
|
+
mock(ExceptionHandling.logger).fatal(/\(Error:517033020\) context\nArgumentError: \(blah\):\n.*exception_handling_test\.rb/, anything)
|
540
579
|
b = ExceptionHandling.ensure_safe("context") { raise ArgumentError, "blah" }
|
541
580
|
assert_nil b
|
542
581
|
|
@@ -616,66 +655,122 @@ class ExceptionHandlingTest < ActiveSupport::TestCase
|
|
616
655
|
ExceptionHandling.log_error(exception_with_nil_message)
|
617
656
|
end
|
618
657
|
|
619
|
-
|
620
|
-
|
621
|
-
|
622
|
-
|
623
|
-
|
624
|
-
|
625
|
-
|
626
|
-
|
627
|
-
|
628
|
-
|
629
|
-
|
630
|
-
|
631
|
-
|
632
|
-
|
633
|
-
|
634
|
-
|
635
|
-
honeybadger_data = nil
|
636
|
-
mock(Honeybadger).notify.with_any_args do |data|
|
637
|
-
honeybadger_data = data
|
658
|
+
context "with stubbed values" do
|
659
|
+
setup do
|
660
|
+
Time.now_override = Time.now
|
661
|
+
@env = { server: "fe98" }
|
662
|
+
@parameters = { advertiser_id: 435, controller: "some_controller" }
|
663
|
+
@session = { username: "jsmith" }
|
664
|
+
@request_uri = "host/path"
|
665
|
+
@controller = create_dummy_controller(@env, @parameters, @session, @request_uri)
|
666
|
+
stub(ExceptionHandling).server_name { "invoca_fe98" }
|
667
|
+
|
668
|
+
@exception = StandardError.new("Some Exception")
|
669
|
+
@exception.set_backtrace([
|
670
|
+
"test/unit/exception_handling_test.rb:847:in `exception_1'",
|
671
|
+
"test/unit/exception_handling_test.rb:455:in `block (4 levels) in <class:ExceptionHandlingTest>'"
|
672
|
+
])
|
673
|
+
@exception_context = { "SERVER_NAME" => "exceptional.com" }
|
638
674
|
end
|
639
|
-
|
640
|
-
|
641
|
-
|
642
|
-
|
643
|
-
|
675
|
+
|
676
|
+
should "send error details and relevant context data to Honeybadger with log_context" do
|
677
|
+
honeybadger_data = nil
|
678
|
+
mock(Honeybadger).notify.with_any_args do |data|
|
679
|
+
honeybadger_data = data
|
680
|
+
end
|
681
|
+
ExceptionHandling.logger.global_context = { service_name: "rails", region: "AWS-us-east-1" }
|
682
|
+
log_context = { log_source: "gem/listen", service_name: "bin/console" }
|
683
|
+
ExceptionHandling.log_error(@exception, @exception_context, @controller, **log_context) do |data|
|
684
|
+
data[:scm_revision] = "5b24eac37aaa91f5784901e9aabcead36fd9df82"
|
685
|
+
data[:user_details] = { username: "jsmith" }
|
686
|
+
data[:event_response] = "Event successfully received"
|
687
|
+
data[:other_section] = "This should not be included in the response"
|
688
|
+
end
|
689
|
+
|
690
|
+
expected_data = {
|
691
|
+
error_class: :"Test Exception",
|
692
|
+
error_message: "Some Exception",
|
693
|
+
controller: "some_controller",
|
694
|
+
exception: @exception,
|
695
|
+
context: {
|
696
|
+
timestamp: Time.now.to_i,
|
697
|
+
error_class: "StandardError",
|
698
|
+
server: "invoca_fe98",
|
699
|
+
exception_context: { "SERVER_NAME" => "exceptional.com" },
|
700
|
+
scm_revision: "5b24eac37aaa91f5784901e9aabcead36fd9df82",
|
701
|
+
notes: "this is used by a test",
|
702
|
+
user_details: { "username" => "jsmith" },
|
703
|
+
request: {
|
704
|
+
"params" => { "advertiser_id" => 435, "controller" => "some_controller" },
|
705
|
+
"rails_root" => "Rails.root not defined. Is this a test environment?",
|
706
|
+
"url" => "host/path"
|
707
|
+
},
|
708
|
+
session: {
|
709
|
+
"key" => nil,
|
710
|
+
"data" => { "username" => "jsmith" }
|
711
|
+
},
|
712
|
+
environment: {
|
713
|
+
"SERVER_NAME" => "exceptional.com"
|
714
|
+
},
|
715
|
+
backtrace: [
|
716
|
+
"test/unit/exception_handling_test.rb:847:in `exception_1'",
|
717
|
+
"test/unit/exception_handling_test.rb:455:in `block (4 levels) in <class:ExceptionHandlingTest>'"
|
718
|
+
],
|
719
|
+
event_response: "Event successfully received",
|
720
|
+
log_context: { "service_name" => "bin/console", "region" => "AWS-us-east-1", "log_source" => "gem/listen" }
|
721
|
+
}
|
722
|
+
}
|
723
|
+
assert_equal_with_diff expected_data, honeybadger_data
|
644
724
|
end
|
645
725
|
|
646
|
-
|
647
|
-
|
648
|
-
|
649
|
-
|
650
|
-
|
651
|
-
|
652
|
-
|
653
|
-
|
654
|
-
|
655
|
-
|
656
|
-
|
657
|
-
|
658
|
-
|
659
|
-
|
660
|
-
|
661
|
-
|
662
|
-
|
663
|
-
|
664
|
-
|
665
|
-
|
666
|
-
|
667
|
-
|
668
|
-
|
669
|
-
"SERVER_NAME" => "exceptional.com"
|
670
|
-
|
671
|
-
|
672
|
-
|
673
|
-
|
674
|
-
|
675
|
-
|
726
|
+
should "send error details and relevant context data to Honeybadger with empty log_context" do
|
727
|
+
honeybadger_data = nil
|
728
|
+
mock(Honeybadger).notify.with_any_args do |data|
|
729
|
+
honeybadger_data = data
|
730
|
+
end
|
731
|
+
ExceptionHandling.logger.global_context = {}
|
732
|
+
log_context = {}
|
733
|
+
ExceptionHandling.log_error(@exception, @exception_context, @controller, **log_context) do |data|
|
734
|
+
data[:scm_revision] = "5b24eac37aaa91f5784901e9aabcead36fd9df82"
|
735
|
+
data[:user_details] = { username: "jsmith" }
|
736
|
+
data[:event_response] = "Event successfully received"
|
737
|
+
data[:other_section] = "This should not be included in the response"
|
738
|
+
end
|
739
|
+
|
740
|
+
expected_data = {
|
741
|
+
error_class: :"Test Exception",
|
742
|
+
error_message: "Some Exception",
|
743
|
+
controller: "some_controller",
|
744
|
+
exception: @exception,
|
745
|
+
context: {
|
746
|
+
timestamp: Time.now.to_i,
|
747
|
+
error_class: "StandardError",
|
748
|
+
server: "invoca_fe98",
|
749
|
+
exception_context: { "SERVER_NAME" => "exceptional.com" },
|
750
|
+
scm_revision: "5b24eac37aaa91f5784901e9aabcead36fd9df82",
|
751
|
+
notes: "this is used by a test",
|
752
|
+
user_details: { "username" => "jsmith" },
|
753
|
+
request: {
|
754
|
+
"params" => { "advertiser_id" => 435, "controller" => "some_controller" },
|
755
|
+
"rails_root" => "Rails.root not defined. Is this a test environment?",
|
756
|
+
"url" => "host/path"
|
757
|
+
},
|
758
|
+
session: {
|
759
|
+
"key" => nil,
|
760
|
+
"data" => { "username" => "jsmith" }
|
761
|
+
},
|
762
|
+
environment: {
|
763
|
+
"SERVER_NAME" => "exceptional.com"
|
764
|
+
},
|
765
|
+
backtrace: [
|
766
|
+
"test/unit/exception_handling_test.rb:847:in `exception_1'",
|
767
|
+
"test/unit/exception_handling_test.rb:455:in `block (4 levels) in <class:ExceptionHandlingTest>'"
|
768
|
+
],
|
769
|
+
event_response: "Event successfully received"
|
770
|
+
}
|
676
771
|
}
|
677
|
-
|
678
|
-
|
772
|
+
assert_equal_with_diff expected_data, honeybadger_data
|
773
|
+
end
|
679
774
|
end
|
680
775
|
|
681
776
|
context "with post_log_error_hook set" do
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: exception_handling
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.5.1.pre.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Invoca
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-08-
|
11
|
+
date: 2020-08-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: actionmailer
|
@@ -150,6 +150,7 @@ files:
|
|
150
150
|
- lib/exception_handling/version.rb
|
151
151
|
- test/helpers/controller_helpers.rb
|
152
152
|
- test/helpers/exception_helpers.rb
|
153
|
+
- test/rake_test_warning_false.rb
|
153
154
|
- test/test_helper.rb
|
154
155
|
- test/unit/exception_handling/exception_catalog_test.rb
|
155
156
|
- test/unit/exception_handling/exception_description_test.rb
|
@@ -191,6 +192,7 @@ summary: Invoca's exception handling logger/emailer layer, based on exception_no
|
|
191
192
|
test_files:
|
192
193
|
- test/helpers/controller_helpers.rb
|
193
194
|
- test/helpers/exception_helpers.rb
|
195
|
+
- test/rake_test_warning_false.rb
|
194
196
|
- test/test_helper.rb
|
195
197
|
- test/unit/exception_handling/exception_catalog_test.rb
|
196
198
|
- test/unit/exception_handling/exception_description_test.rb
|