bugsnag 6.21.0 → 6.24.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.
Files changed (35) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +102 -0
  3. data/VERSION +1 -1
  4. data/lib/bugsnag/breadcrumb_type.rb +14 -0
  5. data/lib/bugsnag/breadcrumbs/breadcrumb.rb +34 -1
  6. data/lib/bugsnag/breadcrumbs/breadcrumbs.rb +1 -0
  7. data/lib/bugsnag/breadcrumbs/on_breadcrumb_callback_list.rb +50 -0
  8. data/lib/bugsnag/cleaner.rb +31 -18
  9. data/lib/bugsnag/configuration.rb +240 -22
  10. data/lib/bugsnag/delivery/synchronous.rb +2 -2
  11. data/lib/bugsnag/delivery/thread_queue.rb +2 -2
  12. data/lib/bugsnag/endpoint_configuration.rb +11 -0
  13. data/lib/bugsnag/endpoint_validator.rb +80 -0
  14. data/lib/bugsnag/error.rb +25 -0
  15. data/lib/bugsnag/event.rb +7 -0
  16. data/lib/bugsnag/integrations/rack.rb +3 -3
  17. data/lib/bugsnag/integrations/rails/active_job.rb +102 -0
  18. data/lib/bugsnag/integrations/railtie.rb +9 -1
  19. data/lib/bugsnag/integrations/resque.rb +17 -3
  20. data/lib/bugsnag/middleware/active_job.rb +18 -0
  21. data/lib/bugsnag/middleware/delayed_job.rb +21 -2
  22. data/lib/bugsnag/middleware/exception_meta_data.rb +2 -0
  23. data/lib/bugsnag/middleware/rack_request.rb +84 -19
  24. data/lib/bugsnag/middleware/rails3_request.rb +2 -2
  25. data/lib/bugsnag/middleware/rake.rb +1 -1
  26. data/lib/bugsnag/middleware/session_data.rb +3 -1
  27. data/lib/bugsnag/middleware/sidekiq.rb +1 -1
  28. data/lib/bugsnag/report.rb +166 -6
  29. data/lib/bugsnag/session_tracker.rb +52 -12
  30. data/lib/bugsnag/stacktrace.rb +10 -1
  31. data/lib/bugsnag/tasks/bugsnag.rake +1 -1
  32. data/lib/bugsnag/utility/duplicator.rb +124 -0
  33. data/lib/bugsnag/utility/metadata_delegate.rb +102 -0
  34. data/lib/bugsnag.rb +126 -4
  35. metadata +16 -6
@@ -0,0 +1,124 @@
1
+ module Bugsnag::Utility
2
+ # @api private
3
+ class Duplicator
4
+ class << self
5
+ ##
6
+ # Duplicate (deep clone) the given object
7
+ #
8
+ # @param object [Object]
9
+ # @param seen_objects [Hash<String, Object>]
10
+ # @return [Object]
11
+ def duplicate(object, seen_objects = {})
12
+ case object
13
+ # return immutable & non-duplicatable objects as-is
14
+ when Symbol, Numeric, Method, TrueClass, FalseClass, NilClass
15
+ object
16
+ when Array
17
+ duplicate_array(object, seen_objects)
18
+ when Hash
19
+ duplicate_hash(object, seen_objects)
20
+ when Range
21
+ duplicate_range(object, seen_objects)
22
+ when Struct
23
+ duplicate_struct(object, seen_objects)
24
+ else
25
+ duplicate_generic_object(object, seen_objects)
26
+ end
27
+ rescue StandardError
28
+ object
29
+ end
30
+
31
+ private
32
+
33
+ def duplicate_array(array, seen_objects)
34
+ id = array.object_id
35
+
36
+ return seen_objects[id] if seen_objects.key?(id)
37
+
38
+ copy = array.dup
39
+ seen_objects[id] = copy
40
+
41
+ copy.map! do |value|
42
+ duplicate(value, seen_objects)
43
+ end
44
+
45
+ copy
46
+ end
47
+
48
+ def duplicate_hash(hash, seen_objects)
49
+ id = hash.object_id
50
+
51
+ return seen_objects[id] if seen_objects.key?(id)
52
+
53
+ copy = {}
54
+ seen_objects[id] = copy
55
+
56
+ hash.each do |key, value|
57
+ copy[duplicate(key, seen_objects)] = duplicate(value, seen_objects)
58
+ end
59
+
60
+ copy
61
+ end
62
+
63
+ ##
64
+ # Ranges are immutable but the values they contain may not be
65
+ #
66
+ # For example, a range of "a".."z" can be mutated: range.first.upcase!
67
+ def duplicate_range(range, seen_objects)
68
+ id = range.object_id
69
+
70
+ return seen_objects[id] if seen_objects.key?(id)
71
+
72
+ begin
73
+ copy = range.class.new(
74
+ duplicate(range.first, seen_objects),
75
+ duplicate(range.last, seen_objects),
76
+ range.exclude_end?
77
+ )
78
+ rescue StandardError
79
+ copy = range.dup
80
+ end
81
+
82
+ seen_objects[id] = copy
83
+ end
84
+
85
+ def duplicate_struct(struct, seen_objects)
86
+ id = struct.object_id
87
+
88
+ return seen_objects[id] if seen_objects.key?(id)
89
+
90
+ copy = struct.dup
91
+ seen_objects[id] = copy
92
+
93
+ struct.each_pair do |attribute, value|
94
+ begin
95
+ copy.send("#{attribute}=", duplicate(value, seen_objects))
96
+ rescue StandardError # rubocop:todo Lint/SuppressedException
97
+ end
98
+ end
99
+
100
+ copy
101
+ end
102
+
103
+ def duplicate_generic_object(object, seen_objects)
104
+ id = object.object_id
105
+
106
+ return seen_objects[id] if seen_objects.key?(id)
107
+
108
+ copy = object.dup
109
+ seen_objects[id] = copy
110
+
111
+ begin
112
+ copy.instance_variables.each do |variable|
113
+ value = copy.instance_variable_get(variable)
114
+
115
+ copy.instance_variable_set(variable, duplicate(value, seen_objects))
116
+ end
117
+ rescue StandardError # rubocop:todo Lint/SuppressedException
118
+ end
119
+
120
+ copy
121
+ end
122
+ end
123
+ end
124
+ end
@@ -0,0 +1,102 @@
1
+ module Bugsnag::Utility
2
+ # @api private
3
+ class MetadataDelegate
4
+ # nil is a valid metadata value, so we need a sentinel object so we can tell
5
+ # if the value parameter has been provided
6
+ NOT_PROVIDED = Object.new
7
+
8
+ ##
9
+ # Add values to metadata
10
+ #
11
+ # @overload add_metadata(metadata, section, data)
12
+ # Merges data into the given section of metadata
13
+ # @param metadata [Hash] The metadata hash to operate on
14
+ # @param section [String, Symbol]
15
+ # @param data [Hash]
16
+ #
17
+ # @overload add_metadata(metadata, section, key, value)
18
+ # Sets key to value in the given section of metadata. If the value is nil
19
+ # the key will be deleted
20
+ # @param metadata [Hash] The metadata hash to operate on
21
+ # @param section [String, Symbol]
22
+ # @param key [String, Symbol]
23
+ # @param value
24
+ #
25
+ # @return [void]
26
+ def add_metadata(metadata, section, key_or_data, value = NOT_PROVIDED)
27
+ case value
28
+ when NOT_PROVIDED
29
+ merge_metadata(metadata, section, key_or_data)
30
+ when nil
31
+ clear_metadata(metadata, section, key_or_data)
32
+ else
33
+ overwrite_metadata(metadata, section, key_or_data, value)
34
+ end
35
+ end
36
+
37
+ ##
38
+ # Clear values from metadata
39
+ #
40
+ # @overload clear_metadata(metadata, section)
41
+ # Clears the given section of metadata
42
+ # @param metadata [Hash] The metadata hash to operate on
43
+ # @param section [String, Symbol]
44
+ #
45
+ # @overload clear_metadata(metadata, section, key)
46
+ # Clears the key in the given section of metadata
47
+ # @param metadata [Hash] The metadata hash to operate on
48
+ # @param section [String, Symbol]
49
+ # @param key [String, Symbol]
50
+ #
51
+ # @return [void]
52
+ def clear_metadata(metadata, section, key = nil)
53
+ if key.nil?
54
+ metadata.delete(section)
55
+ elsif metadata[section]
56
+ metadata[section].delete(key)
57
+ end
58
+ end
59
+
60
+ private
61
+
62
+ ##
63
+ # Merge new metadata into the existing metadata
64
+ #
65
+ # Any keys with a 'nil' value in the new metadata will be deleted from the
66
+ # existing metadata
67
+ #
68
+ # @param existing_metadata [Hash]
69
+ # @param section [String, Symbol]
70
+ # @param new_metadata [Hash]
71
+ # @return [void]
72
+ def merge_metadata(existing_metadata, section, new_metadata)
73
+ return unless new_metadata.is_a?(Hash)
74
+
75
+ existing_metadata[section] ||= {}
76
+ data = existing_metadata[section]
77
+
78
+ new_metadata.each do |key, value|
79
+ if value.nil?
80
+ data.delete(key)
81
+ else
82
+ data[key] = value
83
+ end
84
+ end
85
+ end
86
+
87
+ ##
88
+ # Overwrite the value in metadata's section & key
89
+ #
90
+ # @param metadata [Hash]
91
+ # @param section [String, Symbol]
92
+ # @param key [String, Symbol]
93
+ # @param value
94
+ # @return [void]
95
+ def overwrite_metadata(metadata, section, key, value)
96
+ return unless key.is_a?(String) || key.is_a?(Symbol)
97
+
98
+ metadata[section] ||= {}
99
+ metadata[section][key] = value
100
+ end
101
+ end
102
+ end
data/lib/bugsnag.rb CHANGED
@@ -5,6 +5,7 @@ require "bugsnag/version"
5
5
  require "bugsnag/configuration"
6
6
  require "bugsnag/meta_data"
7
7
  require "bugsnag/report"
8
+ require "bugsnag/event"
8
9
  require "bugsnag/cleaner"
9
10
  require "bugsnag/helpers"
10
11
  require "bugsnag/session_tracker"
@@ -28,10 +29,14 @@ require "bugsnag/middleware/rake"
28
29
  require "bugsnag/middleware/classify_error"
29
30
  require "bugsnag/middleware/delayed_job"
30
31
 
32
+ require "bugsnag/breadcrumb_type"
31
33
  require "bugsnag/breadcrumbs/validator"
32
34
  require "bugsnag/breadcrumbs/breadcrumb"
33
35
  require "bugsnag/breadcrumbs/breadcrumbs"
34
36
 
37
+ require "bugsnag/utility/duplicator"
38
+ require "bugsnag/utility/metadata_delegate"
39
+
35
40
  # rubocop:todo Metrics/ModuleLength
36
41
  module Bugsnag
37
42
  LOCK = Mutex.new
@@ -132,6 +137,11 @@ module Bugsnag
132
137
  report.severity_reason = initial_reason
133
138
  end
134
139
 
140
+ if report.unhandled_overridden?
141
+ # let the dashboard know that the unhandled flag was overridden
142
+ report.severity_reason[:unhandledOverridden] = true
143
+ end
144
+
135
145
  deliver_notification(report)
136
146
  end
137
147
  end
@@ -187,13 +197,36 @@ module Bugsnag
187
197
  end
188
198
 
189
199
  ##
190
- # Starts a session.
200
+ # Starts a new session, which allows Bugsnag to track error rates across
201
+ # releases
191
202
  #
192
- # Allows Bugsnag to track error rates across releases.
203
+ # @return [void]
193
204
  def start_session
194
205
  session_tracker.start_session
195
206
  end
196
207
 
208
+ ##
209
+ # Stop any events being attributed to the current session until it is
210
+ # resumed or a new session is started
211
+ #
212
+ # @see resume_session
213
+ #
214
+ # @return [void]
215
+ def pause_session
216
+ session_tracker.pause_session
217
+ end
218
+
219
+ ##
220
+ # Resume the current session if it was previously paused. If there is no
221
+ # current session, a new session will be started
222
+ #
223
+ # @see pause_session
224
+ #
225
+ # @return [Boolean] true if a paused session was resumed
226
+ def resume_session
227
+ session_tracker.resume_session
228
+ end
229
+
197
230
  ##
198
231
  # Allow access to "before notify" callbacks as an array.
199
232
  #
@@ -237,7 +270,7 @@ module Bugsnag
237
270
  #
238
271
  # @param name [String] the main breadcrumb name/message
239
272
  # @param meta_data [Hash] String, Numeric, or Boolean meta data to attach
240
- # @param type [String] the breadcrumb type, from Bugsnag::Breadcrumbs::VALID_BREADCRUMB_TYPES
273
+ # @param type [String] the breadcrumb type, see {Bugsnag::BreadcrumbType}
241
274
  # @param auto [Symbol] set to :auto if the breadcrumb is automatically created
242
275
  # @return [void]
243
276
  def leave_breadcrumb(name, meta_data={}, type=Bugsnag::Breadcrumbs::MANUAL_BREADCRUMB_TYPE, auto=:manual)
@@ -250,7 +283,7 @@ module Bugsnag
250
283
  # Skip if it's already invalid
251
284
  return if breadcrumb.ignore?
252
285
 
253
- # Run callbacks
286
+ # Run before_breadcrumb_callbacks
254
287
  configuration.before_breadcrumb_callbacks.each do |c|
255
288
  c.arity > 0 ? c.call(breadcrumb) : c.call
256
289
  break if breadcrumb.ignore?
@@ -259,6 +292,10 @@ module Bugsnag
259
292
  # Return early if ignored
260
293
  return if breadcrumb.ignore?
261
294
 
295
+ # Run on_breadcrumb callbacks
296
+ configuration.on_breadcrumb_callbacks.call(breadcrumb)
297
+ return if breadcrumb.ignore?
298
+
262
299
  # Validate again in case of callback alteration
263
300
  validator.validate(breadcrumb)
264
301
 
@@ -293,6 +330,44 @@ module Bugsnag
293
330
  configuration.remove_on_error(callback)
294
331
  end
295
332
 
333
+ ##
334
+ # Add the given callback to the list of on_breadcrumb callbacks
335
+ #
336
+ # The on_breadcrumb callbacks will be called when a breadcrumb is left and
337
+ # are passed the {Breadcrumbs::Breadcrumb Breadcrumb} object
338
+ #
339
+ # Returning false from an on_breadcrumb callback will cause the breadcrumb
340
+ # to be ignored and will prevent any remaining callbacks from being called
341
+ #
342
+ # @param callback [Proc, Method, #call]
343
+ # @return [void]
344
+ def add_on_breadcrumb(callback)
345
+ configuration.add_on_breadcrumb(callback)
346
+ end
347
+
348
+ ##
349
+ # Remove the given callback from the list of on_breadcrumb callbacks
350
+ #
351
+ # Note that this must be the same instance that was passed to
352
+ # {add_on_breadcrumb}, otherwise it will not be removed
353
+ #
354
+ # @param callback [Proc, Method, #call]
355
+ # @return [void]
356
+ def remove_on_breadcrumb(callback)
357
+ configuration.remove_on_breadcrumb(callback)
358
+ end
359
+
360
+ ##
361
+ # Returns the current list of breadcrumbs
362
+ #
363
+ # This is a per-thread circular buffer, containing at most 'max_breadcrumbs'
364
+ # breadcrumbs
365
+ #
366
+ # @return [Bugsnag::Utility::CircularBuffer]
367
+ def breadcrumbs
368
+ configuration.breadcrumbs
369
+ end
370
+
296
371
  ##
297
372
  # Returns the client's Cleaner object, or creates one if not yet created.
298
373
  #
@@ -306,9 +381,56 @@ module Bugsnag
306
381
  end
307
382
  end
308
383
 
384
+ ##
385
+ # Global metadata added to every event
386
+ #
387
+ # @return [Hash]
388
+ def metadata
389
+ configuration.metadata
390
+ end
391
+
392
+ ##
393
+ # Add values to metadata
394
+ #
395
+ # @overload add_metadata(section, data)
396
+ # Merges data into the given section of metadata
397
+ # @param section [String, Symbol]
398
+ # @param data [Hash]
399
+ #
400
+ # @overload add_metadata(section, key, value)
401
+ # Sets key to value in the given section of metadata. If the value is nil
402
+ # the key will be deleted
403
+ # @param section [String, Symbol]
404
+ # @param key [String, Symbol]
405
+ # @param value
406
+ #
407
+ # @return [void]
408
+ def add_metadata(section, key_or_data, *args)
409
+ configuration.add_metadata(section, key_or_data, *args)
410
+ end
411
+
412
+ ##
413
+ # Clear values from metadata
414
+ #
415
+ # @overload clear_metadata(section)
416
+ # Clears the given section of metadata
417
+ # @param section [String, Symbol]
418
+ #
419
+ # @overload clear_metadata(section, key)
420
+ # Clears the key in the given section of metadata
421
+ # @param section [String, Symbol]
422
+ # @param key [String, Symbol]
423
+ #
424
+ # @return [void]
425
+ def clear_metadata(section, *args)
426
+ configuration.clear_metadata(section, *args)
427
+ end
428
+
309
429
  private
310
430
 
311
431
  def should_deliver_notification?(exception, auto_notify)
432
+ return false unless configuration.enable_events
433
+
312
434
  reason = abort_reason(exception, auto_notify)
313
435
  configuration.debug(reason) unless reason.nil?
314
436
  reason.nil?
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bugsnag
3
3
  version: !ruby/object:Gem::Version
4
- version: 6.21.0
4
+ version: 6.24.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - James Smith
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-06-23 00:00:00.000000000 Z
11
+ date: 2021-11-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: concurrent-ruby
@@ -40,8 +40,10 @@ files:
40
40
  - VERSION
41
41
  - bugsnag.gemspec
42
42
  - lib/bugsnag.rb
43
+ - lib/bugsnag/breadcrumb_type.rb
43
44
  - lib/bugsnag/breadcrumbs/breadcrumb.rb
44
45
  - lib/bugsnag/breadcrumbs/breadcrumbs.rb
46
+ - lib/bugsnag/breadcrumbs/on_breadcrumb_callback_list.rb
45
47
  - lib/bugsnag/breadcrumbs/validator.rb
46
48
  - lib/bugsnag/cleaner.rb
47
49
  - lib/bugsnag/code_extractor.rb
@@ -49,12 +51,17 @@ files:
49
51
  - lib/bugsnag/delivery.rb
50
52
  - lib/bugsnag/delivery/synchronous.rb
51
53
  - lib/bugsnag/delivery/thread_queue.rb
54
+ - lib/bugsnag/endpoint_configuration.rb
55
+ - lib/bugsnag/endpoint_validator.rb
56
+ - lib/bugsnag/error.rb
57
+ - lib/bugsnag/event.rb
52
58
  - lib/bugsnag/helpers.rb
53
59
  - lib/bugsnag/integrations/delayed_job.rb
54
60
  - lib/bugsnag/integrations/mailman.rb
55
61
  - lib/bugsnag/integrations/mongo.rb
56
62
  - lib/bugsnag/integrations/que.rb
57
63
  - lib/bugsnag/integrations/rack.rb
64
+ - lib/bugsnag/integrations/rails/active_job.rb
58
65
  - lib/bugsnag/integrations/rails/active_record_rescue.rb
59
66
  - lib/bugsnag/integrations/rails/controller_methods.rb
60
67
  - lib/bugsnag/integrations/rails/rails_breadcrumbs.rb
@@ -64,6 +71,7 @@ files:
64
71
  - lib/bugsnag/integrations/shoryuken.rb
65
72
  - lib/bugsnag/integrations/sidekiq.rb
66
73
  - lib/bugsnag/meta_data.rb
74
+ - lib/bugsnag/middleware/active_job.rb
67
75
  - lib/bugsnag/middleware/breadcrumbs.rb
68
76
  - lib/bugsnag/middleware/callbacks.rb
69
77
  - lib/bugsnag/middleware/classify_error.rb
@@ -88,13 +96,15 @@ files:
88
96
  - lib/bugsnag/tasks.rb
89
97
  - lib/bugsnag/tasks/bugsnag.rake
90
98
  - lib/bugsnag/utility/circular_buffer.rb
99
+ - lib/bugsnag/utility/duplicator.rb
100
+ - lib/bugsnag/utility/metadata_delegate.rb
91
101
  - lib/bugsnag/version.rb
92
102
  - lib/generators/bugsnag/bugsnag_generator.rb
93
103
  homepage: https://github.com/bugsnag/bugsnag-ruby
94
104
  licenses:
95
105
  - MIT
96
106
  metadata: {}
97
- post_install_message:
107
+ post_install_message:
98
108
  rdoc_options: []
99
109
  require_paths:
100
110
  - lib
@@ -109,8 +119,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
109
119
  - !ruby/object:Gem::Version
110
120
  version: '0'
111
121
  requirements: []
112
- rubygems_version: 3.2.11
113
- signing_key:
122
+ rubygems_version: 3.2.22
123
+ signing_key:
114
124
  specification_version: 4
115
125
  summary: Ruby notifier for bugsnag.com
116
126
  test_files: []