Class: Sentry::Transaction

Inherits:
Span
  • Object
show all
Includes:
LoggingHelper
Defined in:
lib/sentry/transaction.rb

Defined Under Namespace

Classes: SpanRecorder

Constant Summary collapse

SENTRY_TRACE_REGEXP =
Deprecated.

Use Sentry::PropagationContext::SENTRY_TRACE_REGEXP instead.

PropagationContext::SENTRY_TRACE_REGEXP
UNLABELD_NAME =
"<unlabeled transaction>"
MESSAGE_PREFIX =
"[Tracing]"
SOURCES =
i[custom url route view component task]

Constants inherited from Span

Span::DEFAULT_SPAN_ORIGIN, Span::STATUS_MAP

Instance Attribute Summary collapse

Attributes inherited from Span

#data, #description, #op, #origin, #parent_span_id, #sampled, #span_id, #span_recorder, #start_timestamp, #status, #tags, #timestamp, #trace_id, #transaction

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Span

#get_dynamic_sampling_context, #get_trace_context, #metrics_local_aggregator, #metrics_summary, #set_data, #set_description, #set_http_status, #set_op, #set_origin, #set_status, #set_tag, #set_timestamp, #start_child, #to_baggage, #to_sentry_trace, #with_child_span

Constructor Details

#initialize(hub:, name: nil, source: :custom, parent_sampled: nil, baggage: nil, sample_rand: nil, **options) ⇒ Transaction

Returns a new instance of Transaction.



65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
# File 'lib/sentry/transaction.rb', line 65

def initialize(
  hub:,
  name: nil,
  source: :custom,
  parent_sampled: nil,
  baggage: nil,
  sample_rand: nil,
  **options
)
  super(transaction: self, **options)

  set_name(name, source: source)
  @parent_sampled = parent_sampled
  @hub = hub
  @baggage = baggage
  @configuration = hub.configuration # to be removed
  @tracing_enabled = hub.configuration.tracing_enabled?
  @traces_sampler = hub.configuration.traces_sampler
  @traces_sample_rate = hub.configuration.traces_sample_rate
  @sdk_logger = hub.configuration.sdk_logger
  @release = hub.configuration.release
  @environment = hub.configuration.environment
  @dsn = hub.configuration.dsn
  @effective_sample_rate = nil
  @contexts = {}
  @measurements = {}
  @sample_rand = sample_rand

  unless @hub.profiler_running?
    @profiler = @configuration.profiler_class.new(@configuration)
  end

  init_span_recorder

  unless @sample_rand
    generator = Utils::SampleRand.new(trace_id: @trace_id)
    @sample_rand = generator.generate_from_trace_id
  end
end

Instance Attribute Details

#baggageBaggage? (readonly)

The parsed incoming W3C baggage header. This is only for accessing the current baggage variable. Please use the #get_baggage method for interfacing outside this class.

Returns:



37
38
39
# File 'lib/sentry/transaction.rb', line 37

def baggage
  @baggage
end

#configurationObject (readonly)

Deprecated.

Use Sentry.configuration instead.



47
48
49
# File 'lib/sentry/transaction.rb', line 47

def configuration
  @configuration
end

#contextsHash (readonly)

Additional contexts stored directly on the transaction object.

Returns:

  • (Hash)


55
56
57
# File 'lib/sentry/transaction.rb', line 55

def contexts
  @contexts
end

#effective_sample_rateFloat? (readonly)

The effective sample rate at which this transaction was sampled.

Returns:

  • (Float, nil)


51
52
53
# File 'lib/sentry/transaction.rb', line 51

def effective_sample_rate
  @effective_sample_rate
end

#hubObject (readonly)

Deprecated.

Use Sentry.get_current_hub instead.



44
45
46
# File 'lib/sentry/transaction.rb', line 44

def hub
  @hub
end

#measurementsHash (readonly)

The measurements added to the transaction.

Returns:

  • (Hash)


41
42
43
# File 'lib/sentry/transaction.rb', line 41

def measurements
  @measurements
end

#nameString (readonly)

The name of the transaction.

Returns:

  • (String)


23
24
25
# File 'lib/sentry/transaction.rb', line 23

def name
  @name
end

#parent_sampledString (readonly)

The sampling decision of the parent transaction, which will be considered when making the current transaction’s sampling decision.

Returns:

  • (String)


31
32
33
# File 'lib/sentry/transaction.rb', line 31

def parent_sampled
  @parent_sampled
end

#profilerProfiler (readonly)

The Profiler instance for this transaction.

Returns:



59
60
61
# File 'lib/sentry/transaction.rb', line 59

def profiler
  @profiler
end

#sample_randString (readonly)

Sample rand value generated from trace_id

Returns:

  • (String)


63
64
65
# File 'lib/sentry/transaction.rb', line 63

def sample_rand
  @sample_rand
end

#sourceSymbol (readonly)

The source of the transaction name.

Returns:

  • (Symbol)


27
28
29
# File 'lib/sentry/transaction.rb', line 27

def source
  @source
end

Class Method Details

.extract_sample_rand_from_baggage(baggage, trace_id, parent_sampled) ⇒ Object



157
158
159
160
# File 'lib/sentry/transaction.rb', line 157

def self.extract_sample_rand_from_baggage(baggage, trace_id, parent_sampled)
  PropagationContext.extract_sample_rand_from_baggage(baggage, trace_id) ||
    PropagationContext.generate_sample_rand(baggage, trace_id, parent_sampled)
end

.extract_sentry_trace(sentry_trace) ⇒ Array?

Deprecated.

Use Sentry::PropagationContext.extract_sentry_trace instead.

Returns:

  • (Array, nil)


153
154
155
# File 'lib/sentry/transaction.rb', line 153

def self.extract_sentry_trace(sentry_trace)
  PropagationContext.extract_sentry_trace(sentry_trace)
end

.from_sentry_trace(sentry_trace, baggage: nil, hub: Sentry.get_current_hub, **options) ⇒ Transaction?

Deprecated.

use Sentry.continue_trace instead.

Initalizes a Transaction instance with a Sentry trace string from another transaction (usually from an external request).

The original transaction will become the parent of the new Transaction instance. And they will share the same ‘trace_id`.

The child transaction will also store the parent’s sampling decision in its ‘parent_sampled` attribute.

Parameters:

  • sentry_trace (String)

    the trace string from the previous transaction.

  • baggage (String, nil) (defaults to: nil)

    the incoming baggage header string.

  • hub (Hub) (defaults to: Sentry.get_current_hub)

    the hub that’ll be responsible for sending this transaction when it’s finished.

  • options (Hash)

    the options you want to use to initialize a Transaction instance.

Returns:



117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
# File 'lib/sentry/transaction.rb', line 117

def self.from_sentry_trace(sentry_trace, baggage: nil, hub: Sentry.get_current_hub, **options)
  return unless hub.configuration.tracing_enabled?
  return unless sentry_trace

  sentry_trace_data = extract_sentry_trace(sentry_trace)
  return unless sentry_trace_data

  trace_id, parent_span_id, parent_sampled = sentry_trace_data

  baggage =
    if baggage && !baggage.empty?
      Baggage.from_incoming_header(baggage)
    else
      # If there's an incoming sentry-trace but no incoming baggage header,
      # for instance in traces coming from older SDKs,
      # baggage will be empty and frozen and won't be populated as head SDK.
      Baggage.new({})
    end

  baggage.freeze!

  sample_rand = extract_sample_rand_from_baggage(baggage, trace_id, parent_sampled)

  new(
    trace_id: trace_id,
    parent_span_id: parent_span_id,
    parent_sampled: parent_sampled,
    hub: hub,
    baggage: baggage,
    sample_rand: sample_rand,
    **options
  )
end

Instance Method Details

#deep_dupTransaction

Returns:



184
185
186
187
188
189
190
191
192
193
194
195
# File 'lib/sentry/transaction.rb', line 184

def deep_dup
  copy = super
  copy.init_span_recorder(@span_recorder.max_length)

  @span_recorder.spans.each do |span|
    # span_recorder's first span is the current span, which should not be added to the copy's spans
    next if span == self
    copy.span_recorder.add(span.dup)
  end

  copy
end

#finish(hub: nil, end_timestamp: nil) ⇒ TransactionEvent

Finishes the transaction’s recording and send it to Sentry.

Parameters:

  • hub (Hub) (defaults to: nil)

    the hub that’ll send this transaction. (Deprecated)

Returns:



270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
# File 'lib/sentry/transaction.rb', line 270

def finish(hub: nil, end_timestamp: nil)
  if hub
    log_warn(
      "        Specifying a different hub in `Transaction#finish` will be deprecated in version 5.0.\n        Please use `Hub#start_transaction` with the designated hub.\n      MSG\n    )\n  end\n\n  hub ||= @hub\n\n  super(end_timestamp: end_timestamp)\n\n  if @name.nil?\n    @name = UNLABELD_NAME\n  end\n\n  @hub.stop_profiler!(self)\n\n  if @sampled\n    event = hub.current_client.event_from_transaction(self)\n    hub.capture_event(event)\n  else\n    is_backpressure = Sentry.backpressure_monitor&.downsample_factor&.positive?\n    reason = is_backpressure ? :backpressure : :sample_rate\n    hub.current_client.transport.record_lost_event(reason, \"transaction\")\n    hub.current_client.transport.record_lost_event(reason, \"span\")\n  end\nend\n"

#get_baggageBaggage

Get the existing frozen incoming baggage or populate one with sentry- items as the head SDK.

Returns:



304
305
306
307
# File 'lib/sentry/transaction.rb', line 304

def get_baggage
  populate_head_baggage if @baggage.nil? || @baggage.mutable
  @baggage
end

#parent_sample_rateObject



176
177
178
179
180
181
# File 'lib/sentry/transaction.rb', line 176

def parent_sample_rate
  return unless @baggage&.items

  sample_rate_str = @baggage.items["sample_rate"]
  sample_rate_str&.to_f
end

#set_context(key, value) ⇒ void

This method returns an undefined value.

Set contexts directly on the transaction.

Parameters:

  • key (String, Symbol)
  • value (Object)


323
324
325
# File 'lib/sentry/transaction.rb', line 323

def set_context(key, value)
  @contexts[key] = value
end

#set_initial_sample_decision(sampling_context:) ⇒ void

This method returns an undefined value.

Sets initial sampling decision of the transaction.

Parameters:

  • sampling_context (Hash)

    a context Hash that’ll be passed to ‘traces_sampler` (if provided).



209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
# File 'lib/sentry/transaction.rb', line 209

def set_initial_sample_decision(sampling_context:)
  unless @tracing_enabled
    @sampled = false
    return
  end

  unless @sampled.nil?
    @effective_sample_rate = @sampled ? 1.0 : 0.0
    return
  end

  sample_rate =
    if @traces_sampler.is_a?(Proc)
      @traces_sampler.call(sampling_context)
    elsif !sampling_context[:parent_sampled].nil?
      sampling_context[:parent_sampled]
    else
      @traces_sample_rate
    end

  transaction_description = generate_transaction_description

  if [true, false].include?(sample_rate)
    @effective_sample_rate = sample_rate ? 1.0 : 0.0
  elsif sample_rate.is_a?(Numeric) && sample_rate >= 0.0 && sample_rate <= 1.0
    @effective_sample_rate = sample_rate.to_f
  else
    @sampled = false
    log_warn("#{MESSAGE_PREFIX} Discarding #{transaction_description} because of invalid sample_rate: #{sample_rate}")
    return
  end

  if sample_rate == 0.0 || sample_rate == false
    @sampled = false
    log_debug("#{MESSAGE_PREFIX} Discarding #{transaction_description} because traces_sampler returned 0 or false")
    return
  end

  if sample_rate == true
    @sampled = true
  else
    if Sentry.backpressure_monitor
      factor = Sentry.backpressure_monitor.downsample_factor
      @effective_sample_rate /= 2**factor
    end

    @sampled = @sample_rand < @effective_sample_rate
  end

  if @sampled
    log_debug("#{MESSAGE_PREFIX} Starting #{transaction_description}")
  else
    log_debug(
      "#{MESSAGE_PREFIX} Discarding #{transaction_description} because it's not included in the random sample (sampling rate = #{sample_rate})"
    )
  end
end

#set_measurement(name, value, unit = "") ⇒ void

This method returns an undefined value.

Sets a custom measurement on the transaction.

Parameters:

  • name (String)

    name of the measurement

  • value (Float)

    value of the measurement

  • unit (String) (defaults to: "")

    unit of the measurement



202
203
204
# File 'lib/sentry/transaction.rb', line 202

def set_measurement(name, value, unit = "")
  @measurements[name] = { value: value, unit: unit }
end

#set_name(name, source: :custom) ⇒ void

This method returns an undefined value.

Set the transaction name directly. Considered internal api since it bypasses the usual scope logic.

Parameters:

  • name (String)
  • source (Symbol) (defaults to: :custom)


314
315
316
317
# File 'lib/sentry/transaction.rb', line 314

def set_name(name, source: :custom)
  @name = name
  @source = SOURCES.include?(source) ? source.to_sym : :custom
end

#source_low_quality?Boolean

These are high cardinality and thus bad

Returns:

  • (Boolean)


337
338
339
# File 'lib/sentry/transaction.rb', line 337

def source_low_quality?
  source == :url
end

#start_profiler!void

This method returns an undefined value.

Start the profiler.



329
330
331
332
333
334
# File 'lib/sentry/transaction.rb', line 329

def start_profiler!
  return unless profiler

  profiler.set_initial_sample_decision(sampled)
  profiler.start
end

#to_hashHash

Returns:

  • (Hash)


163
164
165
166
167
168
169
170
171
172
173
174
# File 'lib/sentry/transaction.rb', line 163

def to_hash
  hash = super

  hash.merge!(
    name: @name,
    source: @source,
    sampled: @sampled,
    parent_sampled: @parent_sampled
  )

  hash
end