bugsnag 6.16.0 → 6.21.0

Sign up to get free protection for your applications and to get access to all the features.
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