sentry-ruby 5.4.1 → 5.5.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a63e249dfaf6fb45c9a4cfb897b604e96cb751b12920aa7371c8f503754001fd
4
- data.tar.gz: b27555038074ec03421cc287dbecf2fa7e85642c4bffaa71bb770232dc6eb4d1
3
+ metadata.gz: 2ad98e145a972608f9b15a669f771074f1fac592b8819fe1e1e2ac70c6b919a0
4
+ data.tar.gz: 5058a18d24be77f5879c4455ab0a437010ad526cb5fa0ec869161c7fa5174d4f
5
5
  SHA512:
6
- metadata.gz: 3dd63a8eeadb199013c7c2387819e185f58751d733cf6c36f4a95d1653e85bca20b62b75ccea24f8c624eaffc3f4a5c1d2889352e6e4b80744ecc2974981a9bd
7
- data.tar.gz: ef0594cbf709b46819b970debebec8f2a5be3f49aa483ea15963640af3ab84ea9c180ffbf6138675d8354d840106fca5e4e178d1f40e13e22b5ff57b60402e83
6
+ metadata.gz: 69c776cddf21fb89754a1750632f2dc3a28d3dc4cd5e20a0c2a175985533b2f1d6774b4196c3437186776b2e60683356b141675606762338bfbb4e4d2fc9f764
7
+ data.tar.gz: 3684c877d6370e5f72fb09151e5f01803661e177dfdce326b789e26ed59c06671bde2db641957f6bdc423f576cfe9e97657d5ac7e8fb81a61e8760ac31039ab8
data/Gemfile CHANGED
@@ -3,12 +3,13 @@ git_source(:github) { |name| "https://github.com/#{name}.git" }
3
3
 
4
4
  gem "sentry-ruby", path: "./"
5
5
 
6
- gem "rack" unless ENV["WITHOUT_RACK"] == "1"
6
+ rack_version = ENV["RACK_VERSION"]
7
+ rack_version = "3.0.0" if rack_version.nil?
8
+ gem "rack", "~> #{Gem::Version.new(rack_version)}" unless rack_version == "0"
7
9
 
8
10
  gem "rake", "~> 12.0"
9
11
  gem "rspec", "~> 3.0"
10
12
  gem "rspec-retry"
11
- gem "webmock"
12
13
  gem "fakeredis"
13
14
  gem "timecop"
14
15
  gem 'simplecov'
@@ -0,0 +1,81 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'cgi'
4
+
5
+ module Sentry
6
+ # A {https://www.w3.org/TR/baggage W3C Baggage Header} implementation.
7
+ class Baggage
8
+ SENTRY_PREFIX = 'sentry-'
9
+ SENTRY_PREFIX_REGEX = /^sentry-/.freeze
10
+
11
+ DSC_KEYS = %w(
12
+ trace_id
13
+ public_key
14
+ sample_rate
15
+ release
16
+ environment
17
+ transaction
18
+ user_id
19
+ user_segment
20
+ ).freeze
21
+
22
+ # @return [Hash]
23
+ attr_reader :items
24
+
25
+ # @return [Boolean]
26
+ attr_reader :mutable
27
+
28
+ def initialize(items, mutable: true)
29
+ @items = items
30
+ @mutable = mutable
31
+ end
32
+
33
+ # Creates a Baggage object from an incoming W3C Baggage header string.
34
+ #
35
+ # Sentry items are identified with the 'sentry-' prefix and stored in a hash.
36
+ # The presence of a Sentry item makes the baggage object immutable.
37
+ #
38
+ # @param header [String] The incoming Baggage header string.
39
+ # @return [Baggage, nil]
40
+ def self.from_incoming_header(header)
41
+ items = {}
42
+ mutable = true
43
+
44
+ header.split(',').each do |item|
45
+ item = item.strip
46
+ key, val = item.split('=')
47
+
48
+ next unless key && val
49
+ next unless key =~ SENTRY_PREFIX_REGEX
50
+
51
+ baggage_key = key.split('-')[1]
52
+ next unless baggage_key
53
+
54
+ items[CGI.unescape(baggage_key)] = CGI.unescape(val)
55
+ mutable = false
56
+ end
57
+
58
+ new(items, mutable: mutable)
59
+ end
60
+
61
+ # Make the Baggage immutable.
62
+ # @return [void]
63
+ def freeze!
64
+ @mutable = false
65
+ end
66
+
67
+ # A {https://develop.sentry.dev/sdk/performance/dynamic-sampling-context/#envelope-header Dynamic Sampling Context}
68
+ # hash to be used in the trace envelope header.
69
+ # @return [Hash]
70
+ def dynamic_sampling_context
71
+ @items.select { |k, _v| DSC_KEYS.include?(k) }
72
+ end
73
+
74
+ # Serialize the Baggage object back to a string.
75
+ # @return [String]
76
+ def serialize
77
+ items = @items.map { |k, v| "#{SENTRY_PREFIX}#{CGI.escape(k)}=#{CGI.escape(v)}" }
78
+ items.join(',')
79
+ end
80
+ end
81
+ end
@@ -22,7 +22,7 @@ module Sentry
22
22
  def add_breadcrumb(severity, message = nil, progname = nil)
23
23
  # because the breadcrumbs now belongs to different Hub's Scope in different threads
24
24
  # we need to make sure the current thread's Hub has been set before adding breadcrumbs
25
- return unless Sentry.get_current_hub
25
+ return unless Sentry.initialized? && Sentry.get_current_hub
26
26
 
27
27
  category = "logger"
28
28
 
data/lib/sentry/client.rb CHANGED
@@ -105,16 +105,7 @@ module Sentry
105
105
  # @param transaction [Transaction] the transaction to be recorded.
106
106
  # @return [TransactionEvent]
107
107
  def event_from_transaction(transaction)
108
- TransactionEvent.new(configuration: configuration).tap do |event|
109
- event.transaction = transaction.name
110
- event.contexts.merge!(trace: transaction.get_trace_context)
111
- event.timestamp = transaction.timestamp
112
- event.start_timestamp = transaction.start_timestamp
113
- event.tags = transaction.tags
114
-
115
- finished_spans = transaction.span_recorder.spans.select { |span| span.timestamp && span != transaction }
116
- event.spans = finished_spans.map(&:to_hash)
117
- end
108
+ TransactionEvent.new(configuration: configuration, transaction: transaction)
118
109
  end
119
110
 
120
111
  # @!macro send_event
@@ -156,6 +147,22 @@ module Sentry
156
147
  trace
157
148
  end
158
149
 
150
+ # Generates a W3C Baggage header for distribted tracing from the given Span.
151
+ # Returns `nil` if `config.propagate_traces` is `false`.
152
+ # @param span [Span] the span to generate trace from.
153
+ # @return [String, nil]
154
+ def generate_baggage(span)
155
+ return unless configuration.propagate_traces
156
+
157
+ baggage = span.to_baggage
158
+
159
+ if baggage && !baggage.empty?
160
+ log_debug("[Tracing] Adding #{BAGGAGE_HEADER_NAME} header to outgoing request: #{baggage}")
161
+ end
162
+
163
+ baggage
164
+ end
165
+
159
166
  private
160
167
 
161
168
  def dispatch_background_event(event, hint)
data/lib/sentry/event.rb CHANGED
@@ -18,7 +18,7 @@ module Sentry
18
18
  event_id level timestamp
19
19
  release environment server_name modules
20
20
  message user tags contexts extra
21
- fingerprint breadcrumbs transaction
21
+ fingerprint breadcrumbs transaction transaction_info
22
22
  platform sdk type
23
23
  )
24
24
 
@@ -123,13 +123,15 @@ module Sentry
123
123
  !(key.start_with?('HTTP_') || CONTENT_HEADERS.include?(key))
124
124
  end
125
125
 
126
- # Rack adds in an incorrect HTTP_VERSION key, which causes downstream
126
+ # In versions < 3, Rack adds in an incorrect HTTP_VERSION key, which causes downstream
127
127
  # to think this is a Version header. Instead, this is mapped to
128
128
  # env['SERVER_PROTOCOL']. But we don't want to ignore a valid header
129
129
  # if the request has legitimately sent a Version header themselves.
130
130
  # See: https://github.com/rack/rack/blob/028438f/lib/rack/handler/cgi.rb#L29
131
- # NOTE: This will be removed in version 3.0+
132
131
  def is_server_protocol?(key, value, protocol_version)
132
+ rack_version = Gem::Version.new(::Rack.release)
133
+ return false if rack_version >= Gem::Version.new("3.0")
134
+
133
135
  key == 'HTTP_VERSION' && value == protocol_version
134
136
  end
135
137
 
@@ -42,8 +42,13 @@ module Sentry
42
42
  def set_sentry_trace_header(req, sentry_span)
43
43
  return unless sentry_span
44
44
 
45
- trace = Sentry.get_current_client.generate_sentry_trace(sentry_span)
45
+ client = Sentry.get_current_client
46
+
47
+ trace = client.generate_sentry_trace(sentry_span)
46
48
  req[SENTRY_TRACE_HEADER_NAME] = trace if trace
49
+
50
+ baggage = client.generate_baggage(sentry_span)
51
+ req[BAGGAGE_HEADER_NAME] = baggage if baggage && !baggage.empty?
47
52
  end
48
53
 
49
54
  def record_sentry_breadcrumb(req, res)
@@ -18,7 +18,7 @@ module Sentry
18
18
  Sentry.with_scope do |scope|
19
19
  Sentry.with_session_tracking do
20
20
  scope.clear_breadcrumbs
21
- scope.set_transaction_name(env["PATH_INFO"]) if env["PATH_INFO"]
21
+ scope.set_transaction_name(env["PATH_INFO"], source: :url) if env["PATH_INFO"]
22
22
  scope.set_rack_env(env)
23
23
 
24
24
  transaction = start_transaction(env, scope)
@@ -63,8 +63,10 @@ module Sentry
63
63
 
64
64
  def start_transaction(env, scope)
65
65
  sentry_trace = env["HTTP_SENTRY_TRACE"]
66
- options = { name: scope.transaction_name, op: transaction_op }
67
- transaction = Sentry::Transaction.from_sentry_trace(sentry_trace, **options) if sentry_trace
66
+ baggage = env["HTTP_BAGGAGE"]
67
+
68
+ options = { name: scope.transaction_name, source: scope.transaction_source, op: transaction_op }
69
+ transaction = Sentry::Transaction.from_sentry_trace(sentry_trace, baggage: baggage, **options) if sentry_trace
68
70
  Sentry.start_transaction(transaction: transaction, custom_sampling_context: { env: env }, **options)
69
71
  end
70
72
 
data/lib/sentry/rake.rb CHANGED
@@ -10,7 +10,7 @@ module Sentry
10
10
  def display_error_message(ex)
11
11
  Sentry.capture_exception(ex) do |scope|
12
12
  task_name = top_level_tasks.join(' ')
13
- scope.set_transaction_name(task_name)
13
+ scope.set_transaction_name(task_name, source: :task)
14
14
  scope.set_tag("rake_task", task_name)
15
15
  end if Sentry.initialized? && !Sentry.configuration.skip_rake_integration
16
16
 
data/lib/sentry/scope.rb CHANGED
@@ -7,7 +7,21 @@ module Sentry
7
7
  class Scope
8
8
  include ArgumentCheckingHelper
9
9
 
10
- ATTRIBUTES = [:transaction_names, :contexts, :extra, :tags, :user, :level, :breadcrumbs, :fingerprint, :event_processors, :rack_env, :span, :session]
10
+ ATTRIBUTES = [
11
+ :transaction_names,
12
+ :transaction_sources,
13
+ :contexts,
14
+ :extra,
15
+ :tags,
16
+ :user,
17
+ :level,
18
+ :breadcrumbs,
19
+ :fingerprint,
20
+ :event_processors,
21
+ :rack_env,
22
+ :span,
23
+ :session
24
+ ]
11
25
 
12
26
  attr_reader(*ATTRIBUTES)
13
27
 
@@ -33,6 +47,7 @@ module Sentry
33
47
  event.extra = extra.merge(event.extra)
34
48
  event.contexts = contexts.merge(event.contexts)
35
49
  event.transaction = transaction_name if transaction_name
50
+ event.transaction_info = { source: transaction_source } if transaction_source
36
51
 
37
52
  if span
38
53
  event.contexts[:trace] = span.get_trace_context
@@ -73,7 +88,8 @@ module Sentry
73
88
  copy.extra = extra.deep_dup
74
89
  copy.tags = tags.deep_dup
75
90
  copy.user = user.deep_dup
76
- copy.transaction_names = transaction_names.deep_dup
91
+ copy.transaction_names = transaction_names.dup
92
+ copy.transaction_sources = transaction_sources.dup
77
93
  copy.fingerprint = fingerprint.deep_dup
78
94
  copy.span = span.deep_dup
79
95
  copy.session = session.deep_dup
@@ -90,6 +106,7 @@ module Sentry
90
106
  self.tags = scope.tags
91
107
  self.user = scope.user
92
108
  self.transaction_names = scope.transaction_names
109
+ self.transaction_sources = scope.transaction_sources
93
110
  self.fingerprint = scope.fingerprint
94
111
  self.span = scope.span
95
112
  end
@@ -195,8 +212,9 @@ module Sentry
195
212
  # The "transaction" here does not refer to `Transaction` objects.
196
213
  # @param transaction_name [String]
197
214
  # @return [void]
198
- def set_transaction_name(transaction_name)
215
+ def set_transaction_name(transaction_name, source: :custom)
199
216
  @transaction_names << transaction_name
217
+ @transaction_sources << source
200
218
  end
201
219
 
202
220
  # Sets the currently active session on the scope.
@@ -213,6 +231,13 @@ module Sentry
213
231
  @transaction_names.last
214
232
  end
215
233
 
234
+ # Returns current transaction source.
235
+ # The "transaction" here does not refer to `Transaction` objects.
236
+ # @return [String, nil]
237
+ def transaction_source
238
+ @transaction_sources.last
239
+ end
240
+
216
241
  # Returns the associated Transaction object.
217
242
  # @return [Transaction, nil]
218
243
  def get_transaction
@@ -256,6 +281,7 @@ module Sentry
256
281
  @level = :error
257
282
  @fingerprint = []
258
283
  @transaction_names = []
284
+ @transaction_sources = []
259
285
  @event_processors = []
260
286
  @rack_env = {}
261
287
  @span = nil
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Sentry
4
4
  class Session
5
- attr_reader :started, :status
5
+ attr_reader :started, :status, :aggregation_key
6
6
 
7
7
  # TODO-neel add :crashed after adding handled mechanism
8
8
  STATUSES = %i(ok errored exited)
@@ -11,6 +11,10 @@ module Sentry
11
11
  def initialize
12
12
  @started = Sentry.utc_now
13
13
  @status = :ok
14
+
15
+ # truncate seconds from the timestamp since we only care about
16
+ # minute level granularity for aggregation
17
+ @aggregation_key = Time.utc(@started.year, @started.month, @started.day, @started.hour, @started.min)
14
18
  end
15
19
 
16
20
  # TODO-neel add :crashed after adding handled mechanism
@@ -22,12 +26,6 @@ module Sentry
22
26
  @status = :exited if @status == :ok
23
27
  end
24
28
 
25
- # truncate seconds from the timestamp since we only care about
26
- # minute level granularity for aggregation
27
- def aggregation_key
28
- Time.utc(started.year, started.month, started.day, started.hour, started.min)
29
- end
30
-
31
29
  def deep_dup
32
30
  dup
33
31
  end
data/lib/sentry/span.rb CHANGED
@@ -104,6 +104,13 @@ module Sentry
104
104
  "#{@trace_id}-#{@span_id}-#{sampled_flag}"
105
105
  end
106
106
 
107
+ # Generates a W3C Baggage header string for distributed tracing
108
+ # from the incoming baggage stored on the transation.
109
+ # @return [String, nil]
110
+ def to_baggage
111
+ transaction&.get_baggage&.serialize
112
+ end
113
+
107
114
  # @return [Hash]
108
115
  def to_hash
109
116
  {
@@ -31,6 +31,7 @@ module Sentry
31
31
 
32
32
  test_client = Sentry::Client.new(copied_config)
33
33
  Sentry.get_current_hub.bind_client(test_client)
34
+ Sentry.get_current_scope.clear
34
35
  end
35
36
 
36
37
  # Clears all stored events and envelopes.
@@ -41,6 +42,7 @@ module Sentry
41
42
 
42
43
  sentry_transport.events = []
43
44
  sentry_transport.envelopes = []
45
+ Sentry.get_current_scope.clear
44
46
  end
45
47
 
46
48
  # @return [Transport]
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "sentry/baggage"
4
+
3
5
  module Sentry
4
6
  class Transaction < Span
5
7
  SENTRY_TRACE_REGEXP = Regexp.new(
@@ -12,16 +14,29 @@ module Sentry
12
14
  UNLABELD_NAME = "<unlabeled transaction>".freeze
13
15
  MESSAGE_PREFIX = "[Tracing]"
14
16
 
17
+ # https://develop.sentry.dev/sdk/event-payloads/transaction/#transaction-annotations
18
+ SOURCES = %i(custom url route view component task)
19
+
15
20
  include LoggingHelper
16
21
 
17
22
  # The name of the transaction.
18
23
  # @return [String]
19
24
  attr_reader :name
20
25
 
26
+ # The source of the transaction name.
27
+ # @return [Symbol]
28
+ attr_reader :source
29
+
21
30
  # The sampling decision of the parent transaction, which will be considered when making the current transaction's sampling decision.
22
31
  # @return [String]
23
32
  attr_reader :parent_sampled
24
33
 
34
+ # The parsed incoming W3C baggage header.
35
+ # This is only for accessing the current baggage variable.
36
+ # Please use the #get_baggage method for interfacing outside this class.
37
+ # @return [Baggage, nil]
38
+ attr_reader :baggage
39
+
25
40
  # @deprecated Use Sentry.get_current_hub instead.
26
41
  attr_reader :hub
27
42
 
@@ -31,18 +46,35 @@ module Sentry
31
46
  # @deprecated Use Sentry.logger instead.
32
47
  attr_reader :logger
33
48
 
34
- def initialize(name: nil, parent_sampled: nil, hub:, **options)
49
+ # The effective sample rate at which this transaction was sampled.
50
+ # @return [Float, nil]
51
+ attr_reader :effective_sample_rate
52
+
53
+ def initialize(
54
+ hub:,
55
+ name: nil,
56
+ source: :custom,
57
+ parent_sampled: nil,
58
+ baggage: nil,
59
+ **options
60
+ )
35
61
  super(**options)
36
62
 
37
63
  @name = name
64
+ @source = SOURCES.include?(source) ? source.to_sym : :custom
38
65
  @parent_sampled = parent_sampled
39
66
  @transaction = self
40
67
  @hub = hub
68
+ @baggage = baggage
41
69
  @configuration = hub.configuration # to be removed
42
70
  @tracing_enabled = hub.configuration.tracing_enabled?
43
71
  @traces_sampler = hub.configuration.traces_sampler
44
72
  @traces_sample_rate = hub.configuration.traces_sample_rate
45
73
  @logger = hub.configuration.logger
74
+ @release = hub.configuration.release
75
+ @environment = hub.configuration.environment
76
+ @dsn = hub.configuration.dsn
77
+ @effective_sample_rate = nil
46
78
  init_span_recorder
47
79
  end
48
80
 
@@ -52,10 +84,11 @@ module Sentry
52
84
  #
53
85
  # The child transaction will also store the parent's sampling decision in its `parent_sampled` attribute.
54
86
  # @param sentry_trace [String] the trace string from the previous transaction.
87
+ # @param baggage [String, nil] the incoming baggage header string.
55
88
  # @param hub [Hub] the hub that'll be responsible for sending this transaction when it's finished.
56
89
  # @param options [Hash] the options you want to use to initialize a Transaction instance.
57
90
  # @return [Transaction, nil]
58
- def self.from_sentry_trace(sentry_trace, hub: Sentry.get_current_hub, **options)
91
+ def self.from_sentry_trace(sentry_trace, baggage: nil, hub: Sentry.get_current_hub, **options)
59
92
  return unless hub.configuration.tracing_enabled?
60
93
  return unless sentry_trace
61
94
 
@@ -70,13 +103,38 @@ module Sentry
70
103
  sampled_flag != "0"
71
104
  end
72
105
 
73
- new(trace_id: trace_id, parent_span_id: parent_span_id, parent_sampled: parent_sampled, hub: hub, **options)
106
+ baggage = if baggage && !baggage.empty?
107
+ Baggage.from_incoming_header(baggage)
108
+ else
109
+ # If there's an incoming sentry-trace but no incoming baggage header,
110
+ # for instance in traces coming from older SDKs,
111
+ # baggage will be empty and frozen and won't be populated as head SDK.
112
+ Baggage.new({})
113
+ end
114
+
115
+ baggage.freeze!
116
+
117
+ new(
118
+ trace_id: trace_id,
119
+ parent_span_id: parent_span_id,
120
+ parent_sampled: parent_sampled,
121
+ hub: hub,
122
+ baggage: baggage,
123
+ **options
124
+ )
74
125
  end
75
126
 
76
127
  # @return [Hash]
77
128
  def to_hash
78
129
  hash = super
79
- hash.merge!(name: @name, sampled: @sampled, parent_sampled: @parent_sampled)
130
+
131
+ hash.merge!(
132
+ name: @name,
133
+ source: @source,
134
+ sampled: @sampled,
135
+ parent_sampled: @parent_sampled
136
+ )
137
+
80
138
  hash
81
139
  end
82
140
 
@@ -103,7 +161,10 @@ module Sentry
103
161
  return
104
162
  end
105
163
 
106
- return unless @sampled.nil?
164
+ unless @sampled.nil?
165
+ @effective_sample_rate = @sampled ? 1.0 : 0.0
166
+ return
167
+ end
107
168
 
108
169
  sample_rate =
109
170
  if @traces_sampler.is_a?(Proc)
@@ -116,7 +177,11 @@ module Sentry
116
177
 
117
178
  transaction_description = generate_transaction_description
118
179
 
119
- unless [true, false].include?(sample_rate) || (sample_rate.is_a?(Numeric) && sample_rate >= 0.0 && sample_rate <= 1.0)
180
+ if [true, false].include?(sample_rate)
181
+ @effective_sample_rate = sample_rate ? 1.0 : 0.0
182
+ elsif sample_rate.is_a?(Numeric) && sample_rate >= 0.0 && sample_rate <= 1.0
183
+ @effective_sample_rate = sample_rate.to_f
184
+ else
120
185
  @sampled = false
121
186
  log_warn("#{MESSAGE_PREFIX} Discarding #{transaction_description} because of invalid sample_rate: #{sample_rate}")
122
187
  return
@@ -172,6 +237,14 @@ module Sentry
172
237
  end
173
238
  end
174
239
 
240
+ # Get the existing frozen incoming baggage
241
+ # or populate one with sentry- items as the head SDK.
242
+ # @return [Baggage]
243
+ def get_baggage
244
+ populate_head_baggage if @baggage.nil? || @baggage.mutable
245
+ @baggage
246
+ end
247
+
175
248
  protected
176
249
 
177
250
  def init_span_recorder(limit = 1000)
@@ -188,6 +261,29 @@ module Sentry
188
261
  result
189
262
  end
190
263
 
264
+ def populate_head_baggage
265
+ items = {
266
+ "trace_id" => trace_id,
267
+ "sample_rate" => effective_sample_rate&.to_s,
268
+ "environment" => @environment,
269
+ "release" => @release,
270
+ "public_key" => @dsn&.public_key
271
+ }
272
+
273
+ items["transaction"] = name unless source_low_quality?
274
+
275
+ user = @hub.current_scope&.user
276
+ items["user_segment"] = user["segment"] if user && user["segment"]
277
+
278
+ items.compact!
279
+ @baggage = Baggage.new(items, mutable: false)
280
+ end
281
+
282
+ # These are high cardinality and thus bad
283
+ def source_low_quality?
284
+ source == :url
285
+ end
286
+
191
287
  class SpanRecorder
192
288
  attr_reader :max_length, :spans
193
289
 
@@ -8,9 +8,27 @@ module Sentry
8
8
  # @return [<Array[Span]>]
9
9
  attr_accessor :spans
10
10
 
11
+ # @return [Hash, nil]
12
+ attr_accessor :dynamic_sampling_context
13
+
11
14
  # @return [Float, nil]
12
15
  attr_reader :start_timestamp
13
16
 
17
+ def initialize(transaction:, **options)
18
+ super(**options)
19
+
20
+ self.transaction = transaction.name
21
+ self.transaction_info = { source: transaction.source }
22
+ self.contexts.merge!(trace: transaction.get_trace_context)
23
+ self.timestamp = transaction.timestamp
24
+ self.start_timestamp = transaction.start_timestamp
25
+ self.tags = transaction.tags
26
+ self.dynamic_sampling_context = transaction.get_baggage.dynamic_sampling_context
27
+
28
+ finished_spans = transaction.span_recorder.spans.select { |span| span.timestamp && span != transaction }
29
+ self.spans = finished_spans.map(&:to_hash)
30
+ end
31
+
14
32
  # Sets the event's start_timestamp.
15
33
  # @param time [Time, Float]
16
34
  # @return [void]
@@ -136,14 +136,18 @@ module Sentry
136
136
  event_id = event_payload[:event_id] || event_payload["event_id"]
137
137
  item_type = event_payload[:type] || event_payload["type"]
138
138
 
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
- )
139
+ envelope_headers = {
140
+ event_id: event_id,
141
+ dsn: @dsn.to_s,
142
+ sdk: Sentry.sdk_meta,
143
+ sent_at: Sentry.utc_now.iso8601
144
+ }
145
+
146
+ if event.is_a?(TransactionEvent) && event.dynamic_sampling_context
147
+ envelope_headers[:trace] = event.dynamic_sampling_context
148
+ end
149
+
150
+ envelope = Envelope.new(envelope_headers)
147
151
 
148
152
  envelope.add_item(
149
153
  { type: item_type, content_type: 'application/json' },
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Sentry
4
- VERSION = "5.4.1"
4
+ VERSION = "5.5.0"
5
5
  end
data/lib/sentry-ruby.rb CHANGED
@@ -39,6 +39,8 @@ module Sentry
39
39
 
40
40
  SENTRY_TRACE_HEADER_NAME = "sentry-trace".freeze
41
41
 
42
+ BAGGAGE_HEADER_NAME = "baggage".freeze
43
+
42
44
  THREAD_LOCAL = :sentry_hub
43
45
 
44
46
  class << self
@@ -348,7 +350,7 @@ module Sentry
348
350
  # @yieldparam scope [Scope]
349
351
  # @return [void]
350
352
  def with_scope(&block)
351
- return unless initialized?
353
+ return yield unless initialized?
352
354
  get_current_hub.with_scope(&block)
353
355
  end
354
356
 
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.1
4
+ version: 5.5.0
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-07-26 00:00:00.000000000 Z
11
+ date: 2022-10-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: concurrent-ruby
@@ -53,6 +53,7 @@ files:
53
53
  - lib/sentry-ruby.rb
54
54
  - lib/sentry/background_worker.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