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, **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
91
92
93
94
# 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 = {}

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

  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)

141
142
143
# File 'lib/sentry/transaction.rb', line 141

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:


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
134
135
136
137
# File 'lib/sentry/transaction.rb', line 108

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:


160
161
162
163
164
165
166
167
168
169
170
171
# File 'lib/sentry/transaction.rb', line 160

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:


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
272
273
274
275
# File 'lib/sentry/transaction.rb', line 246

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

  @hub.stop_profiler!(self)

  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:


280
281
282
283
# File 'lib/sentry/transaction.rb', line 280

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)

299
300
301
# File 'lib/sentry/transaction.rb', line 299

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


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
238
239
240
241
# File 'lib/sentry/transaction.rb', line 185

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


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

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)

290
291
292
293
# File 'lib/sentry/transaction.rb', line 290

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)

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

def source_low_quality?
  source == :url
end

#start_profiler!void

This method returns an undefined value.

Start the profiler.


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

def start_profiler!
  return unless profiler

  profiler.set_initial_sample_decision(sampled)
  profiler.start
end

#to_hashHash

Returns:

  • (Hash)

146
147
148
149
150
151
152
153
154
155
156
157
# File 'lib/sentry/transaction.rb', line 146

def to_hash
  hash = super

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

  hash
end