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