sentry-ruby 5.4.2 → 5.16.1

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