bugsnag 6.16.0 → 6.21.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e9bb31732c622071a10627844a093751bf767b5ef56471a705d79925c65fdb74
4
- data.tar.gz: 22d0d2499b04005fcbeec5dbddfa5ba9cd456f9559f550044af84d8cb0478c98
3
+ metadata.gz: d25c44a654cbfc8684f28ea8ae1853f3aa482abc2741574662afb8368ab8c5b2
4
+ data.tar.gz: a5c2462967da4d5995a7e07715a310bf5290019943395feef4a782290f2e34c2
5
5
  SHA512:
6
- metadata.gz: b3849f0fc864298c2115cbff97cfb4d6896298b82eb1fd2b1a71063360954fd7b463aa57723d282e47981039723662d7f85f837bcb39d82b4c9d8b04d14db2a8
7
- data.tar.gz: e9562a284de421e222737cb786968e5eade6318291d388a95233335e574b27bf41c66f76a41975047ffc0016ad586520588b068fc3622f16f5c5dc2ac48daf72
6
+ metadata.gz: 97c2d1764646f0e7fa90fd7c6d9fd4f3811acde1da0cd110a5f186cd164d52fb61fe2a13add1d75f3fd492ccc4c034e63167a4f1c7f06e8586363b95a58788db
7
+ data.tar.gz: 64c6671f0cddbcdcc71e34ceb4719132f9e503a9e5be9ec73692348b3d023c3b68f572bba05489220dda5eea9f4a4fb89a3559f16d416eb19e6150bf86482640
data/.yardopts ADDED
@@ -0,0 +1,11 @@
1
+ --charset UTF-8
2
+ --fail-on-warning
3
+ --hide-api private
4
+ --no-private
5
+ --protected
6
+ --title "bugsnag-ruby API Documentation"
7
+ lib/**/*.rb
8
+ -
9
+ README.md
10
+ CONTRIBUTING.md
11
+ CHANGELOG.md
data/CHANGELOG.md CHANGED
@@ -1,6 +1,68 @@
1
1
  Changelog
2
2
  =========
3
3
 
4
+ ## v6.21.0 (23 June 2021)
5
+
6
+ ### Enhancements
7
+
8
+ * Allow a `Method` or any object responding to `#call` to be used as an `on_error` callback or middleware
9
+ | [#662](https://github.com/bugsnag/bugsnag-ruby/pull/662)
10
+ | [odlp](https://github.com/odlp)
11
+
12
+ ### Fixes
13
+
14
+ * Deliver when an error is raised in the block argument to `notify`
15
+ | [#660](https://github.com/bugsnag/bugsnag-ruby/pull/660)
16
+ | [aki77](https://github.com/aki77)
17
+ * Fix potential `NoMethodError` in `Bugsnag::Railtie` when using `require: false` in a Gemfile
18
+ | [#666](https://github.com/bugsnag/bugsnag-ruby/pull/666)
19
+
20
+ ## v6.20.0 (29 March 2021)
21
+
22
+ ### Enhancements
23
+
24
+ * Classify `ActionDispatch::Http::MimeNegotiation::InvalidType` as info severity level
25
+ | [#654](https://github.com/bugsnag/bugsnag-ruby/pull/654)
26
+
27
+ ### Fixes
28
+
29
+ * Include `connection_id` in ActiveRecord breadcrumb metadata on new versons of Rails
30
+ | [#655](https://github.com/bugsnag/bugsnag-ruby/pull/655)
31
+ * Avoid crash when Mongo 1.12 or earlier is used
32
+ | [#652](https://github.com/bugsnag/bugsnag-ruby/pull/652)
33
+ | [isabanin](https://github.com/isabanin)
34
+
35
+ ## 6.19.0 (6 January 2021)
36
+
37
+ ### Enhancements
38
+
39
+ * Exception messages will be truncated if they have a length greater than 3,072
40
+ | [#636](https://github.com/bugsnag/bugsnag-ruby/pull/636)
41
+ | [joshuapinter](https://github.com/joshuapinter)
42
+
43
+ * Breadcrumb metadata can now contain any type
44
+ | [#648](https://github.com/bugsnag/bugsnag-ruby/pull/648)
45
+
46
+ ## 6.18.0 (27 October 2020)
47
+
48
+ ### Enhancements
49
+
50
+ * Bugsnag should now report uncaught exceptions inside Bundler's 'friendly errors'
51
+ | [#634](https://github.com/bugsnag/bugsnag-ruby/pull/634)
52
+
53
+ * Improve the display of breadrumbs in the Bugsnag app by including milliseconds in timestamps
54
+ | [#639](https://github.com/bugsnag/bugsnag-ruby/pull/639)
55
+
56
+ ## 6.17.0 (27 August 2020)
57
+
58
+ ### Enhancements
59
+
60
+ * Sidekiq now uses `thread_queue` delivery by default
61
+ | [#626](https://github.com/bugsnag/bugsnag-ruby/pull/626)
62
+
63
+ * Rescue now uses `thread_queue` delivery when `at_exit` hooks are enabled
64
+ | [#629](https://github.com/bugsnag/bugsnag-ruby/pull/629)
65
+
4
66
  ## 6.16.0 (12 August 2020)
5
67
 
6
68
  ### Enhancements
data/VERSION CHANGED
@@ -1 +1 @@
1
- 6.16.0
1
+ 6.21.0
data/bugsnag.gemspec CHANGED
@@ -10,7 +10,7 @@ Gem::Specification.new do |s|
10
10
  s.homepage = "https://github.com/bugsnag/bugsnag-ruby"
11
11
  s.licenses = ["MIT"]
12
12
 
13
- s.files = `git ls-files -z lib bugsnag.gemspec VERSION`.split("\x0")
13
+ s.files = `git ls-files -z lib bugsnag.gemspec VERSION .yardopts`.split("\x0")
14
14
  s.extra_rdoc_files = [
15
15
  "LICENSE.txt",
16
16
  "README.md",
data/lib/bugsnag.rb CHANGED
@@ -25,7 +25,6 @@ require "bugsnag/middleware/rails3_request"
25
25
  require "bugsnag/middleware/sidekiq"
26
26
  require "bugsnag/middleware/mailman"
27
27
  require "bugsnag/middleware/rake"
28
- require "bugsnag/middleware/callbacks"
29
28
  require "bugsnag/middleware/classify_error"
30
29
  require "bugsnag/middleware/delayed_job"
31
30
 
@@ -44,7 +43,10 @@ module Bugsnag
44
43
  ##
45
44
  # Configure the Bugsnag notifier application-wide settings.
46
45
  #
47
- # Yields a configuration object to use to set application settings.
46
+ # Yields a {Configuration} object to use to set application settings.
47
+ #
48
+ # @yieldparam configuration [Configuration]
49
+ # @return [void]
48
50
  def configure(validate_api_key=true)
49
51
  yield(configuration) if block_given?
50
52
 
@@ -77,7 +79,12 @@ module Bugsnag
77
79
  report = Report.new(exception, configuration, auto_notify)
78
80
 
79
81
  # If this is an auto_notify we yield the block before the any middleware is run
80
- yield(report) if block_given? && auto_notify
82
+ begin
83
+ yield(report) if block_given? && auto_notify
84
+ rescue StandardError => e
85
+ configuration.warn("Error in internal notify block: #{e}")
86
+ configuration.warn("Error in internal notify block stacktrace: #{e.backtrace.inspect}")
87
+ end
81
88
 
82
89
  if report.ignore?
83
90
  configuration.debug("Not notifying #{report.exceptions.last[:errorClass]} due to ignore being signified in auto_notify block")
@@ -104,7 +111,12 @@ module Bugsnag
104
111
 
105
112
  # If this is not an auto_notify then the block was provided by the user. This should be the last
106
113
  # block that is run as it is the users "most specific" block.
107
- yield(report) if block_given? && !auto_notify
114
+ begin
115
+ yield(report) if block_given? && !auto_notify
116
+ rescue StandardError => e
117
+ configuration.warn("Error in notify block: #{e}")
118
+ configuration.warn("Error in notify block stacktrace: #{e.backtrace.inspect}")
119
+ end
108
120
 
109
121
  if report.ignore?
110
122
  configuration.debug("Not notifying #{report.exceptions.last[:errorClass]} due to ignore being signified in user provided block")
@@ -125,13 +137,17 @@ module Bugsnag
125
137
  end
126
138
 
127
139
  ##
128
- # Registers an at_exit function to automatically catch errors on exit
140
+ # Registers an at_exit function to automatically catch errors on exit.
141
+ #
142
+ # @return [void]
129
143
  def register_at_exit
130
144
  return if at_exit_handler_installed?
131
145
  @exit_handler_added = true
132
146
  at_exit do
133
147
  if $!
134
- Bugsnag.notify($!, true) do |report|
148
+ exception = unwrap_bundler_exception($!)
149
+
150
+ Bugsnag.notify(exception, true) do |report|
135
151
  report.severity = 'error'
136
152
  report.severity_reason = {
137
153
  :type => Bugsnag::Report::UNHANDLED_EXCEPTION
@@ -142,14 +158,19 @@ module Bugsnag
142
158
  end
143
159
 
144
160
  ##
145
- # Checks if an at_exit handler has been added
161
+ # Checks if an at_exit handler has been added.
162
+ #
163
+ # The {Bugsnag#configure} method will add this automatically, but it can be
164
+ # added manually using {Bugsnag#register_at_exit}.
165
+ #
166
+ # @return [Boolean]
146
167
  def at_exit_handler_installed?
147
168
  @exit_handler_added ||= false
148
169
  end
149
170
 
150
- # Configuration getters
151
171
  ##
152
172
  # Returns the client's Configuration object, or creates one if not yet created.
173
+ #
153
174
  # @return [Configuration]
154
175
  def configuration
155
176
  @configuration = nil unless defined?(@configuration)
@@ -158,6 +179,8 @@ module Bugsnag
158
179
 
159
180
  ##
160
181
  # Returns the client's SessionTracker object, or creates one if not yet created.
182
+ #
183
+ # @return [SessionTracker]
161
184
  def session_tracker
162
185
  @session_tracker = nil unless defined?(@session_tracker)
163
186
  @session_tracker || LOCK.synchronize { @session_tracker ||= Bugsnag::SessionTracker.new}
@@ -181,7 +204,10 @@ module Bugsnag
181
204
  Bugsnag.configuration.request_data[:before_callbacks] ||= []
182
205
  end
183
206
 
184
- # Attempts to load all integrations through auto-discovery
207
+ ##
208
+ # Attempts to load all integrations through auto-discovery.
209
+ #
210
+ # @return [void]
185
211
  def load_integrations
186
212
  require "bugsnag/integrations/railtie" if defined?(Rails::Railtie)
187
213
  INTEGRATIONS.each do |integration|
@@ -192,7 +218,11 @@ module Bugsnag
192
218
  end
193
219
  end
194
220
 
195
- # Load a specific integration
221
+ ##
222
+ # Load a specific integration.
223
+ #
224
+ # @param integration [Symbol] One of the integrations in {INTEGRATIONS}
225
+ # @return [void]
196
226
  def load_integration(integration)
197
227
  integration = :railtie if integration == :rails
198
228
  if INTEGRATIONS.include?(integration) || integration == :railtie
@@ -209,6 +239,7 @@ module Bugsnag
209
239
  # @param meta_data [Hash] String, Numeric, or Boolean meta data to attach
210
240
  # @param type [String] the breadcrumb type, from Bugsnag::Breadcrumbs::VALID_BREADCRUMB_TYPES
211
241
  # @param auto [Symbol] set to :auto if the breadcrumb is automatically created
242
+ # @return [void]
212
243
  def leave_breadcrumb(name, meta_data={}, type=Bugsnag::Breadcrumbs::MANUAL_BREADCRUMB_TYPE, auto=:manual)
213
244
  breadcrumb = Bugsnag::Breadcrumbs::Breadcrumb.new(name, type, meta_data, auto)
214
245
  validator = Bugsnag::Breadcrumbs::Validator.new(configuration)
@@ -244,7 +275,7 @@ module Bugsnag
244
275
  # Returning false from an on_error callback will cause the error to be ignored
245
276
  # and will prevent any remaining callbacks from being called
246
277
  #
247
- # @param callback [Proc]
278
+ # @param callback [Proc, Method, #call]
248
279
  # @return [void]
249
280
  def add_on_error(callback)
250
281
  configuration.add_on_error(callback)
@@ -370,6 +401,39 @@ module Bugsnag
370
401
 
371
402
  ::JSON.dump(trimmed)
372
403
  end
404
+
405
+ ##
406
+ # When running a script with 'bundle exec', uncaught exceptions will be
407
+ # converted to "friendly errors" which has the side effect of wrapping them
408
+ # in a SystemExit
409
+ #
410
+ # By default we ignore SystemExit, so need to unwrap the original exception
411
+ # in order to avoid ignoring real errors
412
+ #
413
+ # @param exception [Exception]
414
+ # @return [Exception]
415
+ def unwrap_bundler_exception(exception)
416
+ running_in_bundler = ENV.include?('BUNDLE_BIN_PATH')
417
+
418
+ # See if this exception came from Bundler's 'with_friendly_errors' method
419
+ return exception unless running_in_bundler
420
+ return exception unless exception.is_a?(SystemExit)
421
+ return exception unless exception.respond_to?(:cause)
422
+ return exception unless exception.backtrace.first.include?('/bundler/friendly_errors.rb')
423
+ return exception if exception.cause.nil?
424
+
425
+ unwrapped = exception.cause
426
+
427
+ # We may need to unwrap another level if the exception came from running
428
+ # an executable file directly (i.e. 'bundle exec <file>'). In this case
429
+ # there can be a SystemExit from 'with_friendly_errors' _and_ a SystemExit
430
+ # from 'kernel_load'
431
+ return unwrapped unless unwrapped.is_a?(SystemExit)
432
+ return unwrapped unless unwrapped.backtrace.first.include?('/bundler/cli/exec.rb')
433
+ return unwrapped if unwrapped.cause.nil?
434
+
435
+ unwrapped.cause
436
+ end
373
437
  end
374
438
  end
375
439
  # rubocop:enable Metrics/ModuleLength
@@ -69,7 +69,7 @@ module Bugsnag::Breadcrumbs
69
69
  :name => @name,
70
70
  :type => @type,
71
71
  :metaData => @meta_data,
72
- :timestamp => @timestamp.iso8601
72
+ :timestamp => @timestamp.iso8601(3)
73
73
  }
74
74
  end
75
75
  end
@@ -15,16 +15,6 @@ module Bugsnag::Breadcrumbs
15
15
  #
16
16
  # @param breadcrumb [Bugsnag::Breadcrumbs::Breadcrumb] the breadcrumb to be validated
17
17
  def validate(breadcrumb)
18
- # Check meta_data hash doesn't contain complex values
19
- breadcrumb.meta_data = breadcrumb.meta_data.select do |k, v|
20
- if valid_meta_data_type?(v)
21
- true
22
- else
23
- @configuration.debug("Breadcrumb #{breadcrumb.name} meta_data #{k}:#{v.class} has been dropped for having an invalid data type")
24
- false
25
- end
26
- end
27
-
28
18
  # Check type is valid, set to manual otherwise
29
19
  unless Bugsnag::Breadcrumbs::VALID_BREADCRUMB_TYPES.include?(breadcrumb.type)
30
20
  @configuration.debug("Invalid type: #{breadcrumb.type} for breadcrumb: #{breadcrumb.name}, defaulting to #{Bugsnag::Breadcrumbs::MANUAL_BREADCRUMB_TYPE}")
@@ -37,17 +27,5 @@ module Bugsnag::Breadcrumbs
37
27
  @configuration.debug("Automatic breadcrumb of type #{breadcrumb.type} ignored: #{breadcrumb.name}")
38
28
  breadcrumb.ignore!
39
29
  end
40
-
41
- private
42
-
43
- ##
44
- # Tests whether the meta_data types are non-complex objects.
45
- #
46
- # Acceptable types are String, Symbol, Numeric, TrueClass, FalseClass, and nil.
47
- #
48
- # @param value [Object] the object to be type checked
49
- def valid_meta_data_type?(value)
50
- value.nil? || value.is_a?(String) || value.is_a?(Symbol) || value.is_a?(Numeric) || value.is_a?(FalseClass) || value.is_a?(TrueClass)
51
- end
52
30
  end
53
31
  end
@@ -15,64 +15,134 @@ require "bugsnag/breadcrumbs/breadcrumbs"
15
15
 
16
16
  module Bugsnag
17
17
  class Configuration
18
+ # Your Integration API Key
19
+ # @return [String, nil]
18
20
  attr_accessor :api_key
21
+
22
+ # The current stage of the release process, e.g. 'development', production'
23
+ # @return [String, nil]
19
24
  attr_accessor :release_stage
25
+
26
+ # A list of which release stages should cause notifications to be sent
27
+ # @return [Array<String>, nil]
20
28
  attr_accessor :notify_release_stages
29
+
30
+ # Whether notifications should automatically be sent
31
+ # @return [Boolean]
21
32
  attr_accessor :auto_notify
33
+
34
+ # @return [String, nil]
22
35
  attr_accessor :ca_file
36
+
37
+ # Whether to automatically attach the Rack environment to notifications
38
+ # @return [Boolean]
23
39
  attr_accessor :send_environment
40
+
41
+ # Whether code snippets from the exception stacktrace should be sent with notifications
42
+ # @return [Boolean]
24
43
  attr_accessor :send_code
44
+
45
+ # Any stacktrace lines that match this path will be marked as 'in project'
46
+ # @return [String, nil]
25
47
  attr_accessor :project_root
48
+
49
+ # The current version of your application
50
+ # @return [String, nil]
26
51
  attr_accessor :app_version
52
+
53
+ # A list of keys that should be filtered out from the report and breadcrumb
54
+ # metadata before sending them to Bugsnag
55
+ # @return [Set<String, Regexp>]
27
56
  attr_accessor :meta_data_filters
57
+
58
+ # The logger to use for Bugsnag log messages
59
+ # @return [Logger]
28
60
  attr_accessor :logger
61
+
62
+ # The middleware stack that will run on every notification
63
+ # @return [MiddlewareStack]
29
64
  attr_accessor :middleware
65
+
66
+ # @api private
67
+ # @return [MiddlewareStack]
30
68
  attr_accessor :internal_middleware
69
+
70
+ # The host address of the HTTP proxy that should be used when making requests
71
+ # @see parse_proxy
72
+ # @return [String, nil]
31
73
  attr_accessor :proxy_host
74
+
75
+ # The port number of the HTTP proxy that should be used when making requests
76
+ # @see parse_proxy
77
+ # @return [Integer, nil]
32
78
  attr_accessor :proxy_port
79
+
80
+ # The user that should be used when making requests via a HTTP proxy
81
+ # @see parse_proxy
82
+ # @return [String, nil]
33
83
  attr_accessor :proxy_user
84
+
85
+ # The password for the user that should be used when making requests via a HTTP proxy
86
+ # @see parse_proxy
87
+ # @return [String, nil]
34
88
  attr_accessor :proxy_password
89
+
90
+ # The HTTP request timeout, defaults to 15 seconds
91
+ # @return [Integer]
35
92
  attr_accessor :timeout
93
+
94
+ # The name or descriptor of the Ruby server host
95
+ # @return [String]
36
96
  attr_accessor :hostname
97
+
98
+ # @api private
99
+ # @return [Hash{String => String}]
37
100
  attr_accessor :runtime_versions
101
+
102
+ # Exception classes that will be discarded and not sent to Bugsnag
103
+ # @return [Set<String, Regexp>]
38
104
  attr_accessor :discard_classes
105
+
106
+ # Whether Bugsnag should automatically record sessions
107
+ # @return [Boolean]
39
108
  attr_accessor :auto_capture_sessions
40
109
 
41
- ##
42
110
  # @deprecated Use {#discard_classes} instead
111
+ # @return [Set<Class, Proc>]
43
112
  attr_accessor :ignore_classes
44
113
 
45
- ##
46
- # @return [String] URL error notifications will be delivered to
114
+ # The URL error notifications will be delivered to
115
+ # @return [String]
47
116
  attr_reader :notify_endpoint
48
117
  alias :endpoint :notify_endpoint
49
118
 
50
- ##
51
- # @return [String] URL session notifications will be delivered to
119
+ # The URL session notifications will be delivered to
120
+ # @return [String]
52
121
  attr_reader :session_endpoint
53
122
 
54
- ##
55
- # @return [Boolean] whether any sessions types will be delivered
123
+ # Whether sessions will be delivered
124
+ # @return [Boolean]
56
125
  attr_reader :enable_sessions
57
126
 
58
- ##
59
- # @return [Array<String>] strings indicating allowable automatic breadcrumb types
127
+ # A list of strings indicating allowable automatic breadcrumb types
128
+ # @see Bugsnag::Breadcrumbs::VALID_BREADCRUMB_TYPES
129
+ # @return [Array<String>]
60
130
  attr_accessor :enabled_automatic_breadcrumb_types
61
131
 
62
- ##
63
- # @return [Array<#call>] callables to be run before a breadcrumb is logged
132
+ # Callables to be run before a breadcrumb is logged
133
+ # @return [Array<#call>]
64
134
  attr_accessor :before_breadcrumb_callbacks
65
135
 
66
- ##
67
- # @return [Integer] the maximum allowable amount of breadcrumbs per thread
136
+ # The maximum allowable amount of breadcrumbs per thread
137
+ # @return [Integer]
68
138
  attr_reader :max_breadcrumbs
69
139
 
70
- ##
71
- # @return [Regexp] matching file paths out of project
140
+ #
141
+ # @return [Regexp]
72
142
  attr_accessor :vendor_path
73
143
 
74
- ##
75
- # @return [Array]
144
+ # @api private
145
+ # @return [Array<String>]
76
146
  attr_reader :scopes_to_filter
77
147
 
78
148
  API_KEY_REGEX = /[0-9a-f]{32}/i
@@ -96,6 +166,7 @@ module Bugsnag
96
166
  # Path to vendored code. Used to mark file paths as out of project.
97
167
  DEFAULT_VENDOR_PATH = %r{^(vendor/|\.bundle/)}
98
168
 
169
+ # @api private
99
170
  DEFAULT_SCOPES_TO_FILTER = ['events.metaData', 'events.breadcrumbs.metaData'].freeze
100
171
 
101
172
  alias :track_sessions :auto_capture_sessions
@@ -177,6 +248,7 @@ module Bugsnag
177
248
  # Gets the delivery_method that Bugsnag will use to communicate with the
178
249
  # notification endpoint.
179
250
  #
251
+ # @return [Symbol]
180
252
  def delivery_method
181
253
  @delivery_method || @default_delivery_method || :thread_queue
182
254
  end
@@ -185,6 +257,10 @@ module Bugsnag
185
257
  # Sets the delivery_method that Bugsnag will use to communicate with the
186
258
  # notification endpoint.
187
259
  #
260
+ # The default delivery methods are ':thread_queue' and ':synchronous'.
261
+ #
262
+ # @param delivery_method [Symbol]
263
+ # @return [void]
188
264
  def delivery_method=(delivery_method)
189
265
  @delivery_method = delivery_method
190
266
  end
@@ -193,6 +269,10 @@ module Bugsnag
193
269
  # Used to set a new default delivery method that will be used if one is not
194
270
  # set with #delivery_method.
195
271
  #
272
+ # @api private
273
+ #
274
+ # @param delivery_method [Symbol]
275
+ # @return [void]
196
276
  def default_delivery_method=(delivery_method)
197
277
  @default_delivery_method = delivery_method
198
278
  end
@@ -248,12 +328,16 @@ module Bugsnag
248
328
  ##
249
329
  # Indicates whether the notifier should send a notification based on the
250
330
  # configured release stage.
331
+ #
332
+ # @return [Boolean]
251
333
  def should_notify_release_stage?
252
334
  @release_stage.nil? || @notify_release_stages.nil? || @notify_release_stages.include?(@release_stage)
253
335
  end
254
336
 
255
337
  ##
256
338
  # Tests whether the configured API key is valid.
339
+ #
340
+ # @return [Boolean]
257
341
  def valid_api_key?
258
342
  !api_key.nil? && api_key =~ API_KEY_REGEX
259
343
  end
@@ -261,48 +345,68 @@ module Bugsnag
261
345
  ##
262
346
  # Returns the array of data that will be automatically attached to every
263
347
  # error notification.
348
+ #
349
+ # @return [Hash]
264
350
  def request_data
265
351
  Thread.current[THREAD_LOCAL_NAME] ||= {}
266
352
  end
267
353
 
268
354
  ##
269
355
  # Sets an entry in the array of data attached to every error notification.
356
+ #
357
+ # @param key [String, #to_s]
358
+ # @param value [Object]
359
+ # @return [void]
270
360
  def set_request_data(key, value)
271
361
  self.request_data[key] = value
272
362
  end
273
363
 
274
364
  ##
275
365
  # Unsets an entry in the array of data attached to every error notification.
366
+ #
367
+ # @param (see set_request_data)
368
+ # @return [void]
276
369
  def unset_request_data(key, value)
277
370
  self.request_data.delete(key)
278
371
  end
279
372
 
280
373
  ##
281
374
  # Clears the array of data attached to every error notification.
375
+ #
376
+ # @return [void]
282
377
  def clear_request_data
283
378
  Thread.current[THREAD_LOCAL_NAME] = nil
284
379
  end
285
380
 
286
381
  ##
287
382
  # Logs an info level message
383
+ #
384
+ # @param message [String, #to_s] The message to log
288
385
  def info(message)
289
386
  logger.info(PROG_NAME) { message }
290
387
  end
291
388
 
292
389
  ##
293
390
  # Logs a warning level message
391
+ #
392
+ # @param (see info)
294
393
  def warn(message)
295
394
  logger.warn(PROG_NAME) { message }
296
395
  end
297
396
 
298
397
  ##
299
398
  # Logs a debug level message
399
+ #
400
+ # @param (see info)
300
401
  def debug(message)
301
402
  logger.debug(PROG_NAME) { message }
302
403
  end
303
404
 
304
405
  ##
305
406
  # Parses and sets proxy from a uri
407
+ #
408
+ # @param uri [String, #to_s] The URI to parse and extract proxy details from
409
+ # @return [void]
306
410
  def parse_proxy(uri)
307
411
  proxy = URI.parse(uri)
308
412
  self.proxy_host = proxy.host
@@ -314,7 +418,8 @@ module Bugsnag
314
418
  ##
315
419
  # Sets the maximum allowable amount of breadcrumbs
316
420
  #
317
- # @param [Integer] the new maximum breadcrumb limit
421
+ # @param new_max_breadcrumbs [Integer] the new maximum breadcrumb limit
422
+ # @return [void]
318
423
  def max_breadcrumbs=(new_max_breadcrumbs)
319
424
  @max_breadcrumbs = new_max_breadcrumbs
320
425
  breadcrumbs.max_items = new_max_breadcrumbs
@@ -330,9 +435,10 @@ module Bugsnag
330
435
 
331
436
  # Sets the notification endpoint
332
437
  #
333
- # @param new_notify_endpoint [String] The URL to deliver error notifications to
334
- #
335
438
  # @deprecated Use {#set_endpoints} instead
439
+ #
440
+ # @param new_notify_endpoint [String] The URL to deliver error notifications to
441
+ # @return [void]
336
442
  def endpoint=(new_notify_endpoint)
337
443
  warn("The 'endpoint' configuration option is deprecated. The 'set_endpoints' method should be used instead")
338
444
  set_endpoints(new_notify_endpoint, session_endpoint) # Pass the existing session_endpoint through so it doesn't get overwritten
@@ -341,9 +447,10 @@ module Bugsnag
341
447
  ##
342
448
  # Sets the sessions endpoint
343
449
  #
344
- # @param new_session_endpoint [String] The URL to deliver session notifications to
345
- #
346
450
  # @deprecated Use {#set_endpoints} instead
451
+ #
452
+ # @param new_session_endpoint [String] The URL to deliver session notifications to
453
+ # @return [void]
347
454
  def session_endpoint=(new_session_endpoint)
348
455
  warn("The 'session_endpoint' configuration option is deprecated. The 'set_endpoints' method should be used instead")
349
456
  set_endpoints(notify_endpoint, new_session_endpoint) # Pass the existing notify_endpoint through so it doesn't get overwritten
@@ -354,13 +461,16 @@ module Bugsnag
354
461
  #
355
462
  # @param new_notify_endpoint [String] The URL to deliver error notifications to
356
463
  # @param new_session_endpoint [String] The URL to deliver session notifications to
464
+ # @return [void]
357
465
  def set_endpoints(new_notify_endpoint, new_session_endpoint)
358
466
  @notify_endpoint = new_notify_endpoint
359
467
  @session_endpoint = new_session_endpoint
360
468
  end
361
469
 
362
470
  ##
363
- # Disables session tracking and delivery. Cannot be undone
471
+ # Disables session tracking and delivery. Cannot be undone
472
+ #
473
+ # @return [void]
364
474
  def disable_sessions
365
475
  self.auto_capture_sessions = false
366
476
  @enable_sessions = false
@@ -375,7 +485,7 @@ module Bugsnag
375
485
  # Returning false from an on_error callback will cause the error to be ignored
376
486
  # and will prevent any remaining callbacks from being called
377
487
  #
378
- # @param callback [Proc]
488
+ # @param callback [Proc, Method, #call]
379
489
  # @return [void]
380
490
  def add_on_error(callback)
381
491
  middleware.use(callback)
@@ -384,10 +494,10 @@ module Bugsnag
384
494
  ##
385
495
  # Remove the given callback from the list of on_error callbacks
386
496
  #
387
- # Note that this must be the same Proc instance that was passed to
497
+ # Note that this must be the same instance that was passed to
388
498
  # {#add_on_error}, otherwise it will not be removed
389
499
  #
390
- # @param callback [Proc]
500
+ # @param callback [Proc, Method, #call]
391
501
  # @return [void]
392
502
  def remove_on_error(callback)
393
503
  middleware.remove(callback)
@@ -58,7 +58,7 @@ module Bugsnag
58
58
  def default_headers
59
59
  {
60
60
  "Content-Type" => "application/json",
61
- "Bugsnag-Sent-At" => Time.now().utc().strftime('%Y-%m-%dT%H:%M:%S')
61
+ "Bugsnag-Sent-At" => Time.now.utc.iso8601(3)
62
62
  }
63
63
  end
64
64
  end
@@ -4,7 +4,7 @@ require 'json'
4
4
 
5
5
 
6
6
  module Bugsnag
7
- module Helpers
7
+ module Helpers # rubocop:todo Metrics/ModuleLength
8
8
  MAX_STRING_LENGTH = 3072
9
9
  MAX_PAYLOAD_LENGTH = 512000
10
10
  MAX_ARRAY_LENGTH = 80
@@ -19,8 +19,12 @@ module Bugsnag
19
19
 
20
20
  return value unless payload_too_long?(value)
21
21
 
22
+ # Truncate exception messages
23
+ reduced_value = truncate_exception_messages(value)
24
+ return reduced_value unless payload_too_long?(reduced_value)
25
+
22
26
  # Trim metadata
23
- reduced_value = trim_metadata(value)
27
+ reduced_value = trim_metadata(reduced_value)
24
28
  return reduced_value unless payload_too_long?(reduced_value)
25
29
 
26
30
  # Trim code from stacktrace
@@ -71,6 +75,15 @@ module Bugsnag
71
75
 
72
76
  TRUNCATION_INFO = '[TRUNCATED]'
73
77
 
78
+ ##
79
+ # Truncate exception messages
80
+ def self.truncate_exception_messages(payload)
81
+ extract_exception(payload) do |exception|
82
+ exception[:message] = trim_as_string(exception[:message])
83
+ end
84
+ payload
85
+ end
86
+
74
87
  ##
75
88
  # Remove all code from stacktraces
76
89
  def self.trim_stacktrace_code(payload)
@@ -94,11 +107,11 @@ module Bugsnag
94
107
 
95
108
  ##
96
109
  # Wrapper for trimming stacktraces
97
- def self.extract_exception(payload)
110
+ def self.extract_exception(payload, &block)
98
111
  valid_payload = payload.is_a?(Hash) && payload[:events].respond_to?(:map)
99
112
  return unless valid_payload && block_given?
100
113
  payload[:events].each do |event|
101
- event[:exceptions].each { |exception| yield exception }
114
+ event[:exceptions].each(&block)
102
115
  end
103
116
  end
104
117
 
@@ -127,6 +127,8 @@ module Bugsnag
127
127
  end
128
128
  end
129
129
 
130
- ##
131
- # Add the subscriber to the global Mongo monitoring object
132
- Mongo::Monitoring::Global.subscribe(Mongo::Monitoring::COMMAND, Bugsnag::MongoBreadcrumbSubscriber.new)
130
+ if defined?(Mongo::Monitoring)
131
+ ##
132
+ # Add the subscriber to the global Mongo monitoring object
133
+ Mongo::Monitoring::Global.subscribe(Mongo::Monitoring::COMMAND, Bugsnag::MongoBreadcrumbSubscriber.new)
134
+ end
@@ -38,6 +38,8 @@ module Bugsnag::Rails
38
38
  :type => Bugsnag::Breadcrumbs::PROCESS_BREADCRUMB_TYPE,
39
39
  :allowed_data => [
40
40
  :name,
41
+ # :connection_id is no longer provided in Rails 6.1+ but we can get it
42
+ # from the :connection key of the event instead
41
43
  :connection_id,
42
44
  :cached
43
45
  ]
@@ -9,11 +9,44 @@ require "bugsnag/integrations/rails/rails_breadcrumbs"
9
9
 
10
10
  module Bugsnag
11
11
  class Railtie < ::Rails::Railtie
12
-
13
12
  FRAMEWORK_ATTRIBUTES = {
14
13
  :framework => "Rails"
15
14
  }
16
15
 
16
+ ##
17
+ # Subscribes to an ActiveSupport event, leaving a breadcrumb when it triggers
18
+ #
19
+ # @api private
20
+ # @param event [Hash] details of the event to subscribe to
21
+ def event_subscription(event)
22
+ ActiveSupport::Notifications.subscribe(event[:id]) do |*, event_id, data|
23
+ filtered_data = data.slice(*event[:allowed_data])
24
+ filtered_data[:event_name] = event[:id]
25
+ filtered_data[:event_id] = event_id
26
+
27
+ if event[:id] == "sql.active_record"
28
+ if data.key?(:binds)
29
+ binds = data[:binds].each_with_object({}) { |bind, output| output[bind.name] = '?' if defined?(bind.name) }
30
+ filtered_data[:binds] = JSON.dump(binds) unless binds.empty?
31
+ end
32
+
33
+ # Rails < 6.1 included connection_id in the event data, but now
34
+ # includes the connection object instead
35
+ if data.key?(:connection) && !data.key?(:connection_id)
36
+ # the connection ID is the object_id of the connection object
37
+ filtered_data[:connection_id] = data[:connection].object_id
38
+ end
39
+ end
40
+
41
+ Bugsnag.leave_breadcrumb(
42
+ event[:message],
43
+ filtered_data,
44
+ event[:type],
45
+ :auto
46
+ )
47
+ end
48
+ end
49
+
17
50
  rake_tasks do
18
51
  require "bugsnag/integrations/rake"
19
52
  load "bugsnag/tasks/bugsnag.rake"
@@ -80,28 +113,5 @@ module Bugsnag
80
113
  Bugsnag.configuration.warn("Unable to add Bugsnag::Rack middleware as the middleware stack is frozen")
81
114
  end
82
115
  end
83
-
84
- ##
85
- # Subscribes to an ActiveSupport event, leaving a breadcrumb when it triggers
86
- #
87
- # @api private
88
- # @param event [Hash] details of the event to subscribe to
89
- def event_subscription(event)
90
- ActiveSupport::Notifications.subscribe(event[:id]) do |*, event_id, data|
91
- filtered_data = data.slice(*event[:allowed_data])
92
- filtered_data[:event_name] = event[:id]
93
- filtered_data[:event_id] = event_id
94
- if event[:id] == "sql.active_record" && data.key?(:binds)
95
- binds = data[:binds].each_with_object({}) { |bind, output| output[bind.name] = '?' if defined?(bind.name) }
96
- filtered_data[:binds] = JSON.dump(binds) unless binds.empty?
97
- end
98
- Bugsnag.leave_breadcrumb(
99
- event[:message],
100
- filtered_data,
101
- event[:type],
102
- :auto
103
- )
104
- end
105
- end
106
116
  end
107
117
  end
@@ -58,16 +58,23 @@ Resque::Failure::Bugsnag = Bugsnag::Resque
58
58
  # Auto-load the failure backend
59
59
  Bugsnag::Resque.add_failure_backend
60
60
 
61
- if Resque::Worker.new(:bugsnag_fork_check).fork_per_job?
61
+ worker = Resque::Worker.new(:bugsnag_fork_check)
62
+
63
+ # If at_exit hooks are not enabled then we can't use the thread queue delivery
64
+ # method because it relies on an at_exit hook to ensure the queue is flushed
65
+ can_use_thread_queue = worker.respond_to?(:run_at_exit_hooks) && worker.run_at_exit_hooks
66
+ default_delivery_method = can_use_thread_queue ? :thread_queue : :synchronous
67
+
68
+ if worker.fork_per_job?
62
69
  Resque.after_fork do
63
70
  Bugsnag.configuration.detected_app_type = "resque"
64
- Bugsnag.configuration.default_delivery_method = :synchronous
71
+ Bugsnag.configuration.default_delivery_method = default_delivery_method
65
72
  Bugsnag.configuration.runtime_versions["resque"] = ::Resque::VERSION
66
73
  end
67
74
  else
68
75
  Resque.before_first_fork do
69
76
  Bugsnag.configuration.detected_app_type = "resque"
70
- Bugsnag.configuration.default_delivery_method = :synchronous
77
+ Bugsnag.configuration.default_delivery_method = default_delivery_method
71
78
  Bugsnag.configuration.runtime_versions["resque"] = ::Resque::VERSION
72
79
  end
73
80
  end
@@ -14,7 +14,6 @@ module Bugsnag
14
14
  def initialize
15
15
  Bugsnag.configuration.internal_middleware.use(Bugsnag::Middleware::Sidekiq)
16
16
  Bugsnag.configuration.detected_app_type = "sidekiq"
17
- Bugsnag.configuration.default_delivery_method = :synchronous
18
17
  Bugsnag.configuration.runtime_versions["sidekiq"] = ::Sidekiq::VERSION
19
18
  end
20
19
 
@@ -9,6 +9,7 @@ module Bugsnag::Middleware
9
9
  "ActionController::UnknownAction",
10
10
  "ActionController::UnknownFormat",
11
11
  "ActionController::UnknownHttpMethod",
12
+ "ActionDispatch::Http::MimeNegotiation::InvalidType",
12
13
  "ActiveRecord::RecordNotFound",
13
14
  "CGI::Session::CookieStore::TamperedWithCookie",
14
15
  "Mongoid::Errors::DocumentNotFound",
@@ -131,8 +131,8 @@ module Bugsnag
131
131
  #
132
132
  # @return [Array<Proc>]
133
133
  def middleware_procs
134
- # Split the middleware into separate lists of Procs and Classes
135
- procs, classes = @middlewares.partition {|middleware| middleware.is_a?(Proc) }
134
+ # Split the middleware into separate lists of callables (e.g. Proc, Lambda, Method) and Classes
135
+ callables, classes = @middlewares.partition {|middleware| middleware.respond_to?(:call) }
136
136
 
137
137
  # Wrap the classes in a proc that, when called, news up the middleware and
138
138
  # passes the next middleware in the queue
@@ -140,12 +140,12 @@ module Bugsnag
140
140
  proc {|next_middleware| middleware.new(next_middleware) }
141
141
  end
142
142
 
143
- # Wrap the list of procs in a proc that, when called, wraps them in an
143
+ # Wrap the list of callables in a proc that, when called, wraps them in an
144
144
  # 'OnErrorCallbacks' instance that also has a reference to the next middleware
145
- wrapped_procs = proc {|next_middleware| OnErrorCallbacks.new(next_middleware, procs) }
145
+ wrapped_callables = proc {|next_middleware| OnErrorCallbacks.new(next_middleware, callables) }
146
146
 
147
- # Return the combined middleware and wrapped procs
148
- middleware_instances.push(wrapped_procs)
147
+ # Return the combined middleware and wrapped callables
148
+ middleware_instances.push(wrapped_callables)
149
149
  end
150
150
  end
151
151
  end
@@ -19,24 +19,87 @@ module Bugsnag
19
19
 
20
20
  CURRENT_PAYLOAD_VERSION = "4.0"
21
21
 
22
- attr_reader :unhandled
22
+ # Whether this report is for a handled or unhandled error
23
+ # @return [Boolean]
24
+ attr_reader :unhandled
25
+
26
+ # Your Integration API Key
27
+ # @see Configuration#api_key
28
+ # @return [String, nil]
23
29
  attr_accessor :api_key
30
+
31
+ # The type of application executing the current code
32
+ # @see Configuration#app_type
33
+ # @return [String, nil]
24
34
  attr_accessor :app_type
35
+
36
+ # The current version of your application
37
+ # @return [String, nil]
25
38
  attr_accessor :app_version
39
+
40
+ # The list of breadcrumbs attached to this report
41
+ # @return [Array<Breadcrumb>]
26
42
  attr_accessor :breadcrumbs
43
+
44
+ # @api private
45
+ # @return [Configuration]
27
46
  attr_accessor :configuration
47
+
48
+ # Additional context for this report
49
+ # @return [String, nil]
28
50
  attr_accessor :context
51
+
52
+ # The delivery method that will be used for this report
53
+ # @see Configuration#delivery_method
54
+ # @return [Symbol]
29
55
  attr_accessor :delivery_method
56
+
57
+ # The list of exceptions in this report
58
+ # @return [Array<Hash>]
30
59
  attr_accessor :exceptions
60
+
61
+ # @see Configuration#hostname
62
+ # @return [String]
31
63
  attr_accessor :hostname
64
+
65
+ # @api private
66
+ # @see Configuration#runtime_versions
67
+ # @return [Hash{String => String}]
32
68
  attr_accessor :runtime_versions
69
+
70
+ # All errors with the same grouping hash will be grouped in the Bugsnag app
71
+ # @return [String]
33
72
  attr_accessor :grouping_hash
73
+
74
+ # Arbitrary metadata attached to this report
75
+ # @return [Hash]
34
76
  attr_accessor :meta_data
77
+
78
+ # The raw Exception instances for this report
79
+ # @see #exceptions
80
+ # @return [Array<Exception>]
35
81
  attr_accessor :raw_exceptions
82
+
83
+ # The current stage of the release process, e.g. 'development', production'
84
+ # @see Configuration#release_stage
85
+ # @return [String, nil]
36
86
  attr_accessor :release_stage
87
+
88
+ # The session that active when this report was generated
89
+ # @see SessionTracker#get_current_session
90
+ # @return [Hash]
37
91
  attr_accessor :session
92
+
93
+ # The severity of this report, e.g. 'error', 'warning'
94
+ # @return [String]
38
95
  attr_accessor :severity
96
+
97
+ # @api private
98
+ # @return [Hash]
39
99
  attr_accessor :severity_reason
100
+
101
+ # The current user when this report was generated
102
+ # @return [Hash]
40
103
  attr_accessor :user
41
104
 
42
105
  ##
@@ -66,6 +129,12 @@ module Bugsnag
66
129
 
67
130
  ##
68
131
  # Add a new metadata tab to this notification.
132
+ #
133
+ # @param name [String, #to_s] The name of the tab to add
134
+ # @param value [Hash, Object] The value to add to the tab. If the tab already
135
+ # exists, this will be merged with the existing values. If a Hash is not
136
+ # given, the value will be placed into the 'custom' tab
137
+ # @return [void]
69
138
  def add_tab(name, value)
70
139
  return if name.nil?
71
140
 
@@ -81,6 +150,9 @@ module Bugsnag
81
150
 
82
151
  ##
83
152
  # Removes a metadata tab from this notification.
153
+ #
154
+ # @param name [String]
155
+ # @return [void]
84
156
  def remove_tab(name)
85
157
  return if name.nil?
86
158
 
@@ -89,6 +161,8 @@ module Bugsnag
89
161
 
90
162
  ##
91
163
  # Builds and returns the exception payload for this notification.
164
+ #
165
+ # @return [Hash]
92
166
  def as_json
93
167
  # Build the payload's exception event
94
168
  payload_event = {
@@ -129,28 +203,36 @@ module Bugsnag
129
203
 
130
204
  ##
131
205
  # Returns the headers required for the notification.
206
+ #
207
+ # @return [Hash{String => String}]
132
208
  def headers
133
209
  {
134
210
  "Bugsnag-Api-Key" => api_key,
135
211
  "Bugsnag-Payload-Version" => CURRENT_PAYLOAD_VERSION,
136
- "Bugsnag-Sent-At" => Time.now().utc().strftime('%Y-%m-%dT%H:%M:%S')
212
+ "Bugsnag-Sent-At" => Time.now.utc.iso8601(3)
137
213
  }
138
214
  end
139
215
 
140
216
  ##
141
217
  # Whether this report should be ignored and not sent.
218
+ #
219
+ # @return [Boolean]
142
220
  def ignore?
143
221
  @should_ignore
144
222
  end
145
223
 
146
224
  ##
147
225
  # Data set on the configuration to be attached to every error notification.
226
+ #
227
+ # @return [Hash]
148
228
  def request_data
149
229
  configuration.request_data
150
230
  end
151
231
 
152
232
  ##
153
233
  # Tells the client this report should not be sent.
234
+ #
235
+ # @return [void]
154
236
  def ignore!
155
237
  @should_ignore = true
156
238
  end
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.16.0
4
+ version: 6.21.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - James Smith
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-08-12 00:00:00.000000000 Z
11
+ date: 2021-06-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: concurrent-ruby
@@ -33,6 +33,7 @@ extra_rdoc_files:
33
33
  - README.md
34
34
  - CHANGELOG.md
35
35
  files:
36
+ - ".yardopts"
36
37
  - CHANGELOG.md
37
38
  - LICENSE.txt
38
39
  - README.md
@@ -108,7 +109,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
108
109
  - !ruby/object:Gem::Version
109
110
  version: '0'
110
111
  requirements: []
111
- rubygems_version: 3.1.2
112
+ rubygems_version: 3.2.11
112
113
  signing_key:
113
114
  specification_version: 4
114
115
  summary: Ruby notifier for bugsnag.com