sentry-ruby 5.4.2 → 5.16.1

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 (47) hide show
  1. checksums.yaml +4 -4
  2. data/.rspec +0 -1
  3. data/Gemfile +13 -14
  4. data/README.md +11 -8
  5. data/Rakefile +8 -1
  6. data/lib/sentry/background_worker.rb +8 -1
  7. data/lib/sentry/backpressure_monitor.rb +75 -0
  8. data/lib/sentry/backtrace.rb +1 -1
  9. data/lib/sentry/baggage.rb +70 -0
  10. data/lib/sentry/breadcrumb.rb +8 -2
  11. data/lib/sentry/check_in_event.rb +60 -0
  12. data/lib/sentry/client.rb +77 -19
  13. data/lib/sentry/configuration.rb +177 -29
  14. data/lib/sentry/cron/configuration.rb +23 -0
  15. data/lib/sentry/cron/monitor_check_ins.rb +75 -0
  16. data/lib/sentry/cron/monitor_config.rb +53 -0
  17. data/lib/sentry/cron/monitor_schedule.rb +42 -0
  18. data/lib/sentry/envelope.rb +2 -5
  19. data/lib/sentry/event.rb +7 -29
  20. data/lib/sentry/hub.rb +100 -4
  21. data/lib/sentry/integrable.rb +6 -0
  22. data/lib/sentry/interfaces/request.rb +6 -16
  23. data/lib/sentry/interfaces/single_exception.rb +13 -3
  24. data/lib/sentry/net/http.rb +37 -46
  25. data/lib/sentry/profiler.rb +233 -0
  26. data/lib/sentry/propagation_context.rb +134 -0
  27. data/lib/sentry/puma.rb +32 -0
  28. data/lib/sentry/rack/capture_exceptions.rb +4 -5
  29. data/lib/sentry/rake.rb +1 -14
  30. data/lib/sentry/redis.rb +41 -23
  31. data/lib/sentry/release_detector.rb +1 -1
  32. data/lib/sentry/scope.rb +81 -16
  33. data/lib/sentry/session.rb +5 -7
  34. data/lib/sentry/span.rb +57 -10
  35. data/lib/sentry/test_helper.rb +19 -11
  36. data/lib/sentry/transaction.rb +183 -30
  37. data/lib/sentry/transaction_event.rb +51 -0
  38. data/lib/sentry/transport/configuration.rb +74 -1
  39. data/lib/sentry/transport/http_transport.rb +68 -37
  40. data/lib/sentry/transport/spotlight_transport.rb +50 -0
  41. data/lib/sentry/transport.rb +39 -24
  42. data/lib/sentry/utils/argument_checking_helper.rb +9 -3
  43. data/lib/sentry/utils/encoding_helper.rb +22 -0
  44. data/lib/sentry/version.rb +1 -1
  45. data/lib/sentry-ruby.rb +116 -41
  46. metadata +14 -3
  47. data/CODE_OF_CONDUCT.md +0 -74
@@ -14,11 +14,19 @@ module Sentry
14
14
  RATE_LIMIT_HEADER = "x-sentry-rate-limits"
15
15
  USER_AGENT = "sentry-ruby/#{Sentry::VERSION}"
16
16
 
17
+ # The list of errors ::Net::HTTP is known to raise
18
+ # See https://github.com/ruby/ruby/blob/b0c639f249165d759596f9579fa985cb30533de6/lib/bundler/fetcher.rb#L281-L286
19
+ HTTP_ERRORS = [
20
+ Timeout::Error, EOFError, SocketError, Errno::ENETDOWN, Errno::ENETUNREACH,
21
+ Errno::EINVAL, Errno::ECONNRESET, Errno::ETIMEDOUT, Errno::EAGAIN,
22
+ Net::HTTPBadResponse, Net::HTTPHeaderSyntaxError, Net::ProtocolError,
23
+ Zlib::BufError, Errno::EHOSTUNREACH, Errno::ECONNREFUSED
24
+ ].freeze
25
+
26
+
17
27
  def initialize(*args)
18
28
  super
19
- @endpoint = @dsn.envelope_endpoint
20
-
21
- log_debug("Sentry HTTP Transport will connect to #{@dsn.server}")
29
+ log_debug("Sentry HTTP Transport will connect to #{@dsn.server}") if @dsn
22
30
  end
23
31
 
24
32
  def send_data(data)
@@ -32,34 +40,76 @@ module Sentry
32
40
  headers = {
33
41
  'Content-Type' => CONTENT_TYPE,
34
42
  'Content-Encoding' => encoding,
35
- 'X-Sentry-Auth' => generate_auth_header,
36
43
  'User-Agent' => USER_AGENT
37
44
  }
38
45
 
46
+ auth_header = generate_auth_header
47
+ headers['X-Sentry-Auth'] = auth_header if auth_header
48
+
39
49
  response = conn.start do |http|
40
- request = ::Net::HTTP::Post.new(@endpoint, headers)
50
+ request = ::Net::HTTP::Post.new(endpoint, headers)
41
51
  request.body = data
42
52
  http.request(request)
43
53
  end
44
54
 
45
55
  if response.code.match?(/\A2\d{2}/)
46
- if has_rate_limited_header?(response)
47
- handle_rate_limited_response(response)
48
- end
56
+ handle_rate_limited_response(response) if has_rate_limited_header?(response)
57
+ elsif response.code == "429"
58
+ log_debug("the server responded with status 429")
59
+ handle_rate_limited_response(response)
49
60
  else
50
61
  error_info = "the server responded with status #{response.code}"
62
+ error_info += "\nbody: #{response.body}"
63
+ error_info += " Error in headers is: #{response['x-sentry-error']}" if response['x-sentry-error']
64
+
65
+ raise Sentry::ExternalError, error_info
66
+ end
67
+ rescue SocketError, *HTTP_ERRORS => e
68
+ on_error if respond_to?(:on_error)
69
+ raise Sentry::ExternalError.new(e&.message)
70
+ end
71
+
72
+ def endpoint
73
+ @dsn.envelope_endpoint
74
+ end
75
+
76
+ def generate_auth_header
77
+ return nil unless @dsn
78
+
79
+ now = Sentry.utc_now.to_i
80
+ fields = {
81
+ 'sentry_version' => PROTOCOL_VERSION,
82
+ 'sentry_client' => USER_AGENT,
83
+ 'sentry_timestamp' => now,
84
+ 'sentry_key' => @dsn.public_key
85
+ }
86
+ fields['sentry_secret'] = @dsn.secret_key if @dsn.secret_key
87
+ 'Sentry ' + fields.map { |key, value| "#{key}=#{value}" }.join(', ')
88
+ end
51
89
 
52
- if response.code == "429"
53
- handle_rate_limited_response(response)
90
+ def conn
91
+ server = URI(@dsn.server)
92
+
93
+ # connection respects proxy setting from @transport_configuration, or environment variables (HTTP_PROXY, HTTPS_PROXY, NO_PROXY)
94
+ # Net::HTTP will automatically read the env vars.
95
+ # See https://ruby-doc.org/3.2.2/stdlibs/net/Net/HTTP.html#class-Net::HTTP-label-Proxies
96
+ connection =
97
+ if proxy = normalize_proxy(@transport_configuration.proxy)
98
+ ::Net::HTTP.new(server.hostname, server.port, proxy[:uri].hostname, proxy[:uri].port, proxy[:user], proxy[:password])
54
99
  else
55
- error_info += "\nbody: #{response.body}"
56
- error_info += " Error in headers is: #{response['x-sentry-error']}" if response['x-sentry-error']
100
+ ::Net::HTTP.new(server.hostname, server.port)
57
101
  end
58
102
 
59
- raise Sentry::ExternalError, error_info
103
+ connection.use_ssl = server.scheme == "https"
104
+ connection.read_timeout = @transport_configuration.timeout
105
+ connection.write_timeout = @transport_configuration.timeout if connection.respond_to?(:write_timeout)
106
+ connection.open_timeout = @transport_configuration.open_timeout
107
+
108
+ ssl_configuration.each do |key, value|
109
+ connection.send("#{key}=", value)
60
110
  end
61
- rescue SocketError => e
62
- raise Sentry::ExternalError.new(e.message)
111
+
112
+ connection
63
113
  end
64
114
 
65
115
  private
@@ -126,28 +176,9 @@ module Sentry
126
176
  @transport_configuration.encoding == GZIP_ENCODING && data.bytesize >= GZIP_THRESHOLD
127
177
  end
128
178
 
129
- def conn
130
- server = URI(@dsn.server)
131
-
132
- connection =
133
- if proxy = normalize_proxy(@transport_configuration.proxy)
134
- ::Net::HTTP.new(server.hostname, server.port, proxy[:uri].hostname, proxy[:uri].port, proxy[:user], proxy[:password])
135
- else
136
- ::Net::HTTP.new(server.hostname, server.port, nil)
137
- end
138
-
139
- connection.use_ssl = server.scheme == "https"
140
- connection.read_timeout = @transport_configuration.timeout
141
- connection.write_timeout = @transport_configuration.timeout if connection.respond_to?(:write_timeout)
142
- connection.open_timeout = @transport_configuration.open_timeout
143
-
144
- ssl_configuration.each do |key, value|
145
- connection.send("#{key}=", value)
146
- end
147
-
148
- connection
149
- end
150
-
179
+ # @param proxy [String, URI, Hash] Proxy config value passed into `config.transport`.
180
+ # Accepts either a URI formatted string, URI, or a hash with the `uri`, `user`, and `password` keys.
181
+ # @return [Hash] Normalized proxy config that will be passed into `Net::HTTP`
151
182
  def normalize_proxy(proxy)
152
183
  return proxy unless proxy
153
184
 
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "net/http"
4
+ require "zlib"
5
+
6
+ module Sentry
7
+ # Designed to just report events to Spotlight in development.
8
+ class SpotlightTransport < HTTPTransport
9
+ DEFAULT_SIDECAR_URL = "http://localhost:8969/stream"
10
+ MAX_FAILED_REQUESTS = 3
11
+
12
+ def initialize(configuration)
13
+ super
14
+ @sidecar_url = configuration.spotlight.is_a?(String) ? configuration.spotlight : DEFAULT_SIDECAR_URL
15
+ @failed = 0
16
+ @logged = false
17
+
18
+ log_debug("[Spotlight] initialized for url #{@sidecar_url}")
19
+ end
20
+
21
+ def endpoint
22
+ "/stream"
23
+ end
24
+
25
+ def send_data(data)
26
+ if @failed >= MAX_FAILED_REQUESTS
27
+ unless @logged
28
+ log_debug("[Spotlight] disabling because of too many request failures")
29
+ @logged = true
30
+ end
31
+
32
+ return
33
+ end
34
+
35
+ super
36
+ end
37
+
38
+ def on_error
39
+ @failed += 1
40
+ end
41
+
42
+ # Similar to HTTPTransport connection, but does not support Proxy and SSL
43
+ def conn
44
+ sidecar = URI(@sidecar_url)
45
+ connection = ::Net::HTTP.new(sidecar.hostname, sidecar.port, nil)
46
+ connection.use_ssl = false
47
+ connection
48
+ end
49
+ end
50
+ end
@@ -18,7 +18,9 @@ module Sentry
18
18
  :network_error,
19
19
  :sample_rate,
20
20
  :before_send,
21
- :event_processor
21
+ :event_processor,
22
+ :insufficient_data,
23
+ :backpressure
22
24
  ]
23
25
 
24
26
  include LoggingHelper
@@ -73,7 +75,7 @@ module Sentry
73
75
  result, oversized = item.serialize
74
76
 
75
77
  if oversized
76
- log_info("Envelope item [#{item.type}] is still oversized after size reduction: {#{item.size_breakdown}}")
78
+ log_debug("Envelope item [#{item.type}] is still oversized after size reduction: {#{item.size_breakdown}}")
77
79
 
78
80
  next
79
81
  end
@@ -118,16 +120,8 @@ module Sentry
118
120
  !!delay && delay > Time.now
119
121
  end
120
122
 
121
- def generate_auth_header
122
- now = Sentry.utc_now.to_i
123
- fields = {
124
- 'sentry_version' => PROTOCOL_VERSION,
125
- 'sentry_client' => USER_AGENT,
126
- 'sentry_timestamp' => now,
127
- 'sentry_key' => @dsn.public_key
128
- }
129
- fields['sentry_secret'] = @dsn.secret_key if @dsn.secret_key
130
- 'Sentry ' + fields.map { |key, value| "#{key}=#{value}" }.join(', ')
123
+ def any_rate_limited?
124
+ @rate_limits.values.any? { |t| t && t > Time.now }
131
125
  end
132
126
 
133
127
  def envelope_from_event(event)
@@ -136,20 +130,31 @@ module Sentry
136
130
  event_id = event_payload[:event_id] || event_payload["event_id"]
137
131
  item_type = event_payload[:type] || event_payload["type"]
138
132
 
139
- envelope = Envelope.new(
140
- {
141
- event_id: event_id,
142
- dsn: @dsn.to_s,
143
- sdk: Sentry.sdk_meta,
144
- sent_at: Sentry.utc_now.iso8601
145
- }
146
- )
133
+ envelope_headers = {
134
+ event_id: event_id,
135
+ dsn: @dsn.to_s,
136
+ sdk: Sentry.sdk_meta,
137
+ sent_at: Sentry.utc_now.iso8601
138
+ }
139
+
140
+ if event.is_a?(Event) && event.dynamic_sampling_context
141
+ envelope_headers[:trace] = event.dynamic_sampling_context
142
+ end
143
+
144
+ envelope = Envelope.new(envelope_headers)
147
145
 
148
146
  envelope.add_item(
149
147
  { type: item_type, content_type: 'application/json' },
150
148
  event_payload
151
149
  )
152
150
 
151
+ if event.is_a?(TransactionEvent) && event.profile
152
+ envelope.add_item(
153
+ { type: 'profile', content_type: 'application/json' },
154
+ event.profile
155
+ )
156
+ end
157
+
153
158
  client_report_headers, client_report_payload = fetch_pending_client_report
154
159
  envelope.add_item(client_report_headers, client_report_payload) if client_report_headers
155
160
 
@@ -163,18 +168,27 @@ module Sentry
163
168
  @discarded_events[[reason, item_type]] += 1
164
169
  end
165
170
 
171
+ def flush
172
+ client_report_headers, client_report_payload = fetch_pending_client_report(force: true)
173
+ return unless client_report_headers
174
+
175
+ envelope = Envelope.new
176
+ envelope.add_item(client_report_headers, client_report_payload)
177
+ send_envelope(envelope)
178
+ end
179
+
166
180
  private
167
181
 
168
- def fetch_pending_client_report
182
+ def fetch_pending_client_report(force: false)
169
183
  return nil unless @send_client_reports
170
- return nil if @last_client_report_sent > Time.now - CLIENT_REPORT_INTERVAL
184
+ return nil if !force && @last_client_report_sent > Time.now - CLIENT_REPORT_INTERVAL
171
185
  return nil if @discarded_events.empty?
172
186
 
173
187
  discarded_events_hash = @discarded_events.map do |key, val|
174
188
  reason, type = key
175
189
 
176
190
  # 'event' has to be mapped to 'error'
177
- category = type == 'transaction' ? 'transaction' : 'error'
191
+ category = type == 'event' ? 'error' : type
178
192
 
179
193
  { reason: reason, category: category, quantity: val }
180
194
  end
@@ -194,7 +208,7 @@ module Sentry
194
208
  def reject_rate_limited_items(envelope)
195
209
  envelope.items.reject! do |item|
196
210
  if is_rate_limited?(item.type)
197
- log_info("[Transport] Envelope item [#{item.type}] not sent: rate limiting")
211
+ log_debug("[Transport] Envelope item [#{item.type}] not sent: rate limiting")
198
212
  record_lost_event(:ratelimit_backoff, item.type)
199
213
 
200
214
  true
@@ -208,3 +222,4 @@ end
208
222
 
209
223
  require "sentry/transport/dummy_transport"
210
224
  require "sentry/transport/http_transport"
225
+ require "sentry/transport/spotlight_transport"
@@ -4,9 +4,15 @@ module Sentry
4
4
  module ArgumentCheckingHelper
5
5
  private
6
6
 
7
- def check_argument_type!(argument, expected_type)
8
- unless argument.is_a?(expected_type)
9
- raise ArgumentError, "expect the argument to be a #{expected_type}, got #{argument.class} (#{argument.inspect})"
7
+ def check_argument_type!(argument, *expected_types)
8
+ unless expected_types.any? { |t| argument.is_a?(t) }
9
+ raise ArgumentError, "expect the argument to be a #{expected_types.join(' or ')}, got #{argument.class} (#{argument.inspect})"
10
+ end
11
+ end
12
+
13
+ def check_argument_includes!(argument, values)
14
+ unless values.include?(argument)
15
+ raise ArgumentError, "expect the argument to be one of #{values.map(&:inspect).join(' or ')}, got #{argument.inspect}"
10
16
  end
11
17
  end
12
18
  end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Sentry
4
+ module Utils
5
+ module EncodingHelper
6
+ def self.encode_to_utf_8(value)
7
+ if value.encoding != Encoding::UTF_8 && value.respond_to?(:force_encoding)
8
+ value = value.dup.force_encoding(Encoding::UTF_8)
9
+ end
10
+
11
+ value = value.scrub unless value.valid_encoding?
12
+ value
13
+ end
14
+
15
+ def self.valid_utf_8?(value)
16
+ return true unless value.respond_to?(:force_encoding)
17
+
18
+ value.dup.force_encoding(Encoding::UTF_8).valid_encoding?
19
+ end
20
+ end
21
+ end
22
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Sentry
4
- VERSION = "5.4.2"
4
+ VERSION = "5.16.1"
5
5
  end
data/lib/sentry-ruby.rb CHANGED
@@ -8,17 +8,21 @@ require "sentry/version"
8
8
  require "sentry/exceptions"
9
9
  require "sentry/core_ext/object/deep_dup"
10
10
  require "sentry/utils/argument_checking_helper"
11
+ require "sentry/utils/encoding_helper"
11
12
  require "sentry/utils/logging_helper"
12
13
  require "sentry/configuration"
13
14
  require "sentry/logger"
14
15
  require "sentry/event"
15
16
  require "sentry/error_event"
16
17
  require "sentry/transaction_event"
18
+ require "sentry/check_in_event"
17
19
  require "sentry/span"
18
20
  require "sentry/transaction"
19
21
  require "sentry/hub"
20
22
  require "sentry/background_worker"
21
23
  require "sentry/session_flusher"
24
+ require "sentry/backpressure_monitor"
25
+ require "sentry/cron/monitor_check_ins"
22
26
 
23
27
  [
24
28
  "sentry/rake",
@@ -39,6 +43,8 @@ module Sentry
39
43
 
40
44
  SENTRY_TRACE_HEADER_NAME = "sentry-trace".freeze
41
45
 
46
+ BAGGAGE_HEADER_NAME = "baggage".freeze
47
+
42
48
  THREAD_LOCAL = :sentry_hub
43
49
 
44
50
  class << self
@@ -60,30 +66,44 @@ module Sentry
60
66
  end
61
67
 
62
68
  # @!attribute [rw] background_worker
63
- # @return [BackgroundWorker, nil]
69
+ # @return [BackgroundWorker]
64
70
  attr_accessor :background_worker
65
71
 
66
72
  # @!attribute [r] session_flusher
67
73
  # @return [SessionFlusher, nil]
68
74
  attr_reader :session_flusher
69
75
 
76
+ # @!attribute [r] backpressure_monitor
77
+ # @return [BackpressureMonitor, nil]
78
+ attr_reader :backpressure_monitor
79
+
70
80
  ##### Patch Registration #####
71
81
 
72
82
  # @!visibility private
73
- def register_patch(&block)
74
- registered_patches << block
83
+ def register_patch(key, patch = nil, target = nil, &block)
84
+ if patch && block
85
+ raise ArgumentError.new("Please provide either a patch and its target OR a block, but not both")
86
+ end
87
+
88
+ if block
89
+ registered_patches[key] = block
90
+ else
91
+ registered_patches[key] = proc do
92
+ target.send(:prepend, patch) unless target.ancestors.include?(patch)
93
+ end
94
+ end
75
95
  end
76
96
 
77
97
  # @!visibility private
78
98
  def apply_patches(config)
79
- registered_patches.each do |patch|
80
- patch.call(config)
99
+ registered_patches.each do |key, patch|
100
+ patch.call(config) if config.enabled_patches.include?(key)
81
101
  end
82
102
  end
83
103
 
84
104
  # @!visibility private
85
105
  def registered_patches
86
- @registered_patches ||= []
106
+ @registered_patches ||= {}
87
107
  end
88
108
 
89
109
  ##### Integrations #####
@@ -202,17 +222,9 @@ module Sentry
202
222
  Thread.current.thread_variable_set(THREAD_LOCAL, hub)
203
223
  @main_hub = hub
204
224
  @background_worker = Sentry::BackgroundWorker.new(config)
205
-
206
- @session_flusher = if config.auto_session_tracking
207
- Sentry::SessionFlusher.new(config, client)
208
- else
209
- nil
210
- end
211
-
212
- if config.capture_exception_frame_locals
213
- exception_locals_tp.enable
214
- end
215
-
225
+ @session_flusher = config.auto_session_tracking ? Sentry::SessionFlusher.new(config, client) : nil
226
+ @backpressure_monitor = config.enable_backpressure_handling ? Sentry::BackpressureMonitor.new(config, client) : nil
227
+ exception_locals_tp.enable if config.include_local_variables
216
228
  at_exit { close }
217
229
  end
218
230
 
@@ -221,20 +233,27 @@ module Sentry
221
233
  #
222
234
  # @return [void]
223
235
  def close
224
- if @background_worker
225
- @background_worker.shutdown
226
- @background_worker = nil
227
- end
228
-
229
236
  if @session_flusher
237
+ @session_flusher.flush
230
238
  @session_flusher.kill
231
239
  @session_flusher = nil
232
240
  end
233
241
 
234
- if configuration&.capture_exception_frame_locals
235
- exception_locals_tp.disable
242
+ if @backpressure_monitor
243
+ @backpressure_monitor.kill
244
+ @backpressure_monitor = nil
236
245
  end
237
246
 
247
+ if client = get_current_client
248
+ client.transport.flush
249
+
250
+ if client.configuration.include_local_variables
251
+ exception_locals_tp.disable
252
+ end
253
+ end
254
+
255
+ @background_worker.shutdown
256
+
238
257
  @main_hub = nil
239
258
  Thread.current.thread_variable_set(THREAD_LOCAL, nil)
240
259
  end
@@ -348,7 +367,7 @@ module Sentry
348
367
  # @yieldparam scope [Scope]
349
368
  # @return [void]
350
369
  def with_scope(&block)
351
- return unless initialized?
370
+ return yield unless initialized?
352
371
  get_current_hub.with_scope(&block)
353
372
  end
354
373
 
@@ -417,6 +436,22 @@ module Sentry
417
436
  get_current_hub.capture_event(event)
418
437
  end
419
438
 
439
+ # Captures a check-in and sends it to Sentry via the currently active hub.
440
+ #
441
+ # @param slug [String] identifier of this monitor
442
+ # @param status [Symbol] status of this check-in, one of {CheckInEvent::VALID_STATUSES}
443
+ #
444
+ # @param [Hash] options extra check-in options
445
+ # @option options [String] check_in_id for updating the status of an existing monitor
446
+ # @option options [Integer] duration seconds elapsed since this monitor started
447
+ # @option options [Cron::MonitorConfig] monitor_config configuration for this monitor
448
+ #
449
+ # @return [String, nil] The {CheckInEvent#check_in_id} to use for later updates on the same slug
450
+ def capture_check_in(slug, status, **options)
451
+ return unless initialized?
452
+ get_current_hub.capture_check_in(slug, status, **options)
453
+ end
454
+
420
455
  # Takes or initializes a new Sentry::Transaction and makes a sampling decision for it.
421
456
  #
422
457
  # @return [Transaction, nil]
@@ -439,22 +474,8 @@ module Sentry
439
474
  # end
440
475
  #
441
476
  def with_child_span(**attributes, &block)
442
- if Sentry.initialized? && current_span = get_current_scope.get_span
443
- result = nil
444
-
445
- begin
446
- current_span.with_child_span(**attributes) do |child_span|
447
- get_current_scope.set_span(child_span)
448
- result = yield(child_span)
449
- end
450
- ensure
451
- get_current_scope.set_span(current_span)
452
- end
453
-
454
- result
455
- else
456
- yield(nil)
457
- end
477
+ return yield(nil) unless Sentry.initialized?
478
+ get_current_hub.with_child_span(**attributes, &block)
458
479
  end
459
480
 
460
481
  # Returns the id of the lastly reported Sentry::Event.
@@ -473,6 +494,59 @@ module Sentry
473
494
  !!exc.instance_variable_get(CAPTURED_SIGNATURE)
474
495
  end
475
496
 
497
+ # Add a global event processor [Proc].
498
+ # These run before scope event processors.
499
+ #
500
+ # @yieldparam event [Event]
501
+ # @yieldparam hint [Hash, nil]
502
+ # @return [void]
503
+ #
504
+ # @example
505
+ # Sentry.add_global_event_processor do |event, hint|
506
+ # event.tags = { foo: 42 }
507
+ # event
508
+ # end
509
+ #
510
+ def add_global_event_processor(&block)
511
+ Scope.add_global_event_processor(&block)
512
+ end
513
+
514
+ # Returns the traceparent (sentry-trace) header for distributed tracing.
515
+ # Can be either from the currently active span or the propagation context.
516
+ #
517
+ # @return [String, nil]
518
+ def get_traceparent
519
+ return nil unless initialized?
520
+ get_current_hub.get_traceparent
521
+ end
522
+
523
+ # Returns the baggage header for distributed tracing.
524
+ # Can be either from the currently active span or the propagation context.
525
+ #
526
+ # @return [String, nil]
527
+ def get_baggage
528
+ return nil unless initialized?
529
+ get_current_hub.get_baggage
530
+ end
531
+
532
+ # Returns the a Hash containing sentry-trace and baggage.
533
+ # Can be either from the currently active span or the propagation context.
534
+ #
535
+ # @return [Hash, nil]
536
+ def get_trace_propagation_headers
537
+ return nil unless initialized?
538
+ get_current_hub.get_trace_propagation_headers
539
+ end
540
+
541
+ # Continue an incoming trace from a rack env like hash.
542
+ #
543
+ # @param env [Hash]
544
+ # @return [Transaction, nil]
545
+ def continue_trace(env, **options)
546
+ return nil unless initialized?
547
+ get_current_hub.continue_trace(env, **options)
548
+ end
549
+
476
550
  ##### Helpers #####
477
551
 
478
552
  # @!visibility private
@@ -503,3 +577,4 @@ end
503
577
  # patches
504
578
  require "sentry/net/http"
505
579
  require "sentry/redis"
580
+ require "sentry/puma"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sentry-ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.4.2
4
+ version: 5.16.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sentry Team
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-08-17 00:00:00.000000000 Z
11
+ date: 2024-01-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: concurrent-ruby
@@ -42,7 +42,6 @@ files:
42
42
  - ".rspec"
43
43
  - ".yardopts"
44
44
  - CHANGELOG.md
45
- - CODE_OF_CONDUCT.md
46
45
  - Gemfile
47
46
  - LICENSE.txt
48
47
  - Makefile
@@ -52,14 +51,21 @@ files:
52
51
  - bin/setup
53
52
  - lib/sentry-ruby.rb
54
53
  - lib/sentry/background_worker.rb
54
+ - lib/sentry/backpressure_monitor.rb
55
55
  - lib/sentry/backtrace.rb
56
+ - lib/sentry/baggage.rb
56
57
  - lib/sentry/breadcrumb.rb
57
58
  - lib/sentry/breadcrumb/sentry_logger.rb
58
59
  - lib/sentry/breadcrumb_buffer.rb
60
+ - lib/sentry/check_in_event.rb
59
61
  - lib/sentry/client.rb
60
62
  - lib/sentry/configuration.rb
61
63
  - lib/sentry/core_ext/object/deep_dup.rb
62
64
  - lib/sentry/core_ext/object/duplicable.rb
65
+ - lib/sentry/cron/configuration.rb
66
+ - lib/sentry/cron/monitor_check_ins.rb
67
+ - lib/sentry/cron/monitor_config.rb
68
+ - lib/sentry/cron/monitor_schedule.rb
63
69
  - lib/sentry/dsn.rb
64
70
  - lib/sentry/envelope.rb
65
71
  - lib/sentry/error_event.rb
@@ -77,6 +83,9 @@ files:
77
83
  - lib/sentry/linecache.rb
78
84
  - lib/sentry/logger.rb
79
85
  - lib/sentry/net/http.rb
86
+ - lib/sentry/profiler.rb
87
+ - lib/sentry/propagation_context.rb
88
+ - lib/sentry/puma.rb
80
89
  - lib/sentry/rack.rb
81
90
  - lib/sentry/rack/capture_exceptions.rb
82
91
  - lib/sentry/rake.rb
@@ -93,8 +102,10 @@ files:
93
102
  - lib/sentry/transport/configuration.rb
94
103
  - lib/sentry/transport/dummy_transport.rb
95
104
  - lib/sentry/transport/http_transport.rb
105
+ - lib/sentry/transport/spotlight_transport.rb
96
106
  - lib/sentry/utils/argument_checking_helper.rb
97
107
  - lib/sentry/utils/custom_inspection.rb
108
+ - lib/sentry/utils/encoding_helper.rb
98
109
  - lib/sentry/utils/exception_cause_chain.rb
99
110
  - lib/sentry/utils/logging_helper.rb
100
111
  - lib/sentry/utils/real_ip.rb