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



279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
# File 'lib/opentelemetry/sdk/trace/span.rb', line 279

def initialize(context, parent_context, parent_span, name, kind, parent_span_id, span_limits, span_processors, attributes, links, start_timestamp, resource, instrumentation_library) # rubocop:disable Metrics/AbcSize,  Metrics/CyclomaticComplexity, 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_library = instrumentation_library
  @ended = false
  @status = DEFAULT_STATUS
  @total_recorded_events = 0
  @total_recorded_links = links&.size || 0
  @total_recorded_attributes = attributes&.size || 0
  @attributes = attributes.nil? ? nil : Hash[attributes] # We need a mutable copy of 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)
                              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_libraryObject (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 instrumentation_library
  @instrumentation_library
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



101
102
103
104
105
106
107
108
109
110
111
112
113
# File 'lib/opentelemetry/sdk/trace/span.rb', line 101

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



133
134
135
136
137
138
139
140
141
142
143
144
145
146
# File 'lib/opentelemetry/sdk/trace/span.rb', line 133

def add_event(name, attributes: nil, timestamp: nil)
  event = Event.new(name, truncate_attribute_values(attributes), 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

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



33
34
35
36
37
# File 'lib/opentelemetry/sdk/trace/span.rb', line 33

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.



44
45
46
47
48
# File 'lib/opentelemetry/sdk/trace/span.rb', line 44

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



230
231
232
233
234
235
236
237
238
239
240
241
242
243
# File 'lib/opentelemetry/sdk/trace/span.rb', line 230

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)
    @attributes = validated_attributes(@attributes).freeze
    @events.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.



158
159
160
161
162
163
164
165
166
# File 'lib/opentelemetry/sdk/trace/span.rb', line 158

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.



55
56
57
# File 'lib/opentelemetry/sdk/trace/span.rb', line 55

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



73
74
75
76
77
78
79
80
81
82
83
84
85
# File 'lib/opentelemetry/sdk/trace/span.rb', line 73

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:



255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
# File 'lib/opentelemetry/sdk/trace/span.rb', line 255

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_library,
    context.span_id,
    context.trace_id,
    context.trace_flags,
    context.tracestate
  )
end