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.
Files changed (63) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +2 -13
  3. data/README.md +10 -10
  4. data/Rakefile +1 -1
  5. data/lib/sentry/background_worker.rb +9 -2
  6. data/lib/sentry/backpressure_monitor.rb +75 -0
  7. data/lib/sentry/backtrace.rb +7 -3
  8. data/lib/sentry/breadcrumb.rb +8 -2
  9. data/lib/sentry/check_in_event.rb +60 -0
  10. data/lib/sentry/client.rb +88 -17
  11. data/lib/sentry/configuration.rb +66 -12
  12. data/lib/sentry/cron/configuration.rb +23 -0
  13. data/lib/sentry/cron/monitor_check_ins.rb +75 -0
  14. data/lib/sentry/cron/monitor_config.rb +53 -0
  15. data/lib/sentry/cron/monitor_schedule.rb +42 -0
  16. data/lib/sentry/dsn.rb +1 -1
  17. data/lib/sentry/envelope.rb +19 -2
  18. data/lib/sentry/error_event.rb +2 -2
  19. data/lib/sentry/event.rb +14 -36
  20. data/lib/sentry/hub.rb +70 -2
  21. data/lib/sentry/integrable.rb +10 -0
  22. data/lib/sentry/interface.rb +1 -0
  23. data/lib/sentry/interfaces/exception.rb +5 -3
  24. data/lib/sentry/interfaces/mechanism.rb +20 -0
  25. data/lib/sentry/interfaces/request.rb +2 -2
  26. data/lib/sentry/interfaces/single_exception.rb +10 -6
  27. data/lib/sentry/interfaces/stacktrace_builder.rb +8 -0
  28. data/lib/sentry/metrics/aggregator.rb +276 -0
  29. data/lib/sentry/metrics/configuration.rb +47 -0
  30. data/lib/sentry/metrics/counter_metric.rb +25 -0
  31. data/lib/sentry/metrics/distribution_metric.rb +25 -0
  32. data/lib/sentry/metrics/gauge_metric.rb +35 -0
  33. data/lib/sentry/metrics/local_aggregator.rb +53 -0
  34. data/lib/sentry/metrics/metric.rb +19 -0
  35. data/lib/sentry/metrics/set_metric.rb +28 -0
  36. data/lib/sentry/metrics/timing.rb +43 -0
  37. data/lib/sentry/metrics.rb +55 -0
  38. data/lib/sentry/net/http.rb +25 -22
  39. data/lib/sentry/profiler.rb +18 -7
  40. data/lib/sentry/propagation_context.rb +135 -0
  41. data/lib/sentry/puma.rb +12 -5
  42. data/lib/sentry/rack/capture_exceptions.rb +7 -5
  43. data/lib/sentry/rake.rb +3 -14
  44. data/lib/sentry/redis.rb +8 -3
  45. data/lib/sentry/release_detector.rb +1 -1
  46. data/lib/sentry/scope.rb +36 -15
  47. data/lib/sentry/session.rb +2 -2
  48. data/lib/sentry/session_flusher.rb +1 -6
  49. data/lib/sentry/span.rb +54 -3
  50. data/lib/sentry/test_helper.rb +18 -12
  51. data/lib/sentry/transaction.rb +33 -33
  52. data/lib/sentry/transaction_event.rb +5 -3
  53. data/lib/sentry/transport/configuration.rb +73 -1
  54. data/lib/sentry/transport/http_transport.rb +68 -37
  55. data/lib/sentry/transport/spotlight_transport.rb +50 -0
  56. data/lib/sentry/transport.rb +27 -37
  57. data/lib/sentry/utils/argument_checking_helper.rb +12 -0
  58. data/lib/sentry/utils/real_ip.rb +1 -1
  59. data/lib/sentry/utils/request_id.rb +1 -1
  60. data/lib/sentry/version.rb +1 -1
  61. data/lib/sentry-ruby.rb +96 -26
  62. data/sentry-ruby.gemspec +1 -0
  63. metadata +35 -2
@@ -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
- # Return a Transport::Configuration object for transport-related configurations.
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
- ).freeze
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
- # allow extensions to add their hooks to the Configuration class
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
- log_info("Please make sure to include the 'stackprof' gem in your Gemfile to use Profiling with Sentry.") unless defined?(StackProf)
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(host path public_key project_id).freeze
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
 
@@ -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 * 200
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
@@ -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(type timestamp level)
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
- :remote_addr => env["REMOTE_ADDR"],
171
- :client_ip => env["HTTP_CLIENT_IP"],
172
- :real_ip => env["HTTP_X_REAL_IP"],
173
- :forwarded_for => env["HTTP_X_FORWARDED_FOR"],
174
- :trusted_proxies => @trusted_proxies
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 unless event.is_a?(Sentry::TransactionEvent)
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.auto_session_tracking
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
@@ -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
@@ -14,3 +14,4 @@ require "sentry/interfaces/request"
14
14
  require "sentry/interfaces/single_exception"
15
15
  require "sentry/interfaces/stacktrace"
16
16
  require "sentry/interfaces/threads"
17
+ require "sentry/interfaces/mechanism"