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.
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"