bugsnag 6.22.1 → 6.24.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +93 -0
- data/VERSION +1 -1
- data/lib/bugsnag/breadcrumb_type.rb +14 -0
- data/lib/bugsnag/breadcrumbs/breadcrumb.rb +34 -1
- data/lib/bugsnag/breadcrumbs/breadcrumbs.rb +1 -0
- data/lib/bugsnag/breadcrumbs/on_breadcrumb_callback_list.rb +50 -0
- data/lib/bugsnag/cleaner.rb +31 -18
- data/lib/bugsnag/configuration.rb +240 -22
- data/lib/bugsnag/delivery/synchronous.rb +2 -2
- data/lib/bugsnag/delivery/thread_queue.rb +2 -2
- data/lib/bugsnag/endpoint_configuration.rb +11 -0
- data/lib/bugsnag/endpoint_validator.rb +80 -0
- data/lib/bugsnag/error.rb +25 -0
- data/lib/bugsnag/event.rb +7 -0
- data/lib/bugsnag/integrations/railtie.rb +27 -2
- data/lib/bugsnag/integrations/resque.rb +10 -6
- data/lib/bugsnag/middleware/active_job.rb +1 -1
- data/lib/bugsnag/middleware/delayed_job.rb +1 -1
- data/lib/bugsnag/middleware/exception_meta_data.rb +2 -0
- data/lib/bugsnag/middleware/rack_request.rb +84 -19
- data/lib/bugsnag/middleware/rails3_request.rb +2 -2
- data/lib/bugsnag/middleware/rake.rb +1 -1
- data/lib/bugsnag/middleware/session_data.rb +3 -1
- data/lib/bugsnag/middleware/sidekiq.rb +1 -1
- data/lib/bugsnag/report.rb +166 -6
- data/lib/bugsnag/session_tracker.rb +52 -12
- data/lib/bugsnag/stacktrace.rb +10 -1
- data/lib/bugsnag/tasks/bugsnag.rake +1 -1
- data/lib/bugsnag/utility/duplicator.rb +124 -0
- data/lib/bugsnag/utility/metadata_delegate.rb +102 -0
- data/lib/bugsnag.rb +126 -4
- metadata +14 -6
@@ -12,6 +12,9 @@ require "bugsnag/middleware/session_data"
|
|
12
12
|
require "bugsnag/middleware/breadcrumbs"
|
13
13
|
require "bugsnag/utility/circular_buffer"
|
14
14
|
require "bugsnag/breadcrumbs/breadcrumbs"
|
15
|
+
require "bugsnag/breadcrumbs/on_breadcrumb_callback_list"
|
16
|
+
require "bugsnag/endpoint_configuration"
|
17
|
+
require "bugsnag/endpoint_validator"
|
15
18
|
|
16
19
|
module Bugsnag
|
17
20
|
class Configuration
|
@@ -24,6 +27,7 @@ module Bugsnag
|
|
24
27
|
attr_accessor :release_stage
|
25
28
|
|
26
29
|
# A list of which release stages should cause notifications to be sent
|
30
|
+
# @deprecated Use {#enabled_release_stages} instead
|
27
31
|
# @return [Array<String>, nil]
|
28
32
|
attr_accessor :notify_release_stages
|
29
33
|
|
@@ -52,9 +56,20 @@ module Bugsnag
|
|
52
56
|
|
53
57
|
# A list of keys that should be filtered out from the report and breadcrumb
|
54
58
|
# metadata before sending them to Bugsnag
|
59
|
+
# @deprecated Use {#redacted_keys} instead
|
55
60
|
# @return [Set<String, Regexp>]
|
56
61
|
attr_accessor :meta_data_filters
|
57
62
|
|
63
|
+
# A set of keys that should be redacted from the report and breadcrumb
|
64
|
+
# metadata before sending them to Bugsnag
|
65
|
+
#
|
66
|
+
# When adding strings, keys that are equal to the string (ignoring case)
|
67
|
+
# will be redacted. When adding regular expressions, any keys which match
|
68
|
+
# the regular expression will be redacted
|
69
|
+
#
|
70
|
+
# @return [Set<String, Regexp>]
|
71
|
+
attr_accessor :redacted_keys
|
72
|
+
|
58
73
|
# The logger to use for Bugsnag log messages
|
59
74
|
# @return [Logger]
|
60
75
|
attr_accessor :logger
|
@@ -104,6 +119,7 @@ module Bugsnag
|
|
104
119
|
attr_accessor :discard_classes
|
105
120
|
|
106
121
|
# Whether Bugsnag should automatically record sessions
|
122
|
+
# @deprecated Use {#auto_track_sessions} instead
|
107
123
|
# @return [Boolean]
|
108
124
|
attr_accessor :auto_capture_sessions
|
109
125
|
|
@@ -111,21 +127,23 @@ module Bugsnag
|
|
111
127
|
# @return [Set<Class, Proc>]
|
112
128
|
attr_accessor :ignore_classes
|
113
129
|
|
114
|
-
# The
|
115
|
-
# @return [
|
116
|
-
attr_reader :
|
117
|
-
alias :endpoint :notify_endpoint
|
130
|
+
# The URLs to send events and sessions to
|
131
|
+
# @return [EndpointConfiguration]
|
132
|
+
attr_reader :endpoints
|
118
133
|
|
119
|
-
#
|
120
|
-
# @
|
121
|
-
|
134
|
+
# Whether events will be delivered
|
135
|
+
# @api private
|
136
|
+
# @return [Boolean]
|
137
|
+
attr_reader :enable_events
|
122
138
|
|
123
139
|
# Whether sessions will be delivered
|
140
|
+
# @api private
|
124
141
|
# @return [Boolean]
|
125
142
|
attr_reader :enable_sessions
|
126
143
|
|
127
144
|
# A list of strings indicating allowable automatic breadcrumb types
|
128
|
-
# @
|
145
|
+
# @deprecated Use {#enabled_breadcrumb_types} instead
|
146
|
+
# @see Bugsnag::BreadcrumbType
|
129
147
|
# @return [Array<String>]
|
130
148
|
attr_accessor :enabled_automatic_breadcrumb_types
|
131
149
|
|
@@ -137,14 +155,37 @@ module Bugsnag
|
|
137
155
|
# @return [Integer]
|
138
156
|
attr_reader :max_breadcrumbs
|
139
157
|
|
140
|
-
#
|
158
|
+
# @deprecated Use {vendor_paths} instead
|
141
159
|
# @return [Regexp]
|
142
160
|
attr_accessor :vendor_path
|
143
161
|
|
162
|
+
# An array of paths within the {project_root} that should not be considered
|
163
|
+
# as "in project"
|
164
|
+
#
|
165
|
+
# These paths should be relative to the {project_root} and will only match
|
166
|
+
# whole directory names
|
167
|
+
#
|
168
|
+
# @return [Array<String>]
|
169
|
+
attr_accessor :vendor_paths
|
170
|
+
|
171
|
+
# The default context for all future events
|
172
|
+
# Setting this will disable automatic context setting
|
173
|
+
# @return [String, nil]
|
174
|
+
attr_accessor :context
|
175
|
+
|
176
|
+
# Global metadata added to every event
|
177
|
+
# @return [Hash]
|
178
|
+
attr_reader :metadata
|
179
|
+
|
144
180
|
# @api private
|
145
181
|
# @return [Array<String>]
|
146
182
|
attr_reader :scopes_to_filter
|
147
183
|
|
184
|
+
# Expose on_breadcrumb_callbacks internally for Bugsnag.leave_breadcrumb
|
185
|
+
# @api private
|
186
|
+
# @return [Breadcrumbs::OnBreadcrumbCallbackList]
|
187
|
+
attr_reader :on_breadcrumb_callbacks
|
188
|
+
|
148
189
|
API_KEY_REGEX = /[0-9a-f]{32}/i
|
149
190
|
THREAD_LOCAL_NAME = "bugsnag_req_data"
|
150
191
|
|
@@ -180,6 +221,7 @@ module Bugsnag
|
|
180
221
|
self.send_environment = false
|
181
222
|
self.send_code = true
|
182
223
|
self.meta_data_filters = Set.new(DEFAULT_META_DATA_FILTERS)
|
224
|
+
@redacted_keys = Set.new
|
183
225
|
self.scopes_to_filter = DEFAULT_SCOPES_TO_FILTER
|
184
226
|
self.hostname = default_hostname
|
185
227
|
self.runtime_versions = {}
|
@@ -193,16 +235,20 @@ module Bugsnag
|
|
193
235
|
# All valid breadcrumb types should be allowable initially
|
194
236
|
self.enabled_automatic_breadcrumb_types = Bugsnag::Breadcrumbs::VALID_BREADCRUMB_TYPES.dup
|
195
237
|
self.before_breadcrumb_callbacks = []
|
238
|
+
@on_breadcrumb_callbacks = Breadcrumbs::OnBreadcrumbCallbackList.new(self)
|
196
239
|
|
197
240
|
# Store max_breadcrumbs here instead of outputting breadcrumbs.max_items
|
198
241
|
# to avoid infinite recursion when creating breadcrumb buffer
|
199
242
|
@max_breadcrumbs = DEFAULT_MAX_BREADCRUMBS
|
200
243
|
|
201
|
-
|
202
|
-
|
203
|
-
@
|
244
|
+
@endpoints = EndpointConfiguration.new(DEFAULT_NOTIFY_ENDPOINT, DEFAULT_SESSION_ENDPOINT)
|
245
|
+
|
246
|
+
@enable_events = true
|
204
247
|
@enable_sessions = true
|
205
248
|
|
249
|
+
@metadata = {}
|
250
|
+
@metadata_delegate = Utility::MetadataDelegate.new
|
251
|
+
|
206
252
|
# SystemExit and SignalException are common Exception types seen with
|
207
253
|
# successful exits and are not automatically reported to Bugsnag
|
208
254
|
# TODO move these defaults into `discard_classes` when `ignore_classes`
|
@@ -222,6 +268,7 @@ module Bugsnag
|
|
222
268
|
# Stacktrace lines that matches regex will be marked as "out of project"
|
223
269
|
# will only appear in the full trace.
|
224
270
|
self.vendor_path = DEFAULT_VENDOR_PATH
|
271
|
+
@vendor_paths = []
|
225
272
|
|
226
273
|
# Set up logging
|
227
274
|
self.logger = Logger.new(STDOUT)
|
@@ -389,15 +436,23 @@ module Bugsnag
|
|
389
436
|
##
|
390
437
|
# Logs a warning level message
|
391
438
|
#
|
392
|
-
# @param
|
439
|
+
# @param message [String, #to_s] The message to log
|
393
440
|
def warn(message)
|
394
441
|
logger.warn(PROG_NAME) { message }
|
395
442
|
end
|
396
443
|
|
444
|
+
##
|
445
|
+
# Logs an error level message
|
446
|
+
#
|
447
|
+
# @param message [String, #to_s] The message to log
|
448
|
+
def error(message)
|
449
|
+
logger.error(PROG_NAME) { message }
|
450
|
+
end
|
451
|
+
|
397
452
|
##
|
398
453
|
# Logs a debug level message
|
399
454
|
#
|
400
|
-
# @param
|
455
|
+
# @param message [String, #to_s] The message to log
|
401
456
|
def debug(message)
|
402
457
|
logger.debug(PROG_NAME) { message }
|
403
458
|
end
|
@@ -426,33 +481,54 @@ module Bugsnag
|
|
426
481
|
end
|
427
482
|
|
428
483
|
##
|
429
|
-
# Returns the
|
484
|
+
# Returns the current list of breadcrumbs
|
485
|
+
#
|
486
|
+
# This is a per-thread circular buffer, containing at most 'max_breadcrumbs'
|
487
|
+
# breadcrumbs
|
430
488
|
#
|
431
|
-
# @return [Bugsnag::Utility::CircularBuffer]
|
489
|
+
# @return [Bugsnag::Utility::CircularBuffer]
|
432
490
|
def breadcrumbs
|
433
491
|
request_data[:breadcrumbs] ||= Bugsnag::Utility::CircularBuffer.new(@max_breadcrumbs)
|
434
492
|
end
|
435
493
|
|
494
|
+
# The URL error notifications will be delivered to
|
495
|
+
# @!attribute notify_endpoint
|
496
|
+
# @return [String]
|
497
|
+
# @deprecated Use {#endpoints} instead
|
498
|
+
def notify_endpoint
|
499
|
+
@endpoints.notify
|
500
|
+
end
|
501
|
+
|
502
|
+
alias :endpoint :notify_endpoint
|
503
|
+
|
436
504
|
# Sets the notification endpoint
|
437
505
|
#
|
438
|
-
# @deprecated Use {#
|
506
|
+
# @deprecated Use {#endpoints} instead
|
439
507
|
#
|
440
508
|
# @param new_notify_endpoint [String] The URL to deliver error notifications to
|
441
509
|
# @return [void]
|
442
510
|
def endpoint=(new_notify_endpoint)
|
443
|
-
warn("The 'endpoint' configuration option is deprecated.
|
511
|
+
warn("The 'endpoint' configuration option is deprecated. Set both endpoints with the 'endpoints=' method instead")
|
444
512
|
set_endpoints(new_notify_endpoint, session_endpoint) # Pass the existing session_endpoint through so it doesn't get overwritten
|
445
513
|
end
|
446
514
|
|
515
|
+
# The URL session notifications will be delivered to
|
516
|
+
# @!attribute session_endpoint
|
517
|
+
# @return [String]
|
518
|
+
# @deprecated Use {#endpoints} instead
|
519
|
+
def session_endpoint
|
520
|
+
@endpoints.sessions
|
521
|
+
end
|
522
|
+
|
447
523
|
##
|
448
524
|
# Sets the sessions endpoint
|
449
525
|
#
|
450
|
-
# @deprecated Use {#
|
526
|
+
# @deprecated Use {#endpoints} instead
|
451
527
|
#
|
452
528
|
# @param new_session_endpoint [String] The URL to deliver session notifications to
|
453
529
|
# @return [void]
|
454
530
|
def session_endpoint=(new_session_endpoint)
|
455
|
-
warn("The 'session_endpoint' configuration option is deprecated.
|
531
|
+
warn("The 'session_endpoint' configuration option is deprecated. Set both endpoints with the 'endpoints=' method instead")
|
456
532
|
set_endpoints(notify_endpoint, new_session_endpoint) # Pass the existing notify_endpoint through so it doesn't get overwritten
|
457
533
|
end
|
458
534
|
|
@@ -462,9 +538,26 @@ module Bugsnag
|
|
462
538
|
# @param new_notify_endpoint [String] The URL to deliver error notifications to
|
463
539
|
# @param new_session_endpoint [String] The URL to deliver session notifications to
|
464
540
|
# @return [void]
|
541
|
+
# @deprecated Use {#endpoints} instead
|
465
542
|
def set_endpoints(new_notify_endpoint, new_session_endpoint)
|
466
|
-
|
467
|
-
|
543
|
+
self.endpoints = EndpointConfiguration.new(new_notify_endpoint, new_session_endpoint)
|
544
|
+
end
|
545
|
+
|
546
|
+
def endpoints=(endpoint_configuration)
|
547
|
+
result = EndpointValidator.validate(endpoint_configuration)
|
548
|
+
|
549
|
+
if result.valid?
|
550
|
+
@enable_events = true
|
551
|
+
@enable_sessions = true
|
552
|
+
else
|
553
|
+
warn(result.reason)
|
554
|
+
|
555
|
+
@enable_events = result.keep_events_enabled_for_backwards_compatibility?
|
556
|
+
@enable_sessions = false
|
557
|
+
end
|
558
|
+
|
559
|
+
# use the given endpoints even if they are invalid
|
560
|
+
@endpoints = endpoint_configuration
|
468
561
|
end
|
469
562
|
|
470
563
|
##
|
@@ -503,6 +596,131 @@ module Bugsnag
|
|
503
596
|
middleware.remove(callback)
|
504
597
|
end
|
505
598
|
|
599
|
+
##
|
600
|
+
# Add the given callback to the list of on_breadcrumb callbacks
|
601
|
+
#
|
602
|
+
# The on_breadcrumb callbacks will be called when a breadcrumb is left and
|
603
|
+
# are passed the {Breadcrumbs::Breadcrumb Breadcrumb} object
|
604
|
+
#
|
605
|
+
# Returning false from an on_breadcrumb callback will cause the breadcrumb
|
606
|
+
# to be ignored and will prevent any remaining callbacks from being called
|
607
|
+
#
|
608
|
+
# @param callback [Proc, Method, #call]
|
609
|
+
# @return [void]
|
610
|
+
def add_on_breadcrumb(callback)
|
611
|
+
@on_breadcrumb_callbacks.add(callback)
|
612
|
+
end
|
613
|
+
|
614
|
+
##
|
615
|
+
# Remove the given callback from the list of on_breadcrumb callbacks
|
616
|
+
#
|
617
|
+
# Note that this must be the same instance that was passed to
|
618
|
+
# {add_on_breadcrumb}, otherwise it will not be removed
|
619
|
+
#
|
620
|
+
# @param callback [Proc, Method, #call]
|
621
|
+
# @return [void]
|
622
|
+
def remove_on_breadcrumb(callback)
|
623
|
+
@on_breadcrumb_callbacks.remove(callback)
|
624
|
+
end
|
625
|
+
|
626
|
+
##
|
627
|
+
# Add values to metadata
|
628
|
+
#
|
629
|
+
# @overload add_metadata(section, data)
|
630
|
+
# Merges data into the given section of metadata
|
631
|
+
# @param section [String, Symbol]
|
632
|
+
# @param data [Hash]
|
633
|
+
#
|
634
|
+
# @overload add_metadata(section, key, value)
|
635
|
+
# Sets key to value in the given section of metadata. If the value is nil
|
636
|
+
# the key will be deleted
|
637
|
+
# @param section [String, Symbol]
|
638
|
+
# @param key [String, Symbol]
|
639
|
+
# @param value
|
640
|
+
#
|
641
|
+
# @return [void]
|
642
|
+
def add_metadata(section, key_or_data, *args)
|
643
|
+
@mutex.synchronize do
|
644
|
+
@metadata_delegate.add_metadata(@metadata, section, key_or_data, *args)
|
645
|
+
end
|
646
|
+
end
|
647
|
+
|
648
|
+
##
|
649
|
+
# Clear values from metadata
|
650
|
+
#
|
651
|
+
# @overload clear_metadata(section)
|
652
|
+
# Clears the given section of metadata
|
653
|
+
# @param section [String, Symbol]
|
654
|
+
#
|
655
|
+
# @overload clear_metadata(section, key)
|
656
|
+
# Clears the key in the given section of metadata
|
657
|
+
# @param section [String, Symbol]
|
658
|
+
# @param key [String, Symbol]
|
659
|
+
#
|
660
|
+
# @return [void]
|
661
|
+
def clear_metadata(section, *args)
|
662
|
+
@mutex.synchronize do
|
663
|
+
@metadata_delegate.clear_metadata(@metadata, section, *args)
|
664
|
+
end
|
665
|
+
end
|
666
|
+
|
667
|
+
##
|
668
|
+
# Has the context been explicitly set?
|
669
|
+
#
|
670
|
+
# This is necessary to differentiate between the context not being set and
|
671
|
+
# the context being set to 'nil' explicitly
|
672
|
+
#
|
673
|
+
# @api private
|
674
|
+
# @return [Boolean]
|
675
|
+
def context_set?
|
676
|
+
defined?(@context) != nil
|
677
|
+
end
|
678
|
+
|
679
|
+
# TODO: These methods can be a simple attr_accessor when they replace the
|
680
|
+
# methods they are aliasing
|
681
|
+
# NOTE: they are not aliases as YARD doesn't allow documenting the non-alias
|
682
|
+
# as deprecated without also marking the alias as deprecated
|
683
|
+
|
684
|
+
# A list of which release stages should cause notifications to be sent
|
685
|
+
# @!attribute enabled_release_stages
|
686
|
+
# @return [Array<String>, nil]
|
687
|
+
def enabled_release_stages
|
688
|
+
@notify_release_stages
|
689
|
+
end
|
690
|
+
|
691
|
+
# @param release_stages [Array<String>, nil]
|
692
|
+
# @return [void]
|
693
|
+
def enabled_release_stages=(release_stages)
|
694
|
+
@notify_release_stages = release_stages
|
695
|
+
end
|
696
|
+
|
697
|
+
# A list of breadcrumb types that Bugsnag will collect automatically
|
698
|
+
# @!attribute enabled_breadcrumb_types
|
699
|
+
# @see Bugsnag::BreadcrumbType
|
700
|
+
# @return [Array<String>]
|
701
|
+
def enabled_breadcrumb_types
|
702
|
+
@enabled_automatic_breadcrumb_types
|
703
|
+
end
|
704
|
+
|
705
|
+
# @param breadcrumb_types [Array<String>]
|
706
|
+
# @return [void]
|
707
|
+
def enabled_breadcrumb_types=(breadcrumb_types)
|
708
|
+
@enabled_automatic_breadcrumb_types = breadcrumb_types
|
709
|
+
end
|
710
|
+
|
711
|
+
# Whether sessions should be tracked automatically
|
712
|
+
# @!attribute auto_track_sessions
|
713
|
+
# @return [Boolean]
|
714
|
+
def auto_track_sessions
|
715
|
+
@auto_capture_sessions
|
716
|
+
end
|
717
|
+
|
718
|
+
# @param track_sessions [Boolean]
|
719
|
+
# @return [void]
|
720
|
+
def auto_track_sessions=(track_sessions)
|
721
|
+
@auto_capture_sessions = track_sessions
|
722
|
+
end
|
723
|
+
|
506
724
|
private
|
507
725
|
|
508
726
|
attr_writer :scopes_to_filter
|
@@ -18,8 +18,8 @@ module Bugsnag
|
|
18
18
|
# KLUDGE: Since we don't re-raise http exceptions, this breaks rspec
|
19
19
|
raise if e.class.to_s == "RSpec::Expectations::ExpectationNotMetError"
|
20
20
|
|
21
|
-
configuration.
|
22
|
-
configuration.
|
21
|
+
configuration.error("Unable to send information to Bugsnag (#{url}), #{e.inspect}")
|
22
|
+
configuration.error(e.backtrace)
|
23
23
|
end
|
24
24
|
end
|
25
25
|
|
@@ -31,8 +31,8 @@ module Bugsnag
|
|
31
31
|
begin
|
32
32
|
payload = get_payload.call
|
33
33
|
rescue StandardError => e
|
34
|
-
configuration.
|
35
|
-
configuration.
|
34
|
+
configuration.error("Unable to send information to Bugsnag (#{url}), #{e.inspect}")
|
35
|
+
configuration.error(e.backtrace)
|
36
36
|
end
|
37
37
|
|
38
38
|
Synchronous.deliver(url, payload, configuration, options) unless payload.nil?
|
@@ -0,0 +1,80 @@
|
|
1
|
+
module Bugsnag
|
2
|
+
# @api private
|
3
|
+
class EndpointValidator
|
4
|
+
def self.validate(endpoints)
|
5
|
+
# ensure we have an EndpointConfiguration object
|
6
|
+
return Result.missing_urls unless endpoints.is_a?(EndpointConfiguration)
|
7
|
+
|
8
|
+
# check for missing URLs
|
9
|
+
return Result.missing_urls if endpoints.notify.nil? && endpoints.sessions.nil?
|
10
|
+
return Result.missing_notify if endpoints.notify.nil?
|
11
|
+
return Result.missing_session if endpoints.sessions.nil?
|
12
|
+
|
13
|
+
# check for empty URLs
|
14
|
+
return Result.invalid_urls if endpoints.notify.empty? && endpoints.sessions.empty?
|
15
|
+
return Result.invalid_notify if endpoints.notify.empty?
|
16
|
+
return Result.invalid_session if endpoints.sessions.empty?
|
17
|
+
|
18
|
+
Result.valid
|
19
|
+
end
|
20
|
+
|
21
|
+
# @api private
|
22
|
+
class Result
|
23
|
+
# rubocop:disable Layout/LineLength
|
24
|
+
MISSING_URLS = "Invalid configuration. endpoints must be set with both a notify and session URL. Bugsnag will not send any requests.".freeze
|
25
|
+
MISSING_NOTIFY_URL = "Invalid configuration. endpoints.sessions cannot be set without also setting endpoints.notify. Bugsnag will not send any requests.".freeze
|
26
|
+
MISSING_SESSION_URL = "Invalid configuration. endpoints.notify cannot be set without also setting endpoints.sessions. Bugsnag will not send any sessions.".freeze
|
27
|
+
|
28
|
+
INVALID_URLS = "Invalid configuration. endpoints should be valid URLs, got empty strings. Bugsnag will not send any requests.".freeze
|
29
|
+
INVALID_NOTIFY_URL = "Invalid configuration. endpoints.notify should be a valid URL, got empty string. Bugsnag will not send any requests.".freeze
|
30
|
+
INVALID_SESSION_URL = "Invalid configuration. endpoints.sessions should be a valid URL, got empty string. Bugsnag will not send any sessions.".freeze
|
31
|
+
# rubocop:enable Layout/LineLength
|
32
|
+
|
33
|
+
attr_reader :reason
|
34
|
+
|
35
|
+
def initialize(valid, keep_events_enabled_for_backwards_compatibility = true, reason = nil)
|
36
|
+
@valid = valid
|
37
|
+
@keep_events_enabled_for_backwards_compatibility = keep_events_enabled_for_backwards_compatibility
|
38
|
+
@reason = reason
|
39
|
+
end
|
40
|
+
|
41
|
+
def valid?
|
42
|
+
@valid
|
43
|
+
end
|
44
|
+
|
45
|
+
def keep_events_enabled_for_backwards_compatibility?
|
46
|
+
@keep_events_enabled_for_backwards_compatibility
|
47
|
+
end
|
48
|
+
|
49
|
+
# factory functions
|
50
|
+
|
51
|
+
def self.valid
|
52
|
+
new(true)
|
53
|
+
end
|
54
|
+
|
55
|
+
def self.missing_urls
|
56
|
+
new(false, false, MISSING_URLS)
|
57
|
+
end
|
58
|
+
|
59
|
+
def self.missing_notify
|
60
|
+
new(false, false, MISSING_NOTIFY_URL)
|
61
|
+
end
|
62
|
+
|
63
|
+
def self.missing_session
|
64
|
+
new(false, true, MISSING_SESSION_URL)
|
65
|
+
end
|
66
|
+
|
67
|
+
def self.invalid_urls
|
68
|
+
new(false, false, INVALID_URLS)
|
69
|
+
end
|
70
|
+
|
71
|
+
def self.invalid_notify
|
72
|
+
new(false, false, INVALID_NOTIFY_URL)
|
73
|
+
end
|
74
|
+
|
75
|
+
def self.invalid_session
|
76
|
+
new(false, true, INVALID_SESSION_URL)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Bugsnag
|
2
|
+
class Error
|
3
|
+
# @return [String] the error's class name
|
4
|
+
attr_accessor :error_class
|
5
|
+
|
6
|
+
# @return [String] the error's message
|
7
|
+
attr_accessor :error_message
|
8
|
+
|
9
|
+
# @return [Hash] the error's processed stacktrace
|
10
|
+
attr_reader :stacktrace
|
11
|
+
|
12
|
+
# @return [String] the type of error (always "ruby")
|
13
|
+
attr_accessor :type
|
14
|
+
|
15
|
+
# @api private
|
16
|
+
TYPE = "ruby".freeze
|
17
|
+
|
18
|
+
def initialize(error_class, error_message, stacktrace)
|
19
|
+
@error_class = error_class
|
20
|
+
@error_message = error_message
|
21
|
+
@stacktrace = stacktrace
|
22
|
+
@type = TYPE
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -47,6 +47,29 @@ module Bugsnag
|
|
47
47
|
end
|
48
48
|
end
|
49
49
|
|
50
|
+
##
|
51
|
+
# Do we need to rescue (& notify) in Active Record callbacks?
|
52
|
+
#
|
53
|
+
# On Rails versions < 4.2, Rails did not raise errors in AR callbacks
|
54
|
+
# On Rails version 4.2, a config option was added to control this
|
55
|
+
# On Rails version 5.0, the config option was removed and errors in callbacks
|
56
|
+
# always bubble up
|
57
|
+
#
|
58
|
+
# @api private
|
59
|
+
def self.rescue_in_active_record_callbacks?
|
60
|
+
# Rails 5+ will re-raise errors in callbacks, so we don't need to rescue them
|
61
|
+
return false if ::Rails::VERSION::MAJOR > 4
|
62
|
+
|
63
|
+
# before 4.2, errors were always swallowed, so we need to rescue them
|
64
|
+
return true if ::Rails::VERSION::MAJOR < 4
|
65
|
+
|
66
|
+
# a config option was added in 4.2 to control this, but won't exist in 4.0 & 4.1
|
67
|
+
return true unless ActiveRecord::Base.respond_to?(:raise_in_transactional_callbacks)
|
68
|
+
|
69
|
+
# if the config option is false, we need to rescue and notify
|
70
|
+
ActiveRecord::Base.raise_in_transactional_callbacks == false
|
71
|
+
end
|
72
|
+
|
50
73
|
rake_tasks do
|
51
74
|
require "bugsnag/integrations/rake"
|
52
75
|
load "bugsnag/tasks/bugsnag.rake"
|
@@ -70,8 +93,10 @@ module Bugsnag
|
|
70
93
|
end
|
71
94
|
|
72
95
|
ActiveSupport.on_load(:active_record) do
|
73
|
-
|
74
|
-
|
96
|
+
if Bugsnag::Railtie.rescue_in_active_record_callbacks?
|
97
|
+
require "bugsnag/integrations/rails/active_record_rescue"
|
98
|
+
include Bugsnag::Rails::ActiveRecordRescue
|
99
|
+
end
|
75
100
|
end
|
76
101
|
|
77
102
|
ActiveSupport.on_load(:active_job) do
|
@@ -45,18 +45,22 @@ module Bugsnag
|
|
45
45
|
}
|
46
46
|
|
47
47
|
metadata = payload
|
48
|
-
class_name =
|
48
|
+
class_name = metadata['class']
|
49
49
|
|
50
50
|
# when using Active Job the payload "class" will always be the Resque
|
51
|
-
# "JobWrapper",
|
52
|
-
if
|
53
|
-
|
54
|
-
|
51
|
+
# "JobWrapper", so we need to unwrap the actual class name
|
52
|
+
if class_name == "ActiveJob::QueueAdapters::ResqueAdapter::JobWrapper"
|
53
|
+
unwrapped_class_name = metadata['args'][0]['job_class'] rescue nil
|
54
|
+
|
55
|
+
if unwrapped_class_name
|
56
|
+
class_name = unwrapped_class_name
|
57
|
+
metadata['wrapped'] ||= unwrapped_class_name
|
58
|
+
end
|
55
59
|
end
|
56
60
|
|
57
61
|
context = "#{class_name}@#{queue}"
|
58
62
|
report.meta_data.merge!({ context: context, payload: metadata })
|
59
|
-
report.
|
63
|
+
report.automatic_context = context
|
60
64
|
end
|
61
65
|
end
|
62
66
|
end
|
@@ -30,7 +30,7 @@ module Bugsnag::Middleware
|
|
30
30
|
payload_data = construct_job_payload(job.payload_object)
|
31
31
|
|
32
32
|
context = get_context(payload_data, job_data[:active_job])
|
33
|
-
report.
|
33
|
+
report.automatic_context = context unless context.nil?
|
34
34
|
|
35
35
|
job_data[:payload] = payload_data
|
36
36
|
end
|
@@ -16,6 +16,8 @@ module Bugsnag::Middleware
|
|
16
16
|
|
17
17
|
if exception.respond_to?(:bugsnag_context)
|
18
18
|
context = exception.bugsnag_context
|
19
|
+
# note: this should set 'context' not 'automatic_context' as it's a
|
20
|
+
# user-supplied value
|
19
21
|
report.context = context if context.is_a?(String)
|
20
22
|
end
|
21
23
|
|