sentry-ruby 5.10.0 → 5.17.3
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 +4 -4
- data/Gemfile +2 -13
- data/README.md +10 -10
- data/Rakefile +1 -1
- data/lib/sentry/background_worker.rb +9 -2
- data/lib/sentry/backpressure_monitor.rb +75 -0
- data/lib/sentry/backtrace.rb +7 -3
- data/lib/sentry/breadcrumb.rb +8 -2
- data/lib/sentry/check_in_event.rb +60 -0
- data/lib/sentry/client.rb +88 -17
- data/lib/sentry/configuration.rb +66 -12
- data/lib/sentry/cron/configuration.rb +23 -0
- data/lib/sentry/cron/monitor_check_ins.rb +75 -0
- data/lib/sentry/cron/monitor_config.rb +53 -0
- data/lib/sentry/cron/monitor_schedule.rb +42 -0
- data/lib/sentry/dsn.rb +1 -1
- data/lib/sentry/envelope.rb +19 -2
- data/lib/sentry/error_event.rb +2 -2
- data/lib/sentry/event.rb +14 -36
- data/lib/sentry/hub.rb +70 -2
- data/lib/sentry/integrable.rb +10 -0
- data/lib/sentry/interface.rb +1 -0
- data/lib/sentry/interfaces/exception.rb +5 -3
- data/lib/sentry/interfaces/mechanism.rb +20 -0
- data/lib/sentry/interfaces/request.rb +2 -2
- data/lib/sentry/interfaces/single_exception.rb +10 -6
- data/lib/sentry/interfaces/stacktrace_builder.rb +8 -0
- data/lib/sentry/metrics/aggregator.rb +276 -0
- data/lib/sentry/metrics/configuration.rb +47 -0
- data/lib/sentry/metrics/counter_metric.rb +25 -0
- data/lib/sentry/metrics/distribution_metric.rb +25 -0
- data/lib/sentry/metrics/gauge_metric.rb +35 -0
- data/lib/sentry/metrics/local_aggregator.rb +53 -0
- data/lib/sentry/metrics/metric.rb +19 -0
- data/lib/sentry/metrics/set_metric.rb +28 -0
- data/lib/sentry/metrics/timing.rb +43 -0
- data/lib/sentry/metrics.rb +55 -0
- data/lib/sentry/net/http.rb +25 -22
- data/lib/sentry/profiler.rb +18 -7
- data/lib/sentry/propagation_context.rb +135 -0
- data/lib/sentry/puma.rb +12 -5
- data/lib/sentry/rack/capture_exceptions.rb +7 -5
- data/lib/sentry/rake.rb +3 -14
- data/lib/sentry/redis.rb +8 -3
- data/lib/sentry/release_detector.rb +1 -1
- data/lib/sentry/scope.rb +36 -15
- data/lib/sentry/session.rb +2 -2
- data/lib/sentry/session_flusher.rb +1 -6
- data/lib/sentry/span.rb +54 -3
- data/lib/sentry/test_helper.rb +18 -12
- data/lib/sentry/transaction.rb +33 -33
- data/lib/sentry/transaction_event.rb +5 -3
- data/lib/sentry/transport/configuration.rb +73 -1
- data/lib/sentry/transport/http_transport.rb +68 -37
- data/lib/sentry/transport/spotlight_transport.rb +50 -0
- data/lib/sentry/transport.rb +27 -37
- data/lib/sentry/utils/argument_checking_helper.rb +12 -0
- data/lib/sentry/utils/real_ip.rb +1 -1
- data/lib/sentry/utils/request_id.rb +1 -1
- data/lib/sentry/version.rb +1 -1
- data/lib/sentry-ruby.rb +96 -26
- data/sentry-ruby.gemspec +1 -0
- metadata +35 -2
data/lib/sentry/configuration.rb
CHANGED
@@ -7,6 +7,8 @@ require 'sentry/utils/custom_inspection'
|
|
7
7
|
require "sentry/dsn"
|
8
8
|
require "sentry/release_detector"
|
9
9
|
require "sentry/transport/configuration"
|
10
|
+
require "sentry/cron/configuration"
|
11
|
+
require "sentry/metrics/configuration"
|
10
12
|
require "sentry/linecache"
|
11
13
|
require "sentry/interfaces/stacktrace_builder"
|
12
14
|
|
@@ -40,6 +42,13 @@ module Sentry
|
|
40
42
|
# @return [Integer]
|
41
43
|
attr_accessor :background_worker_threads
|
42
44
|
|
45
|
+
# The maximum queue size for the background worker.
|
46
|
+
# Jobs will be rejected above this limit.
|
47
|
+
#
|
48
|
+
# Default is {BackgroundWorker::DEFAULT_MAX_QUEUE}.
|
49
|
+
# @return [Integer]
|
50
|
+
attr_accessor :background_worker_max_queue
|
51
|
+
|
43
52
|
# a proc/lambda that takes an array of stack traces
|
44
53
|
# it'll be used to silence (reduce) backtrace of the exception
|
45
54
|
#
|
@@ -142,6 +151,14 @@ module Sentry
|
|
142
151
|
# @return [Boolean]
|
143
152
|
attr_accessor :include_local_variables
|
144
153
|
|
154
|
+
# Whether to capture events and traces into Spotlight. Default is false.
|
155
|
+
# If you set this to true, Sentry will send events and traces to the local
|
156
|
+
# Sidecar proxy at http://localhost:8969/stream.
|
157
|
+
# If you want to use a different Sidecar proxy address, set this to String
|
158
|
+
# with the proxy URL.
|
159
|
+
# @return [Boolean, String]
|
160
|
+
attr_accessor :spotlight
|
161
|
+
|
145
162
|
# @deprecated Use {#include_local_variables} instead.
|
146
163
|
alias_method :capture_exception_frame_locals, :include_local_variables
|
147
164
|
|
@@ -211,10 +228,18 @@ module Sentry
|
|
211
228
|
# @return [String]
|
212
229
|
attr_accessor :server_name
|
213
230
|
|
214
|
-
#
|
215
|
-
# @return [Transport]
|
231
|
+
# Transport related configuration.
|
232
|
+
# @return [Transport::Configuration]
|
216
233
|
attr_reader :transport
|
217
234
|
|
235
|
+
# Cron related configuration.
|
236
|
+
# @return [Cron::Configuration]
|
237
|
+
attr_reader :cron
|
238
|
+
|
239
|
+
# Metrics related configuration.
|
240
|
+
# @return [Metrics::Configuration]
|
241
|
+
attr_reader :metrics
|
242
|
+
|
218
243
|
# Take a float between 0.0 and 1.0 as the sample rate for tracing events (transactions).
|
219
244
|
# @return [Float, nil]
|
220
245
|
attr_reader :traces_sample_rate
|
@@ -243,6 +268,17 @@ module Sentry
|
|
243
268
|
# @return [Boolean]
|
244
269
|
attr_accessor :auto_session_tracking
|
245
270
|
|
271
|
+
# Whether to downsample transactions automatically because of backpressure.
|
272
|
+
# Starts a new monitor thread to check health of the SDK every 10 seconds.
|
273
|
+
# Default is false
|
274
|
+
# @return [Boolean]
|
275
|
+
attr_accessor :enable_backpressure_handling
|
276
|
+
|
277
|
+
# Allowlist of outgoing request targets to which sentry-trace and baggage headers are attached.
|
278
|
+
# Default is all (/.*/)
|
279
|
+
# @return [Array<String, Regexp>]
|
280
|
+
attr_accessor :trace_propagation_targets
|
281
|
+
|
246
282
|
# The instrumenter to use, :sentry or :otel
|
247
283
|
# @return [Symbol]
|
248
284
|
attr_reader :instrumenter
|
@@ -253,6 +289,11 @@ module Sentry
|
|
253
289
|
# @return [Float, nil]
|
254
290
|
attr_reader :profiles_sample_rate
|
255
291
|
|
292
|
+
# Array of patches to apply.
|
293
|
+
# Default is {DEFAULT_PATCHES}
|
294
|
+
# @return [Array<Symbol>]
|
295
|
+
attr_accessor :enabled_patches
|
296
|
+
|
256
297
|
# these are not config options
|
257
298
|
# @!visibility private
|
258
299
|
attr_reader :errors, :gem_specs
|
@@ -275,11 +316,11 @@ module Sentry
|
|
275
316
|
'Sinatra::NotFound'
|
276
317
|
].freeze
|
277
318
|
|
278
|
-
RACK_ENV_WHITELIST_DEFAULT = %w
|
319
|
+
RACK_ENV_WHITELIST_DEFAULT = %w[
|
279
320
|
REMOTE_ADDR
|
280
321
|
SERVER_NAME
|
281
322
|
SERVER_PORT
|
282
|
-
|
323
|
+
].freeze
|
283
324
|
|
284
325
|
HEROKU_DYNO_METADATA_MESSAGE = "You are running on Heroku but haven't enabled Dyno Metadata. For Sentry's "\
|
285
326
|
"release detection to work correctly, please run `heroku labs:enable runtime-dyno-metadata`".freeze
|
@@ -290,6 +331,10 @@ module Sentry
|
|
290
331
|
|
291
332
|
INSTRUMENTERS = [:sentry, :otel]
|
292
333
|
|
334
|
+
PROPAGATION_TARGETS_MATCH_ALL = /.*/.freeze
|
335
|
+
|
336
|
+
DEFAULT_PATCHES = %i[redis puma http].freeze
|
337
|
+
|
293
338
|
class << self
|
294
339
|
# Post initialization callbacks are called at the end of initialization process
|
295
340
|
# allowing extending the configuration of sentry-ruby by multiple extensions
|
@@ -297,7 +342,7 @@ module Sentry
|
|
297
342
|
@post_initialization_callbacks ||= []
|
298
343
|
end
|
299
344
|
|
300
|
-
|
345
|
+
# allow extensions to add their hooks to the Configuration class
|
301
346
|
def add_post_initialization_callback(&block)
|
302
347
|
post_initialization_callbacks << block
|
303
348
|
end
|
@@ -307,6 +352,7 @@ module Sentry
|
|
307
352
|
self.app_dirs_pattern = nil
|
308
353
|
self.debug = false
|
309
354
|
self.background_worker_threads = Concurrent.processor_count
|
355
|
+
self.background_worker_max_queue = BackgroundWorker::DEFAULT_MAX_QUEUE
|
310
356
|
self.backtrace_cleanup_callback = nil
|
311
357
|
self.max_breadcrumbs = BreadcrumbBuffer::DEFAULT_SIZE
|
312
358
|
self.breadcrumbs_logger = []
|
@@ -328,10 +374,14 @@ module Sentry
|
|
328
374
|
self.skip_rake_integration = false
|
329
375
|
self.send_client_reports = true
|
330
376
|
self.auto_session_tracking = true
|
377
|
+
self.enable_backpressure_handling = false
|
331
378
|
self.trusted_proxies = []
|
332
379
|
self.dsn = ENV['SENTRY_DSN']
|
380
|
+
self.spotlight = false
|
333
381
|
self.server_name = server_name_from_env
|
334
382
|
self.instrumenter = :sentry
|
383
|
+
self.trace_propagation_targets = [PROPAGATION_TARGETS_MATCH_ALL]
|
384
|
+
self.enabled_patches = DEFAULT_PATCHES.dup
|
335
385
|
|
336
386
|
self.before_send = nil
|
337
387
|
self.before_send_transaction = nil
|
@@ -340,6 +390,8 @@ module Sentry
|
|
340
390
|
self.enable_tracing = nil
|
341
391
|
|
342
392
|
@transport = Transport::Configuration.new
|
393
|
+
@cron = Cron::Configuration.new
|
394
|
+
@metrics = Metrics::Configuration.new
|
343
395
|
@gem_specs = Hash[Gem::Specification.map { |spec| [spec.name, spec.version.to_s] }] if Gem::Specification.respond_to?(:map)
|
344
396
|
|
345
397
|
run_post_initialization_callbacks
|
@@ -428,11 +480,15 @@ module Sentry
|
|
428
480
|
|
429
481
|
def profiles_sample_rate=(profiles_sample_rate)
|
430
482
|
raise ArgumentError, "profiles_sample_rate must be a Numeric or nil" unless is_numeric_or_nil?(profiles_sample_rate)
|
431
|
-
|
483
|
+
log_warn("Please make sure to include the 'stackprof' gem in your Gemfile to use Profiling with Sentry.") unless defined?(StackProf)
|
432
484
|
@profiles_sample_rate = profiles_sample_rate
|
433
485
|
end
|
434
486
|
|
435
487
|
def sending_allowed?
|
488
|
+
spotlight || sending_to_dsn_allowed?
|
489
|
+
end
|
490
|
+
|
491
|
+
def sending_to_dsn_allowed?
|
436
492
|
@errors = []
|
437
493
|
|
438
494
|
valid? && capture_in_environment?
|
@@ -444,6 +500,10 @@ module Sentry
|
|
444
500
|
Random.rand < sample_rate
|
445
501
|
end
|
446
502
|
|
503
|
+
def session_tracking?
|
504
|
+
auto_session_tracking && enabled_in_current_env?
|
505
|
+
end
|
506
|
+
|
447
507
|
def exception_class_allowed?(exc)
|
448
508
|
if exc.is_a?(Sentry::Error)
|
449
509
|
# Try to prevent error reporting loops
|
@@ -520,12 +580,6 @@ module Sentry
|
|
520
580
|
|
521
581
|
private
|
522
582
|
|
523
|
-
def check_callable!(name, value)
|
524
|
-
unless value == nil || value.respond_to?(:call)
|
525
|
-
raise ArgumentError, "#{name} must be callable (or nil to disable)"
|
526
|
-
end
|
527
|
-
end
|
528
|
-
|
529
583
|
def init_dsn(dsn_string)
|
530
584
|
return if dsn_string.nil? || dsn_string.empty?
|
531
585
|
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Sentry
|
4
|
+
module Cron
|
5
|
+
class Configuration
|
6
|
+
# Defaults set here will apply to all {Cron::MonitorConfig} objects unless overwritten.
|
7
|
+
|
8
|
+
# How long (in minutes) after the expected checkin time will we wait
|
9
|
+
# until we consider the checkin to have been missed.
|
10
|
+
# @return [Integer, nil]
|
11
|
+
attr_accessor :default_checkin_margin
|
12
|
+
|
13
|
+
# How long (in minutes) is the checkin allowed to run for in in_progress
|
14
|
+
# before it is considered failed.
|
15
|
+
# @return [Integer, nil]
|
16
|
+
attr_accessor :default_max_runtime
|
17
|
+
|
18
|
+
# tz database style timezone string
|
19
|
+
# @return [String, nil]
|
20
|
+
attr_accessor :default_timezone
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
module Sentry
|
2
|
+
module Cron
|
3
|
+
module MonitorCheckIns
|
4
|
+
MAX_SLUG_LENGTH = 50
|
5
|
+
|
6
|
+
module Patch
|
7
|
+
def perform(*args, **opts)
|
8
|
+
slug = self.class.sentry_monitor_slug
|
9
|
+
monitor_config = self.class.sentry_monitor_config
|
10
|
+
|
11
|
+
check_in_id = Sentry.capture_check_in(slug,
|
12
|
+
:in_progress,
|
13
|
+
monitor_config: monitor_config)
|
14
|
+
|
15
|
+
start = Sentry.utc_now.to_i
|
16
|
+
|
17
|
+
begin
|
18
|
+
# need to do this on ruby <= 2.6 sadly
|
19
|
+
ret = method(:perform).super_method.arity == 0 ? super() : super
|
20
|
+
duration = Sentry.utc_now.to_i - start
|
21
|
+
|
22
|
+
Sentry.capture_check_in(slug,
|
23
|
+
:ok,
|
24
|
+
check_in_id: check_in_id,
|
25
|
+
duration: duration,
|
26
|
+
monitor_config: monitor_config)
|
27
|
+
|
28
|
+
ret
|
29
|
+
rescue Exception
|
30
|
+
duration = Sentry.utc_now.to_i - start
|
31
|
+
|
32
|
+
Sentry.capture_check_in(slug,
|
33
|
+
:error,
|
34
|
+
check_in_id: check_in_id,
|
35
|
+
duration: duration,
|
36
|
+
monitor_config: monitor_config)
|
37
|
+
|
38
|
+
raise
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
module ClassMethods
|
44
|
+
def sentry_monitor_check_ins(slug: nil, monitor_config: nil)
|
45
|
+
if monitor_config && Sentry.configuration
|
46
|
+
cron_config = Sentry.configuration.cron
|
47
|
+
monitor_config.checkin_margin ||= cron_config.default_checkin_margin
|
48
|
+
monitor_config.max_runtime ||= cron_config.default_max_runtime
|
49
|
+
monitor_config.timezone ||= cron_config.default_timezone
|
50
|
+
end
|
51
|
+
|
52
|
+
@sentry_monitor_slug = slug
|
53
|
+
@sentry_monitor_config = monitor_config
|
54
|
+
|
55
|
+
prepend Patch
|
56
|
+
end
|
57
|
+
|
58
|
+
def sentry_monitor_slug(name: self.name)
|
59
|
+
@sentry_monitor_slug ||= begin
|
60
|
+
slug = name.gsub('::', '-').downcase
|
61
|
+
slug[-MAX_SLUG_LENGTH..-1] || slug
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def sentry_monitor_config
|
66
|
+
@sentry_monitor_config
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def self.included(base)
|
71
|
+
base.extend(ClassMethods)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'sentry/cron/monitor_schedule'
|
4
|
+
|
5
|
+
module Sentry
|
6
|
+
module Cron
|
7
|
+
class MonitorConfig
|
8
|
+
# The monitor schedule configuration
|
9
|
+
# @return [MonitorSchedule::Crontab, MonitorSchedule::Interval]
|
10
|
+
attr_accessor :schedule
|
11
|
+
|
12
|
+
# How long (in minutes) after the expected checkin time will we wait
|
13
|
+
# until we consider the checkin to have been missed.
|
14
|
+
# @return [Integer, nil]
|
15
|
+
attr_accessor :checkin_margin
|
16
|
+
|
17
|
+
# How long (in minutes) is the checkin allowed to run for in in_progress
|
18
|
+
# before it is considered failed.
|
19
|
+
# @return [Integer, nil]
|
20
|
+
attr_accessor :max_runtime
|
21
|
+
|
22
|
+
# tz database style timezone string
|
23
|
+
# @return [String, nil]
|
24
|
+
attr_accessor :timezone
|
25
|
+
|
26
|
+
def initialize(schedule, checkin_margin: nil, max_runtime: nil, timezone: nil)
|
27
|
+
@schedule = schedule
|
28
|
+
@checkin_margin = checkin_margin
|
29
|
+
@max_runtime = max_runtime
|
30
|
+
@timezone = timezone
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.from_crontab(crontab, **options)
|
34
|
+
new(MonitorSchedule::Crontab.new(crontab), **options)
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.from_interval(num, unit, **options)
|
38
|
+
return nil unless MonitorSchedule::Interval::VALID_UNITS.include?(unit)
|
39
|
+
|
40
|
+
new(MonitorSchedule::Interval.new(num, unit), **options)
|
41
|
+
end
|
42
|
+
|
43
|
+
def to_hash
|
44
|
+
{
|
45
|
+
schedule: schedule.to_hash,
|
46
|
+
checkin_margin: checkin_margin,
|
47
|
+
max_runtime: max_runtime,
|
48
|
+
timezone: timezone
|
49
|
+
}.compact
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Sentry
|
4
|
+
module Cron
|
5
|
+
module MonitorSchedule
|
6
|
+
class Crontab
|
7
|
+
# A crontab formatted string such as "0 * * * *".
|
8
|
+
# @return [String]
|
9
|
+
attr_accessor :value
|
10
|
+
|
11
|
+
def initialize(value)
|
12
|
+
@value = value
|
13
|
+
end
|
14
|
+
|
15
|
+
def to_hash
|
16
|
+
{ type: :crontab, value: value }
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
class Interval
|
21
|
+
# The number representing duration of the interval.
|
22
|
+
# @return [Integer]
|
23
|
+
attr_accessor :value
|
24
|
+
|
25
|
+
# The unit representing duration of the interval.
|
26
|
+
# @return [Symbol]
|
27
|
+
attr_accessor :unit
|
28
|
+
|
29
|
+
VALID_UNITS = %i[year month week day hour minute]
|
30
|
+
|
31
|
+
def initialize(value, unit)
|
32
|
+
@value = value
|
33
|
+
@unit = unit
|
34
|
+
end
|
35
|
+
|
36
|
+
def to_hash
|
37
|
+
{ type: :interval, value: value, unit: unit }
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
data/lib/sentry/dsn.rb
CHANGED
@@ -5,7 +5,7 @@ require "uri"
|
|
5
5
|
module Sentry
|
6
6
|
class DSN
|
7
7
|
PORT_MAP = { 'http' => 80, 'https' => 443 }.freeze
|
8
|
-
REQUIRED_ATTRIBUTES = %w
|
8
|
+
REQUIRED_ATTRIBUTES = %w[host path public_key project_id].freeze
|
9
9
|
|
10
10
|
attr_reader :scheme, :secret_key, :port, *REQUIRED_ATTRIBUTES
|
11
11
|
|
data/lib/sentry/envelope.rb
CHANGED
@@ -5,7 +5,7 @@ module Sentry
|
|
5
5
|
class Envelope
|
6
6
|
class Item
|
7
7
|
STACKTRACE_FRAME_LIMIT_ON_OVERSIZED_PAYLOAD = 500
|
8
|
-
MAX_SERIALIZED_PAYLOAD_SIZE = 1024 *
|
8
|
+
MAX_SERIALIZED_PAYLOAD_SIZE = 1024 * 1000
|
9
9
|
|
10
10
|
attr_accessor :headers, :payload
|
11
11
|
|
@@ -18,8 +18,25 @@ module Sentry
|
|
18
18
|
@headers[:type] || 'event'
|
19
19
|
end
|
20
20
|
|
21
|
+
# rate limits and client reports use the data_category rather than envelope item type
|
22
|
+
def self.data_category(type)
|
23
|
+
case type
|
24
|
+
when 'session', 'attachment', 'transaction', 'profile' then type
|
25
|
+
when 'sessions' then 'session'
|
26
|
+
when 'check_in' then 'monitor'
|
27
|
+
when 'statsd', 'metric_meta' then 'metric_bucket'
|
28
|
+
when 'event' then 'error'
|
29
|
+
when 'client_report' then 'internal'
|
30
|
+
else 'default'
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def data_category
|
35
|
+
self.class.data_category(type)
|
36
|
+
end
|
37
|
+
|
21
38
|
def to_s
|
22
|
-
[JSON.generate(@headers), JSON.generate(@payload)].join("\n")
|
39
|
+
[JSON.generate(@headers), @payload.is_a?(String) ? @payload : JSON.generate(@payload)].join("\n")
|
23
40
|
end
|
24
41
|
|
25
42
|
def serialize
|
data/lib/sentry/error_event.rb
CHANGED
@@ -27,12 +27,12 @@ module Sentry
|
|
27
27
|
end
|
28
28
|
|
29
29
|
# @!visibility private
|
30
|
-
def add_exception_interface(exception)
|
30
|
+
def add_exception_interface(exception, mechanism:)
|
31
31
|
if exception.respond_to?(:sentry_context)
|
32
32
|
@extra.merge!(exception.sentry_context)
|
33
33
|
end
|
34
34
|
|
35
|
-
@exception = Sentry::ExceptionInterface.build(exception: exception, stacktrace_builder: @stacktrace_builder)
|
35
|
+
@exception = Sentry::ExceptionInterface.build(exception: exception, stacktrace_builder: @stacktrace_builder, mechanism: mechanism)
|
36
36
|
end
|
37
37
|
end
|
38
38
|
end
|
data/lib/sentry/event.rb
CHANGED
@@ -14,16 +14,16 @@ module Sentry
|
|
14
14
|
class Event
|
15
15
|
TYPE = "event"
|
16
16
|
# These are readable attributes.
|
17
|
-
SERIALIZEABLE_ATTRIBUTES = %i
|
17
|
+
SERIALIZEABLE_ATTRIBUTES = %i[
|
18
18
|
event_id level timestamp
|
19
19
|
release environment server_name modules
|
20
20
|
message user tags contexts extra
|
21
21
|
fingerprint breadcrumbs transaction transaction_info
|
22
22
|
platform sdk type
|
23
|
-
|
23
|
+
]
|
24
24
|
|
25
25
|
# These are writable attributes.
|
26
|
-
WRITER_ATTRIBUTES = SERIALIZEABLE_ATTRIBUTES - %i
|
26
|
+
WRITER_ATTRIBUTES = SERIALIZEABLE_ATTRIBUTES - %i[type timestamp level]
|
27
27
|
|
28
28
|
MAX_MESSAGE_SIZE_IN_BYTES = 1024 * 8
|
29
29
|
|
@@ -37,6 +37,11 @@ module Sentry
|
|
37
37
|
# @return [RequestInterface]
|
38
38
|
attr_reader :request
|
39
39
|
|
40
|
+
# Dynamic Sampling Context (DSC) that gets attached
|
41
|
+
# as the trace envelope header in the transport.
|
42
|
+
# @return [Hash, nil]
|
43
|
+
attr_accessor :dynamic_sampling_context
|
44
|
+
|
40
45
|
# @param configuration [Configuration]
|
41
46
|
# @param integration_meta [Hash, nil]
|
42
47
|
# @param message [String, nil]
|
@@ -54,6 +59,7 @@ module Sentry
|
|
54
59
|
@tags = {}
|
55
60
|
|
56
61
|
@fingerprint = []
|
62
|
+
@dynamic_sampling_context = nil
|
57
63
|
|
58
64
|
# configuration data that's directly used by events
|
59
65
|
@server_name = configuration.server_name
|
@@ -70,34 +76,6 @@ module Sentry
|
|
70
76
|
@message = (message || "").byteslice(0..MAX_MESSAGE_SIZE_IN_BYTES)
|
71
77
|
end
|
72
78
|
|
73
|
-
class << self
|
74
|
-
# @!visibility private
|
75
|
-
def get_log_message(event_hash)
|
76
|
-
message = event_hash[:message] || event_hash['message']
|
77
|
-
|
78
|
-
return message unless message.nil? || message.empty?
|
79
|
-
|
80
|
-
message = get_message_from_exception(event_hash)
|
81
|
-
|
82
|
-
return message unless message.nil? || message.empty?
|
83
|
-
|
84
|
-
message = event_hash[:transaction] || event_hash["transaction"]
|
85
|
-
|
86
|
-
return message unless message.nil? || message.empty?
|
87
|
-
|
88
|
-
'<no message value>'
|
89
|
-
end
|
90
|
-
|
91
|
-
# @!visibility private
|
92
|
-
def get_message_from_exception(event_hash)
|
93
|
-
if exception = event_hash.dig(:exception, :values, 0)
|
94
|
-
"#{exception[:type]}: #{exception[:value]}"
|
95
|
-
elsif exception = event_hash.dig("exception", "values", 0)
|
96
|
-
"#{exception["type"]}: #{exception["value"]}"
|
97
|
-
end
|
98
|
-
end
|
99
|
-
end
|
100
|
-
|
101
79
|
# @deprecated This method will be removed in v5.0.0. Please just use Sentry.configuration
|
102
80
|
# @return [Configuration]
|
103
81
|
def configuration
|
@@ -167,11 +145,11 @@ module Sentry
|
|
167
145
|
# REMOTE_ADDR to determine the Event IP, and must use other headers instead.
|
168
146
|
def calculate_real_ip_from_rack(env)
|
169
147
|
Utils::RealIp.new(
|
170
|
-
:
|
171
|
-
:
|
172
|
-
:
|
173
|
-
:
|
174
|
-
:
|
148
|
+
remote_addr: env["REMOTE_ADDR"],
|
149
|
+
client_ip: env["HTTP_CLIENT_IP"],
|
150
|
+
real_ip: env["HTTP_X_REAL_IP"],
|
151
|
+
forwarded_for: env["HTTP_X_FORWARDED_FOR"],
|
152
|
+
trusted_proxies: @trusted_proxies
|
175
153
|
).calculate_ip
|
176
154
|
end
|
177
155
|
end
|
data/lib/sentry/hub.rb
CHANGED
@@ -156,6 +156,30 @@ module Sentry
|
|
156
156
|
capture_event(event, **options, &block)
|
157
157
|
end
|
158
158
|
|
159
|
+
def capture_check_in(slug, status, **options)
|
160
|
+
check_argument_type!(slug, ::String)
|
161
|
+
check_argument_includes!(status, Sentry::CheckInEvent::VALID_STATUSES)
|
162
|
+
|
163
|
+
return unless current_client
|
164
|
+
|
165
|
+
options[:hint] ||= {}
|
166
|
+
options[:hint][:slug] = slug
|
167
|
+
|
168
|
+
event = current_client.event_from_check_in(
|
169
|
+
slug,
|
170
|
+
status,
|
171
|
+
options[:hint],
|
172
|
+
duration: options.delete(:duration),
|
173
|
+
monitor_config: options.delete(:monitor_config),
|
174
|
+
check_in_id: options.delete(:check_in_id)
|
175
|
+
)
|
176
|
+
|
177
|
+
return unless event
|
178
|
+
|
179
|
+
capture_event(event, **options)
|
180
|
+
event.check_in_id
|
181
|
+
end
|
182
|
+
|
159
183
|
def capture_event(event, **options, &block)
|
160
184
|
check_argument_type!(event, Sentry::Event)
|
161
185
|
|
@@ -178,7 +202,7 @@ module Sentry
|
|
178
202
|
configuration.log_debug(event.to_json_compatible)
|
179
203
|
end
|
180
204
|
|
181
|
-
@last_event_id = event&.event_id
|
205
|
+
@last_event_id = event&.event_id if event.is_a?(Sentry::ErrorEvent)
|
182
206
|
event
|
183
207
|
end
|
184
208
|
|
@@ -221,7 +245,7 @@ module Sentry
|
|
221
245
|
end
|
222
246
|
|
223
247
|
def with_session_tracking(&block)
|
224
|
-
return yield unless configuration.
|
248
|
+
return yield unless configuration.session_tracking?
|
225
249
|
|
226
250
|
start_session
|
227
251
|
yield
|
@@ -229,6 +253,50 @@ module Sentry
|
|
229
253
|
end_session
|
230
254
|
end
|
231
255
|
|
256
|
+
def get_traceparent
|
257
|
+
return nil unless current_scope
|
258
|
+
|
259
|
+
current_scope.get_span&.to_sentry_trace ||
|
260
|
+
current_scope.propagation_context.get_traceparent
|
261
|
+
end
|
262
|
+
|
263
|
+
def get_baggage
|
264
|
+
return nil unless current_scope
|
265
|
+
|
266
|
+
current_scope.get_span&.to_baggage ||
|
267
|
+
current_scope.propagation_context.get_baggage&.serialize
|
268
|
+
end
|
269
|
+
|
270
|
+
def get_trace_propagation_headers
|
271
|
+
headers = {}
|
272
|
+
|
273
|
+
traceparent = get_traceparent
|
274
|
+
headers[SENTRY_TRACE_HEADER_NAME] = traceparent if traceparent
|
275
|
+
|
276
|
+
baggage = get_baggage
|
277
|
+
headers[BAGGAGE_HEADER_NAME] = baggage if baggage && !baggage.empty?
|
278
|
+
|
279
|
+
headers
|
280
|
+
end
|
281
|
+
|
282
|
+
def continue_trace(env, **options)
|
283
|
+
configure_scope { |s| s.generate_propagation_context(env) }
|
284
|
+
|
285
|
+
return nil unless configuration.tracing_enabled?
|
286
|
+
|
287
|
+
propagation_context = current_scope.propagation_context
|
288
|
+
return nil unless propagation_context.incoming_trace
|
289
|
+
|
290
|
+
Transaction.new(
|
291
|
+
hub: self,
|
292
|
+
trace_id: propagation_context.trace_id,
|
293
|
+
parent_span_id: propagation_context.parent_span_id,
|
294
|
+
parent_sampled: propagation_context.parent_sampled,
|
295
|
+
baggage: propagation_context.baggage,
|
296
|
+
**options
|
297
|
+
)
|
298
|
+
end
|
299
|
+
|
232
300
|
private
|
233
301
|
|
234
302
|
def current_layer
|
data/lib/sentry/integrable.rb
CHANGED
@@ -14,6 +14,10 @@ module Sentry
|
|
14
14
|
def capture_exception(exception, **options, &block)
|
15
15
|
options[:hint] ||= {}
|
16
16
|
options[:hint][:integration] = integration_name
|
17
|
+
|
18
|
+
# within an integration, we usually intercept uncaught exceptions so we set handled to false.
|
19
|
+
options[:hint][:mechanism] ||= Sentry::Mechanism.new(type: integration_name, handled: false)
|
20
|
+
|
17
21
|
Sentry.capture_exception(exception, **options, &block)
|
18
22
|
end
|
19
23
|
|
@@ -22,5 +26,11 @@ module Sentry
|
|
22
26
|
options[:hint][:integration] = integration_name
|
23
27
|
Sentry.capture_message(message, **options, &block)
|
24
28
|
end
|
29
|
+
|
30
|
+
def capture_check_in(slug, status, **options, &block)
|
31
|
+
options[:hint] ||= {}
|
32
|
+
options[:hint][:integration] = integration_name
|
33
|
+
Sentry.capture_check_in(slug, status, **options, &block)
|
34
|
+
end
|
25
35
|
end
|
26
36
|
end
|
data/lib/sentry/interface.rb
CHANGED