bugsnag 6.21.0 → 6.25.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +1 -0
  3. data/CHANGELOG.md +137 -0
  4. data/VERSION +1 -1
  5. data/bugsnag.gemspec +18 -1
  6. data/lib/bugsnag/breadcrumb_type.rb +14 -0
  7. data/lib/bugsnag/breadcrumbs/breadcrumb.rb +34 -1
  8. data/lib/bugsnag/breadcrumbs/breadcrumbs.rb +1 -0
  9. data/lib/bugsnag/breadcrumbs/on_breadcrumb_callback_list.rb +50 -0
  10. data/lib/bugsnag/cleaner.rb +31 -18
  11. data/lib/bugsnag/configuration.rb +240 -22
  12. data/lib/bugsnag/delivery/synchronous.rb +2 -2
  13. data/lib/bugsnag/delivery/thread_queue.rb +2 -2
  14. data/lib/bugsnag/endpoint_configuration.rb +11 -0
  15. data/lib/bugsnag/endpoint_validator.rb +80 -0
  16. data/lib/bugsnag/error.rb +25 -0
  17. data/lib/bugsnag/event.rb +7 -0
  18. data/lib/bugsnag/feature_flag.rb +74 -0
  19. data/lib/bugsnag/integrations/rack.rb +3 -3
  20. data/lib/bugsnag/integrations/rails/active_job.rb +102 -0
  21. data/lib/bugsnag/integrations/railtie.rb +36 -3
  22. data/lib/bugsnag/integrations/resque.rb +17 -3
  23. data/lib/bugsnag/middleware/active_job.rb +18 -0
  24. data/lib/bugsnag/middleware/delayed_job.rb +21 -2
  25. data/lib/bugsnag/middleware/exception_meta_data.rb +2 -0
  26. data/lib/bugsnag/middleware/rack_request.rb +84 -19
  27. data/lib/bugsnag/middleware/rails3_request.rb +2 -2
  28. data/lib/bugsnag/middleware/rake.rb +1 -1
  29. data/lib/bugsnag/middleware/session_data.rb +3 -1
  30. data/lib/bugsnag/middleware/sidekiq.rb +1 -1
  31. data/lib/bugsnag/middleware/suggestion_data.rb +9 -7
  32. data/lib/bugsnag/report.rb +204 -8
  33. data/lib/bugsnag/session_tracker.rb +52 -12
  34. data/lib/bugsnag/stacktrace.rb +13 -2
  35. data/lib/bugsnag/tasks/bugsnag.rake +1 -1
  36. data/lib/bugsnag/utility/duplicator.rb +124 -0
  37. data/lib/bugsnag/utility/feature_data_store.rb +41 -0
  38. data/lib/bugsnag/utility/feature_flag_delegate.rb +89 -0
  39. data/lib/bugsnag/utility/metadata_delegate.rb +102 -0
  40. data/lib/bugsnag.rb +143 -5
  41. metadata +24 -7
@@ -0,0 +1,89 @@
1
+ module Bugsnag::Utility
2
+ # @api private
3
+ class FeatureFlagDelegate
4
+ def initialize
5
+ # feature flags are stored internally in a hash of "name" => <FeatureFlag>
6
+ # we don't use a Set because new feature flags should overwrite old ones
7
+ # that share a name, but FeatureFlag equality also uses the variant
8
+ @storage = {}
9
+ end
10
+
11
+ def initialize_dup(original)
12
+ super
13
+
14
+ # copy the internal storage when 'dup' is called
15
+ @storage = @storage.dup
16
+ end
17
+
18
+ # Add a feature flag with the given name & variant
19
+ #
20
+ # @param name [String]
21
+ # @param variant [String, nil]
22
+ # @return [void]
23
+ def add(name, variant)
24
+ flag = Bugsnag::FeatureFlag.new(name, variant)
25
+
26
+ return unless flag.valid?
27
+
28
+ @storage[flag.name] = flag
29
+ end
30
+
31
+ # Merge the given array of FeatureFlag instances into the stored feature
32
+ # flags
33
+ #
34
+ # New flags will be appended to the array. Flags with the same name will be
35
+ # overwritten, but their position in the array will not change
36
+ #
37
+ # @param feature_flags [Array<Bugsnag::FeatureFlag>]
38
+ # @return [void]
39
+ def merge(feature_flags)
40
+ feature_flags.each do |flag|
41
+ next unless flag.is_a?(Bugsnag::FeatureFlag)
42
+ next unless flag.valid?
43
+
44
+ @storage[flag.name] = flag
45
+ end
46
+ end
47
+
48
+ # Remove the stored flag with the given name
49
+ #
50
+ # @param name [String]
51
+ # @return [void]
52
+ def remove(name)
53
+ @storage.delete(name)
54
+ end
55
+
56
+ # Remove all the stored flags
57
+ #
58
+ # @return [void]
59
+ def clear
60
+ @storage.clear
61
+ end
62
+
63
+ # Get an array of FeatureFlag instances
64
+ #
65
+ # @example
66
+ # [
67
+ # <#Bugsnag::FeatureFlag>,
68
+ # <#Bugsnag::FeatureFlag>,
69
+ # ]
70
+ #
71
+ # @return [Array<Bugsnag::FeatureFlag>]
72
+ def to_a
73
+ @storage.values
74
+ end
75
+
76
+ # Get the feature flags in their JSON representation
77
+ #
78
+ # @example
79
+ # [
80
+ # { "featureFlag" => "name", "variant" => "variant" },
81
+ # { "featureFlag" => "another name" },
82
+ # ]
83
+ #
84
+ # @return [Array<Hash{String => String}>]
85
+ def as_json
86
+ to_a.map(&:to_h)
87
+ end
88
+ end
89
+ 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
@@ -2,9 +2,11 @@ require "rubygems"
2
2
  require "thread"
3
3
 
4
4
  require "bugsnag/version"
5
+ require "bugsnag/utility/feature_data_store"
5
6
  require "bugsnag/configuration"
6
7
  require "bugsnag/meta_data"
7
8
  require "bugsnag/report"
9
+ require "bugsnag/event"
8
10
  require "bugsnag/cleaner"
9
11
  require "bugsnag/helpers"
10
12
  require "bugsnag/session_tracker"
@@ -13,6 +15,8 @@ require "bugsnag/delivery"
13
15
  require "bugsnag/delivery/synchronous"
14
16
  require "bugsnag/delivery/thread_queue"
15
17
 
18
+ require "bugsnag/feature_flag"
19
+
16
20
  # Rack is not bundled with the other integrations
17
21
  # as it doesn't auto-configure when loaded
18
22
  require "bugsnag/integrations/rack"
@@ -28,10 +32,15 @@ require "bugsnag/middleware/rake"
28
32
  require "bugsnag/middleware/classify_error"
29
33
  require "bugsnag/middleware/delayed_job"
30
34
 
35
+ require "bugsnag/breadcrumb_type"
31
36
  require "bugsnag/breadcrumbs/validator"
32
37
  require "bugsnag/breadcrumbs/breadcrumb"
33
38
  require "bugsnag/breadcrumbs/breadcrumbs"
34
39
 
40
+ require "bugsnag/utility/duplicator"
41
+ require "bugsnag/utility/metadata_delegate"
42
+ require "bugsnag/utility/feature_flag_delegate"
43
+
35
44
  # rubocop:todo Metrics/ModuleLength
36
45
  module Bugsnag
37
46
  LOCK = Mutex.new
@@ -40,6 +49,8 @@ module Bugsnag
40
49
  NIL_EXCEPTION_DESCRIPTION = "'nil' was notified as an exception"
41
50
 
42
51
  class << self
52
+ include Utility::FeatureDataStore
53
+
43
54
  ##
44
55
  # Configure the Bugsnag notifier application-wide settings.
45
56
  #
@@ -67,7 +78,7 @@ module Bugsnag
67
78
  #
68
79
  # Optionally accepts a block to append metadata to the yielded report.
69
80
  def notify(exception, auto_notify=false, &block)
70
- unless auto_notify.is_a? TrueClass or auto_notify.is_a? FalseClass
81
+ unless false.equal? auto_notify or true.equal? auto_notify
71
82
  configuration.warn("Adding metadata/severity using a hash is no longer supported, please use block syntax instead")
72
83
  auto_notify = false
73
84
  end
@@ -132,6 +143,11 @@ module Bugsnag
132
143
  report.severity_reason = initial_reason
133
144
  end
134
145
 
146
+ if report.unhandled_overridden?
147
+ # let the dashboard know that the unhandled flag was overridden
148
+ report.severity_reason[:unhandledOverridden] = true
149
+ end
150
+
135
151
  deliver_notification(report)
136
152
  end
137
153
  end
@@ -187,13 +203,36 @@ module Bugsnag
187
203
  end
188
204
 
189
205
  ##
190
- # Starts a session.
206
+ # Starts a new session, which allows Bugsnag to track error rates across
207
+ # releases
191
208
  #
192
- # Allows Bugsnag to track error rates across releases.
209
+ # @return [void]
193
210
  def start_session
194
211
  session_tracker.start_session
195
212
  end
196
213
 
214
+ ##
215
+ # Stop any events being attributed to the current session until it is
216
+ # resumed or a new session is started
217
+ #
218
+ # @see resume_session
219
+ #
220
+ # @return [void]
221
+ def pause_session
222
+ session_tracker.pause_session
223
+ end
224
+
225
+ ##
226
+ # Resume the current session if it was previously paused. If there is no
227
+ # current session, a new session will be started
228
+ #
229
+ # @see pause_session
230
+ #
231
+ # @return [Boolean] true if a paused session was resumed
232
+ def resume_session
233
+ session_tracker.resume_session
234
+ end
235
+
197
236
  ##
198
237
  # Allow access to "before notify" callbacks as an array.
199
238
  #
@@ -237,7 +276,7 @@ module Bugsnag
237
276
  #
238
277
  # @param name [String] the main breadcrumb name/message
239
278
  # @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
279
+ # @param type [String] the breadcrumb type, see {Bugsnag::BreadcrumbType}
241
280
  # @param auto [Symbol] set to :auto if the breadcrumb is automatically created
242
281
  # @return [void]
243
282
  def leave_breadcrumb(name, meta_data={}, type=Bugsnag::Breadcrumbs::MANUAL_BREADCRUMB_TYPE, auto=:manual)
@@ -250,7 +289,7 @@ module Bugsnag
250
289
  # Skip if it's already invalid
251
290
  return if breadcrumb.ignore?
252
291
 
253
- # Run callbacks
292
+ # Run before_breadcrumb_callbacks
254
293
  configuration.before_breadcrumb_callbacks.each do |c|
255
294
  c.arity > 0 ? c.call(breadcrumb) : c.call
256
295
  break if breadcrumb.ignore?
@@ -259,6 +298,10 @@ module Bugsnag
259
298
  # Return early if ignored
260
299
  return if breadcrumb.ignore?
261
300
 
301
+ # Run on_breadcrumb callbacks
302
+ configuration.on_breadcrumb_callbacks.call(breadcrumb)
303
+ return if breadcrumb.ignore?
304
+
262
305
  # Validate again in case of callback alteration
263
306
  validator.validate(breadcrumb)
264
307
 
@@ -293,6 +336,44 @@ module Bugsnag
293
336
  configuration.remove_on_error(callback)
294
337
  end
295
338
 
339
+ ##
340
+ # Add the given callback to the list of on_breadcrumb callbacks
341
+ #
342
+ # The on_breadcrumb callbacks will be called when a breadcrumb is left and
343
+ # are passed the {Breadcrumbs::Breadcrumb Breadcrumb} object
344
+ #
345
+ # Returning false from an on_breadcrumb callback will cause the breadcrumb
346
+ # to be ignored and will prevent any remaining callbacks from being called
347
+ #
348
+ # @param callback [Proc, Method, #call]
349
+ # @return [void]
350
+ def add_on_breadcrumb(callback)
351
+ configuration.add_on_breadcrumb(callback)
352
+ end
353
+
354
+ ##
355
+ # Remove the given callback from the list of on_breadcrumb callbacks
356
+ #
357
+ # Note that this must be the same instance that was passed to
358
+ # {add_on_breadcrumb}, otherwise it will not be removed
359
+ #
360
+ # @param callback [Proc, Method, #call]
361
+ # @return [void]
362
+ def remove_on_breadcrumb(callback)
363
+ configuration.remove_on_breadcrumb(callback)
364
+ end
365
+
366
+ ##
367
+ # Returns the current list of breadcrumbs
368
+ #
369
+ # This is a per-thread circular buffer, containing at most 'max_breadcrumbs'
370
+ # breadcrumbs
371
+ #
372
+ # @return [Bugsnag::Utility::CircularBuffer]
373
+ def breadcrumbs
374
+ configuration.breadcrumbs
375
+ end
376
+
296
377
  ##
297
378
  # Returns the client's Cleaner object, or creates one if not yet created.
298
379
  #
@@ -306,9 +387,66 @@ module Bugsnag
306
387
  end
307
388
  end
308
389
 
390
+ ##
391
+ # Global metadata added to every event
392
+ #
393
+ # @return [Hash]
394
+ def metadata
395
+ configuration.metadata
396
+ end
397
+
398
+ ##
399
+ # Add values to metadata
400
+ #
401
+ # @overload add_metadata(section, data)
402
+ # Merges data into the given section of metadata
403
+ # @param section [String, Symbol]
404
+ # @param data [Hash]
405
+ #
406
+ # @overload add_metadata(section, key, value)
407
+ # Sets key to value in the given section of metadata. If the value is nil
408
+ # the key will be deleted
409
+ # @param section [String, Symbol]
410
+ # @param key [String, Symbol]
411
+ # @param value
412
+ #
413
+ # @return [void]
414
+ def add_metadata(section, key_or_data, *args)
415
+ configuration.add_metadata(section, key_or_data, *args)
416
+ end
417
+
418
+ ##
419
+ # Clear values from metadata
420
+ #
421
+ # @overload clear_metadata(section)
422
+ # Clears the given section of metadata
423
+ # @param section [String, Symbol]
424
+ #
425
+ # @overload clear_metadata(section, key)
426
+ # Clears the key in the given section of metadata
427
+ # @param section [String, Symbol]
428
+ # @param key [String, Symbol]
429
+ #
430
+ # @return [void]
431
+ def clear_metadata(section, *args)
432
+ configuration.clear_metadata(section, *args)
433
+ end
434
+
435
+ # Expose the feature flag delegate internally for use when creating new Events
436
+ #
437
+ # The Bugsnag module's feature_flag_delegate is request-specific
438
+ #
439
+ # @return [Bugsnag::Utility::FeatureFlagDelegate]
440
+ # @api private
441
+ def feature_flag_delegate
442
+ configuration.request_data[:feature_flag_delegate] ||= Utility::FeatureFlagDelegate.new
443
+ end
444
+
309
445
  private
310
446
 
311
447
  def should_deliver_notification?(exception, auto_notify)
448
+ return false unless configuration.enable_events
449
+
312
450
  reason = abort_reason(exception, auto_notify)
313
451
  configuration.debug(reason) unless reason.nil?
314
452
  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.25.2
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: 2023-02-07 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,18 @@ 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
58
+ - lib/bugsnag/feature_flag.rb
52
59
  - lib/bugsnag/helpers.rb
53
60
  - lib/bugsnag/integrations/delayed_job.rb
54
61
  - lib/bugsnag/integrations/mailman.rb
55
62
  - lib/bugsnag/integrations/mongo.rb
56
63
  - lib/bugsnag/integrations/que.rb
57
64
  - lib/bugsnag/integrations/rack.rb
65
+ - lib/bugsnag/integrations/rails/active_job.rb
58
66
  - lib/bugsnag/integrations/rails/active_record_rescue.rb
59
67
  - lib/bugsnag/integrations/rails/controller_methods.rb
60
68
  - lib/bugsnag/integrations/rails/rails_breadcrumbs.rb
@@ -64,6 +72,7 @@ files:
64
72
  - lib/bugsnag/integrations/shoryuken.rb
65
73
  - lib/bugsnag/integrations/sidekiq.rb
66
74
  - lib/bugsnag/meta_data.rb
75
+ - lib/bugsnag/middleware/active_job.rb
67
76
  - lib/bugsnag/middleware/breadcrumbs.rb
68
77
  - lib/bugsnag/middleware/callbacks.rb
69
78
  - lib/bugsnag/middleware/classify_error.rb
@@ -88,13 +97,21 @@ files:
88
97
  - lib/bugsnag/tasks.rb
89
98
  - lib/bugsnag/tasks/bugsnag.rake
90
99
  - lib/bugsnag/utility/circular_buffer.rb
100
+ - lib/bugsnag/utility/duplicator.rb
101
+ - lib/bugsnag/utility/feature_data_store.rb
102
+ - lib/bugsnag/utility/feature_flag_delegate.rb
103
+ - lib/bugsnag/utility/metadata_delegate.rb
91
104
  - lib/bugsnag/version.rb
92
105
  - lib/generators/bugsnag/bugsnag_generator.rb
93
106
  homepage: https://github.com/bugsnag/bugsnag-ruby
94
107
  licenses:
95
108
  - MIT
96
- metadata: {}
97
- post_install_message:
109
+ metadata:
110
+ changelog_uri: https://github.com/bugsnag/bugsnag-ruby/blob/HEAD/CHANGELOG.md
111
+ documentation_uri: https://docs.bugsnag.com/platforms/ruby/
112
+ source_code_uri: https://github.com/bugsnag/bugsnag-ruby/
113
+ rubygems_mfa_required: 'true'
114
+ post_install_message:
98
115
  rdoc_options: []
99
116
  require_paths:
100
117
  - lib
@@ -109,8 +126,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
109
126
  - !ruby/object:Gem::Version
110
127
  version: '0'
111
128
  requirements: []
112
- rubygems_version: 3.2.11
113
- signing_key:
129
+ rubygems_version: 3.3.7
130
+ signing_key:
114
131
  specification_version: 4
115
132
  summary: Ruby notifier for bugsnag.com
116
133
  test_files: []