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>".freeze
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_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, **options) ⇒ Transaction

Returns a new instance of Transaction.



63
64
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
# File 'lib/sentry/transaction.rb', line 63

def initialize(
  hub:,
  name: nil,
  source: :custom,
  parent_sampled: nil,
  baggage: 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
  @logger = hub.configuration.logger
  @release = hub.configuration.release
  @environment = hub.configuration.environment
  @dsn = hub.configuration.dsn
  @effective_sample_rate = nil
  @contexts = {}
  @measurements = {}
  @profiler = Profiler.new(@configuration)
  init_span_recorder
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:



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

def baggage
  @baggage
end

#configurationObject (readonly)

Deprecated.

Use Sentry.configuration instead.



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

def configuration
  @configuration
end

#contextsHash (readonly)

Additional contexts stored directly on the transaction object.

Returns:

  • (Hash)


57
58
59
# File 'lib/sentry/transaction.rb', line 57

def contexts
  @contexts
end

#effective_sample_rateFloat? (readonly)

The effective sample rate at which this transaction was sampled.

Returns:

  • (Float, nil)


53
54
55
# File 'lib/sentry/transaction.rb', line 53

def effective_sample_rate
  @effective_sample_rate
end

#hubObject (readonly)

Deprecated.

Use Sentry.get_current_hub instead.



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

def hub
  @hub
end

#loggerObject (readonly)

Deprecated.

Use Sentry.logger instead.



49
50
51
# File 'lib/sentry/transaction.rb', line 49

def logger
  @logger
end

#measurementsHash (readonly)

The measurements added to the transaction.

Returns:

  • (Hash)


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

def measurements
  @measurements
end

#nameString (readonly)

The name of the transaction.

Returns:

  • (String)


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

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)


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

def parent_sampled
  @parent_sampled
end

#profilerProfiler (readonly)

The Profiler instance for this transaction.

Returns:



61
62
63
# File 'lib/sentry/transaction.rb', line 61

def profiler
  @profiler
end

#sourceSymbol (readonly)

The source of the transaction name.

Returns:

  • (Symbol)


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

def source
  @source
end

Class Method Details

.extract_sentry_trace(sentry_trace) ⇒ Array?

Deprecated.

Use Sentry::PropagationContext.extract_sentry_trace instead.

Returns:

  • (Array, nil)


137
138
139
# File 'lib/sentry/transaction.rb', line 137

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:



104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
# File 'lib/sentry/transaction.rb', line 104

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!

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

Instance Method Details

#deep_dupTransaction

Returns:



156
157
158
159
160
161
162
163
164
165
166
167
# File 'lib/sentry/transaction.rb', line 156

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:



242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
# File 'lib/sentry/transaction.rb', line 242

def finish(hub: nil, end_timestamp: nil)
  if hub
    log_warn(
      <<~MSG
        Specifying a different hub in `Transaction#finish` will be deprecated in version 5.0.
        Please use `Hub#start_transaction` with the designated hub.
      MSG
    )
  end

  hub ||= @hub

  super(end_timestamp: end_timestamp)

  if @name.nil?
    @name = UNLABELD_NAME
  end

  @profiler.stop

  if @sampled
    event = hub.current_client.event_from_transaction(self)
    hub.capture_event(event)
  else
    is_backpressure = Sentry.backpressure_monitor&.downsample_factor&.positive?
    reason = is_backpressure ? :backpressure : :sample_rate
    hub.current_client.transport.record_lost_event(reason, 'transaction')
    hub.current_client.transport.record_lost_event(reason, 'span')
  end
end

#get_baggageBaggage

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

Returns:



276
277
278
279
# File 'lib/sentry/transaction.rb', line 276

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

#set_context(key, value) ⇒ void

This method returns an undefined value.

Set contexts directly on the transaction.

Parameters:

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


295
296
297
# File 'lib/sentry/transaction.rb', line 295

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



181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
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
# File 'lib/sentry/transaction.rb', line 181

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 = Random.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



174
175
176
# File 'lib/sentry/transaction.rb', line 174

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)


286
287
288
289
# File 'lib/sentry/transaction.rb', line 286

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)


307
308
309
# File 'lib/sentry/transaction.rb', line 307

def source_low_quality?
  source == :url
end

#start_profiler!void

This method returns an undefined value.

Start the profiler.



301
302
303
304
# File 'lib/sentry/transaction.rb', line 301

def start_profiler!
  profiler.set_initial_sample_decision(sampled)
  profiler.start
end

#to_hashHash

Returns:

  • (Hash)


142
143
144
145
146
147
148
149
150
151
152
153
# File 'lib/sentry/transaction.rb', line 142

def to_hash
  hash = super

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

  hash
end