bugsnag 6.21.0 → 6.25.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.yardopts +1 -0
- data/CHANGELOG.md +137 -0
- data/VERSION +1 -1
- data/bugsnag.gemspec +18 -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/feature_flag.rb +74 -0
- data/lib/bugsnag/integrations/rack.rb +3 -3
- data/lib/bugsnag/integrations/rails/active_job.rb +102 -0
- data/lib/bugsnag/integrations/railtie.rb +36 -3
- data/lib/bugsnag/integrations/resque.rb +17 -3
- data/lib/bugsnag/middleware/active_job.rb +18 -0
- data/lib/bugsnag/middleware/delayed_job.rb +21 -2
- 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/middleware/suggestion_data.rb +9 -7
- data/lib/bugsnag/report.rb +204 -8
- data/lib/bugsnag/session_tracker.rb +52 -12
- data/lib/bugsnag/stacktrace.rb +13 -2
- data/lib/bugsnag/tasks/bugsnag.rake +1 -1
- data/lib/bugsnag/utility/duplicator.rb +124 -0
- data/lib/bugsnag/utility/feature_data_store.rb +41 -0
- data/lib/bugsnag/utility/feature_flag_delegate.rb +89 -0
- data/lib/bugsnag/utility/metadata_delegate.rb +102 -0
- data/lib/bugsnag.rb +143 -5
- metadata +24 -7
@@ -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
|
@@ -0,0 +1,74 @@
|
|
1
|
+
module Bugsnag
|
2
|
+
class FeatureFlag
|
3
|
+
# Get the name of this feature flag
|
4
|
+
#
|
5
|
+
# @return [String]
|
6
|
+
attr_reader :name
|
7
|
+
|
8
|
+
# Get the variant of this feature flag
|
9
|
+
#
|
10
|
+
# @return [String, nil]
|
11
|
+
attr_reader :variant
|
12
|
+
|
13
|
+
# @param name [String] The name of this feature flags
|
14
|
+
# @param variant [String, nil] An optional variant for this flag
|
15
|
+
def initialize(name, variant = nil)
|
16
|
+
@name = name
|
17
|
+
@variant = coerce_variant(variant)
|
18
|
+
end
|
19
|
+
|
20
|
+
def ==(other)
|
21
|
+
self.class == other.class && @name == other.name && @variant == other.variant
|
22
|
+
end
|
23
|
+
|
24
|
+
def hash
|
25
|
+
[@name, @variant].hash
|
26
|
+
end
|
27
|
+
|
28
|
+
# Convert this flag to a hash
|
29
|
+
#
|
30
|
+
# @example With no variant
|
31
|
+
# { "featureFlag" => "name" }
|
32
|
+
#
|
33
|
+
# @example With a variant
|
34
|
+
# { "featureFlag" => "name", "variant" => "variant" }
|
35
|
+
#
|
36
|
+
# @return [Hash{String => String}]
|
37
|
+
def to_h
|
38
|
+
if @variant.nil?
|
39
|
+
{ "featureFlag" => @name }
|
40
|
+
else
|
41
|
+
{ "featureFlag" => @name, "variant" => @variant }
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
# Check if this flag is valid, i.e. has a name that's a String and a variant
|
46
|
+
# that's either nil or a String
|
47
|
+
#
|
48
|
+
# @return [Boolean]
|
49
|
+
def valid?
|
50
|
+
@name.is_a?(String) &&
|
51
|
+
!@name.empty? &&
|
52
|
+
(@variant.nil? || @variant.is_a?(String))
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
# Coerce this variant into a valid value (String or nil)
|
58
|
+
#
|
59
|
+
# If the variant is not already a string or nil, we use #to_s to coerce it.
|
60
|
+
# If #to_s raises, the variant will be set to nil
|
61
|
+
#
|
62
|
+
# @param variant [Object]
|
63
|
+
# @return [String, nil]
|
64
|
+
def coerce_variant(variant)
|
65
|
+
if variant.nil? || variant.is_a?(String)
|
66
|
+
variant
|
67
|
+
else
|
68
|
+
variant.to_s
|
69
|
+
end
|
70
|
+
rescue StandardError
|
71
|
+
nil
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -25,9 +25,9 @@ module Bugsnag
|
|
25
25
|
end
|
26
26
|
|
27
27
|
# Hook up rack-based notification middlewares
|
28
|
-
config.
|
29
|
-
config.
|
30
|
-
config.
|
28
|
+
config.internal_middleware.insert_before(Bugsnag::Middleware::Rails3Request, Bugsnag::Middleware::RackRequest) if defined?(::Rack)
|
29
|
+
config.internal_middleware.use(Bugsnag::Middleware::WardenUser) if defined?(Warden)
|
30
|
+
config.internal_middleware.use(Bugsnag::Middleware::ClearanceUser) if defined?(Clearance)
|
31
31
|
|
32
32
|
# Set environment data for payload
|
33
33
|
# Note we only set the detected app_type if it's not already set. This
|