Class: OpenTelemetry::SDK::Trace::Span

Inherits:
Trace::Span
  • Object
show all
Defined in:
lib/opentelemetry/sdk/trace/span.rb

Overview

Implementation of Trace::Span that records trace events.

This implementation includes reader methods intended to allow access to internal state by SpanProcessors. Instrumentation should use the API provided by Trace::Span and should consider Span to be write-only.

rubocop:disable Metrics/ClassLength

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(context, parent_context, parent_span, name, kind, parent_span_id, span_limits, span_processors, attributes, links, start_timestamp, resource, instrumentation_scope) ⇒ Span

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns a new instance of Span.



320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
# File 'lib/opentelemetry/sdk/trace/span.rb', line 320

def initialize(context, parent_context, parent_span, name, kind, parent_span_id, span_limits, span_processors, attributes, links, start_timestamp, resource, instrumentation_scope) # rubocop:disable Metrics/MethodLength, Metrics/PerceivedComplexity
  super(span_context: context)
  @mutex = Mutex.new
  @name = name
  @kind = kind
  @parent_span_id = parent_span_id.freeze || OpenTelemetry::Trace::INVALID_SPAN_ID
  @span_limits = span_limits
  @span_processors = span_processors
  @resource = resource
  @instrumentation_scope = instrumentation_scope
  @ended = false
  @status = DEFAULT_STATUS
  @total_recorded_events = 0
  @total_recorded_links = links&.size || 0
  @total_recorded_attributes = attributes&.size || 0
  @attributes = attributes
  trim_span_attributes(@attributes)
  @events = nil
  @links = trim_links(links, span_limits.link_count_limit, span_limits.link_attribute_count_limit)

  # Times are hard. Whenever an explicit timestamp is provided
  # (for Events or for the Span start_timestamp or end_timestamp),
  # we use that as the recorded timestamp. An implicit Event timestamp
  # and end_timestamp is computed as a monotonic clock offset from
  # the realtime start_timestamp. The realtime start_timestamp is
  # computed as a monotonic clock offset from the realtime
  # start_timestamp of its parent span, if available, or it is
  # fetched from the realtime system clock.
  #
  # We therefore have 3 start timestamps. The first two are used
  # internally (and by child spans) to compute other timestamps.
  # The last is the start timestamp actually recorded in the
  # SpanData.
  @monotonic_start_timestamp = monotonic_now
  @realtime_start_timestamp = if parent_span.recording?
                                relative_realtime(parent_span.realtime_start_timestamp, parent_span.monotonic_start_timestamp, @monotonic_start_timestamp)
                              else
                                realtime_now
                              end
  @start_timestamp = if start_timestamp
                       time_in_nanoseconds(start_timestamp)
                     else
                       @realtime_start_timestamp
                     end
  @end_timestamp = nil
  @span_processors.each { |processor| processor.on_start(self, parent_context) }
end

Instance Attribute Details

#end_timestampObject (readonly)

The following readers are intended for the use of SpanProcessors and should not be considered part of the public interface for instrumentation.



26
27
28
# File 'lib/opentelemetry/sdk/trace/span.rb', line 26

def end_timestamp
  @end_timestamp
end

#instrumentation_scopeObject (readonly) Also known as: instrumentation_library

The following readers are intended for the use of SpanProcessors and should not be considered part of the public interface for instrumentation.



26
27
28
# File 'lib/opentelemetry/sdk/trace/span.rb', line 26

def instrumentation_scope
  @instrumentation_scope
end

#kindObject (readonly)

The following readers are intended for the use of SpanProcessors and should not be considered part of the public interface for instrumentation.



26
27
28
# File 'lib/opentelemetry/sdk/trace/span.rb', line 26

def kind
  @kind
end

The following readers are intended for the use of SpanProcessors and should not be considered part of the public interface for instrumentation.



26
27
28
# File 'lib/opentelemetry/sdk/trace/span.rb', line 26

def links
  @links
end

#nameObject

The following readers are intended for the use of SpanProcessors and should not be considered part of the public interface for instrumentation.



26
27
28
# File 'lib/opentelemetry/sdk/trace/span.rb', line 26

def name
  @name
end

#parent_span_idObject (readonly)

The following readers are intended for the use of SpanProcessors and should not be considered part of the public interface for instrumentation.



26
27
28
# File 'lib/opentelemetry/sdk/trace/span.rb', line 26

def parent_span_id
  @parent_span_id
end

#resourceObject (readonly)

The following readers are intended for the use of SpanProcessors and should not be considered part of the public interface for instrumentation.



26
27
28
# File 'lib/opentelemetry/sdk/trace/span.rb', line 26

def resource
  @resource
end

#start_timestampObject (readonly)

The following readers are intended for the use of SpanProcessors and should not be considered part of the public interface for instrumentation.



26
27
28
# File 'lib/opentelemetry/sdk/trace/span.rb', line 26

def start_timestamp
  @start_timestamp
end

#statusObject

The following readers are intended for the use of SpanProcessors and should not be considered part of the public interface for instrumentation.



26
27
28
# File 'lib/opentelemetry/sdk/trace/span.rb', line 26

def status
  @status
end

Instance Method Details

#add_attributes(attributes) ⇒ self

Add attributes

Note that the OpenTelemetry project documents certain "standard attributes" that have prescribed semantic meanings.

Parameters:

  • attributes (Hash{String => String, Numeric, Boolean, Array<String, Numeric, Boolean>})

    Values must be non-nil and (array of) string, boolean or numeric type. Array values must not contain nil elements and all elements must be of the same basic type (string, numeric, boolean).

Returns:

  • (self)

    returns itself



107
108
109
110
111
112
113
114
115
116
117
118
119
# File 'lib/opentelemetry/sdk/trace/span.rb', line 107

def add_attributes(attributes)
  @mutex.synchronize do
    if @ended
      OpenTelemetry.logger.warn('Calling add_attributes on an ended Span.')
    else
      @attributes ||= {}
      @attributes.merge!(attributes)
      trim_span_attributes(@attributes)
      @total_recorded_attributes += attributes.size
    end
  end
  self
end

#add_event(name, attributes: nil, timestamp: nil) ⇒ self

Add an Event to a OpenTelemetry::SDK::Trace::Span.

Example:

span.add_event('event', attributes: => true)

Note that the OpenTelemetry project documents certain "standard event names and keys" which have prescribed semantic meanings.

Parameters:

  • name (String)

    Name of the event.

  • attributes (optional Hash{String => String, Numeric, Boolean, Array<String, Numeric, Boolean>}) (defaults to: nil)

    One or more key:value pairs, where the keys must be strings and the values may be (array of) string, boolean or numeric type.

  • timestamp (optional Time) (defaults to: nil)

    Optional timestamp for the event.

Returns:

  • (self)

    returns itself



170
171
172
173
174
175
176
177
178
179
180
181
182
183
# File 'lib/opentelemetry/sdk/trace/span.rb', line 170

def add_event(name, attributes: nil, timestamp: nil)
  event = Event.new(name, truncate_attribute_values(attributes, @span_limits.event_attribute_length_limit), relative_timestamp(timestamp))

  @mutex.synchronize do
    if @ended
      OpenTelemetry.logger.warn('Calling add_event on an ended Span.')
    else
      @events ||= []
      @events = append_event(@events, event)
      @total_recorded_events += 1
    end
  end
  self
end

Add a link to a OpenTelemetry::SDK::Trace::Span.

Adding links at span creation using the links option is preferred to calling add_link later, because head sampling decisions can only consider information present during span creation.

Example:

span.add_link(OpenTelemetry::Trace::Link.new(span_to_link_from.context))

Note that the OpenTelemetry project documents certain "standard attributes" that have prescribed semantic meanings.

Parameters:

Returns:

  • (self)

    returns itself



139
140
141
142
143
144
145
146
147
148
149
150
# File 'lib/opentelemetry/sdk/trace/span.rb', line 139

def add_link(link)
  @mutex.synchronize do
    if @ended
      OpenTelemetry.logger.warn('Calling add_link on an ended Span.')
    else
      @links ||= []
      @links = trim_links(@links << link, @span_limits.link_count_limit, @span_limits.link_attribute_count_limit)
      @total_recorded_links += 1
    end
  end
  self
end

#attributesHash{String => String, Numeric, Boolean, Array<String, Numeric, Boolean>}

Return a frozen copy of the current attributes. This is intended for use of SpanProcessors and should not be considered part of the public interface for instrumentation.

Returns:

  • (Hash{String => String, Numeric, Boolean, Array<String, Numeric, Boolean>})

    may be nil.



39
40
41
42
43
# File 'lib/opentelemetry/sdk/trace/span.rb', line 39

def attributes
  # Don't bother synchronizing. Access by SpanProcessors is expected to
  # be serialized.
  @attributes&.clone.freeze
end

#eventsArray<Event>

Return a frozen copy of the current events. This is intended for use of SpanProcessors and should not be considered part of the public interface for instrumentation.

Returns:

  • (Array<Event>)

    may be nil.



50
51
52
53
54
# File 'lib/opentelemetry/sdk/trace/span.rb', line 50

def events
  # Don't bother synchronizing. Access by SpanProcessors is expected to
  # be serialized.
  @events&.clone.freeze
end

#finish(end_timestamp: nil) ⇒ self

Finishes the Span

Implementations MUST ignore all subsequent calls to #finish (there might be exceptions when Tracer is streaming event and has no mutable state associated with the Span).

Call to #finish MUST not have any effects on child spans. Those may still be running and can be ended later.

This API MUST be non-blocking*.

(*) not actually non-blocking. In particular, it synchronizes on an internal mutex, which will typically be uncontended, and Export::BatchSpanProcessor will also synchronize on a mutex, if that processor is used.

Parameters:

  • end_timestamp (Time) (defaults to: nil)

    optional end timestamp for the span.

Returns:

  • (self)

    returns itself



267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
# File 'lib/opentelemetry/sdk/trace/span.rb', line 267

def finish(end_timestamp: nil)
  @mutex.synchronize do
    if @ended
      OpenTelemetry.logger.warn('Calling finish on an ended Span.')
      return self
    end
    @end_timestamp = relative_timestamp(end_timestamp)
    @span_processors.each do |processor|
      processor.on_finishing(self) if processor.respond_to?(:on_finishing)
    end
    @attributes = validated_attributes(@attributes).freeze
    @events.freeze
    @links.freeze
    @ended = true
  end
  @span_processors.each { |processor| processor.on_finish(self) }
  self
end

#record_exception(exception, attributes: nil) ⇒ void

This method returns an undefined value.

Record an exception during the execution of this span. Multiple exceptions can be recorded on a span.

Parameters:

  • exception (Exception)

    The exception to be recorded

  • attributes (optional Hash{String => String, Numeric, Boolean, Array<String, Numeric, Boolean>}) (defaults to: nil)

    One or more key:value pairs, where the keys must be strings and the values may be (array of) string, boolean or numeric type.



195
196
197
198
199
200
201
202
203
# File 'lib/opentelemetry/sdk/trace/span.rb', line 195

def record_exception(exception, attributes: nil)
  event_attributes = {
    'exception.type' => exception.class.to_s,
    'exception.message' => exception.message,
    'exception.stacktrace' => exception.full_message(highlight: false, order: :top).encode('UTF-8', invalid: :replace, undef: :replace, replace: '')
  }
  event_attributes.merge!(attributes) unless attributes.nil?
  add_event('exception', attributes: event_attributes)
end

#recording?Boolean

Return the flag whether this span is recording events

Returns:

  • (Boolean)

    true if this Span is active and recording information like events with the #add_event operation and attributes using

    set_attribute.



61
62
63
# File 'lib/opentelemetry/sdk/trace/span.rb', line 61

def recording?
  !@ended
end

#set_attribute(key, value) ⇒ self Also known as: []=

Set attribute

Note that the OpenTelemetry project documents certain "standard attributes" that have prescribed semantic meanings.

Parameters:

  • key (String)
  • value (String, Boolean, Numeric, Array<String, Numeric, Boolean>)

    Values must be non-nil and (array of) string, boolean or numeric type. Array values must not contain nil elements and all elements must be of the same basic type (string, numeric, boolean).

Returns:

  • (self)

    returns itself



79
80
81
82
83
84
85
86
87
88
89
90
91
# File 'lib/opentelemetry/sdk/trace/span.rb', line 79

def set_attribute(key, value)
  @mutex.synchronize do
    if @ended
      OpenTelemetry.logger.warn('Calling set_attribute on an ended Span.')
    else
      @attributes ||= {}
      @attributes[key] = value
      trim_span_attributes(@attributes)
      @total_recorded_attributes += 1
    end
  end
  self
end

#to_span_dataSpanData

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns a SpanData containing a snapshot of the Span fields. It is assumed that the Span has been finished, and that no further modifications will be made to the Span.

This method should be called only from a SpanProcessor prior to calling the SpanExporter.

Returns:



296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
# File 'lib/opentelemetry/sdk/trace/span.rb', line 296

def to_span_data
  SpanData.new(
    @name,
    @kind,
    @status,
    @parent_span_id,
    @total_recorded_attributes,
    @total_recorded_events,
    @total_recorded_links,
    @start_timestamp,
    @end_timestamp,
    @attributes,
    @links,
    @events,
    @resource,
    @instrumentation_scope,
    context.span_id,
    context.trace_id,
    context.trace_flags,
    context.tracestate
  )
end