class Instana::Span

Constants

ENTRY_SPANS
EXIT_SPANS
HTTP_SPANS
REGISTERED_SPANS

Attributes

baggage[RW]
context[RW]
is_root[RW]
parent[RW]

Public Class Methods

new(name, parent_ctx: nil, start_time: ::Instana::Util.now_in_ms) click to toggle source
# File lib/instana/tracing/span.rb, line 23
def initialize(name, parent_ctx: nil, start_time: ::Instana::Util.now_in_ms)
  @data = {}

  if parent_ctx.is_a?(::Instana::Span)
    @parent = parent_ctx
    parent_ctx = parent_ctx.context
  end

  if parent_ctx.is_a?(::Instana::SpanContext)
    @is_root = false

    # If we have a parent trace, link to it
    if parent_ctx.trace_id
      @data[:t] = parent_ctx.trace_id       # Trace ID
      @data[:p] = parent_ctx.span_id        # Parent ID
    else
      @data[:t] = ::Instana::Util.generate_id
    end

    @data[:s] = ::Instana::Util.generate_id # Span ID

    @baggage = parent_ctx.baggage.dup
    @level = parent_ctx.level
  else
    # No parent specified so we're starting a new Trace - this will be the root span
    @is_root = true
    @level = 1

    id = ::Instana::Util.generate_id
    @data[:t] = id                    # Trace ID
    @data[:s] = id                    # Span ID
  end

  @data[:data] = {}

  # Entity Source
  @data[:f] = ::Instana.agent.source
  # Start time
  if start_time.is_a?(Time)
    @data[:ts] = ::Instana::Util.time_to_ms(start_time)
  else
    @data[:ts] = start_time
  end

  # Check for custom tracing
  if REGISTERED_SPANS.include?(name.to_sym)
    @data[:n] = name.to_sym
  else
    configure_custom(name)
  end

  ::Instana.processor.start_span(self)

  # Attach a backtrace to all exit spans
  add_stack if ::Instana.config[:collect_backtraces] && exit_span?
end

Public Instance Methods

[](key) click to toggle source

Hash accessor to the internal @data hash

# File lib/instana/tracing/span.rb, line 248
def [](key)
  @data[key.to_sym]
end
[]=(key, value) click to toggle source

Hash setter to the internal @data hash

# File lib/instana/tracing/span.rb, line 254
def []=(key, value)
  @data[key.to_sym] = value
end
add_error(e) click to toggle source

Log an error into the span

@param e [Exception] The exception to be logged

# File lib/instana/tracing/span.rb, line 101
def add_error(e)
  @data[:error] = true

  if @data.key?(:ec)
    @data[:ec] = @data[:ec] + 1
  else
    @data[:ec] = 1
  end

  # If a valid exception has been passed in, log the information about it
  # In case of just logging an error for things such as HTTP client 5xx
  # responses, an exception/backtrace may not exist.
  if e
    if e.backtrace.is_a?(Array)
      add_stack(stack: e.backtrace)
    end

    if HTTP_SPANS.include?(@data[:n])
      set_tags(:http => { :error => "#{e.class}: #{e.message}" })
    elsif @data[:n] == :activerecord
      @data[:data][:activerecord][:error] = e.message
    else
      log(:error, Time.now, { :message => e.message, :parameters => e.class.to_s })
    end
    e.instance_variable_set(:@instana_logged, true)
  end
  self
end
add_stack(limit: 30, stack: Kernel.caller) click to toggle source

Adds a backtrace to this span

@param limit [Integer] Limit the backtrace to the top <limit> frames

# File lib/instana/tracing/span.rb, line 84
def add_stack(limit: 30, stack: Kernel.caller)
  @data[:stack] = stack
                  .map do |call|
    file, line, *method = call.split(':')

    {
      c: file,
      n: line,
      m: method.join(' ')
    }
  end.take(limit > 40 ? 40 : limit)
end
close(end_time = ::Instana::Util.now_in_ms) click to toggle source

Closes out the span. This difference between this and the finish method tells us how the tracing is being performed (with OpenTracing or Instana default)

@param end_time [Time] custom end time, if not now @return [Span]

# File lib/instana/tracing/span.rb, line 163
def close(end_time = ::Instana::Util.now_in_ms)
  if end_time.is_a?(Time)
    end_time = ::Instana::Util.time_to_ms(end_time)
  end

  @data[:d] = end_time - @data[:ts]

  # Add this span to the queue for reporting
  ::Instana.processor.add_span(self)

  self
end
configure_custom(name) click to toggle source

Configure this span to be a custom span per the SDK generic span type.

Default to an intermediate kind span. Can be overridden by setting a span.kind tag.

@param name [String] name of the span @param kvs [Hash] list of key values to be reported in the span

# File lib/instana/tracing/span.rb, line 140
def configure_custom(name)
  @data[:n] = :sdk
  @data[:data] = { :sdk => { :name => name.to_sym } }
  @data[:data][:sdk][:custom] = { :tags => {}, :logs => {} }

  if @is_root
    # For custom root spans (via SDK or opentracing), default to entry type
    @data[:k] = 1
    @data[:data][:sdk][:type] = :entry
  else
    @data[:k] = 3
    @data[:data][:sdk][:type] = :intermediate
  end
  self
end
custom?() click to toggle source

Indicates whether this span is a custom or registered Span

# File lib/instana/tracing/span.rb, line 271
def custom?
  @data[:n] == :sdk
end
duration() click to toggle source

Get the duration value for this Span

@return [Integer] the duration in milliseconds

# File lib/instana/tracing/span.rb, line 242
def duration
  @data[:d]
end
exit_span?() click to toggle source

Check to see if the current span indicates an exit from application code and into an external service

# File lib/instana/tracing/span.rb, line 281
def exit_span?
  EXIT_SPANS.include?(@data[:n])
end
finish(end_time = ::Instana::Util.now_in_ms) click to toggle source

Finish the {Span} Spec: OpenTracing API

@param end_time [Time] custom end time, if not now

# File lib/instana/tracing/span.rb, line 419
def finish(end_time = ::Instana::Util.now_in_ms)
  close(end_time)
  self
end
get_baggage_item(key) click to toggle source

Get a baggage item Spec: OpenTracing API

@param key [String] the key of the baggage item @return Value of the baggage item

# File lib/instana/tracing/span.rb, line 380
def get_baggage_item(key)
  @baggage[key]
end
id() click to toggle source

Retrieve the ID for this span

@return [Integer] the span ID

# File lib/instana/tracing/span.rb, line 191
def id
  @data[:s]
end
inspect() click to toggle source
# File lib/instana/tracing/span.rb, line 275
def inspect
  @data.inspect
end
key?(k) click to toggle source

Hash key query to the internal @data hash

# File lib/instana/tracing/span.rb, line 260
def key?(k)
  @data.key?(k.to_sym)
end
log(event = nil, timestamp = Time.now, **fields) click to toggle source

Add a log entry to this span Spec: OpenTracing API

@param event [String] event name for the log @param timestamp [Time] time of the log @param fields [Hash] Additional information to log

# File lib/instana/tracing/span.rb, line 402
def log(event = nil, timestamp = Time.now, **fields)
  ts = ::Instana::Util.time_to_ms(timestamp).to_s
  if custom?
    @data[:data][:sdk][:custom][:logs][ts] = fields
    @data[:data][:sdk][:custom][:logs][ts][:event] = event
  else
    set_tags(:log => fields)
  end
rescue StandardError => e
  Instana.logger.debug { "#{__method__}:#{File.basename(__FILE__)}:#{__LINE__}: #{e.message}" }
end
name() click to toggle source

Get the name (operation) of this Span

@return [String] or [Symbol] representing the span name

# File lib/instana/tracing/span.rb, line 219
def name
  if custom?
    @data[:data][:sdk][:name]
  else
    @data[:n]
  end
end
name=(n) click to toggle source

Set the name (operation) for this Span

@params name [String] or [Symbol]

# File lib/instana/tracing/span.rb, line 231
def name=(n)
  if custom?
    @data[:data][:sdk][:name] = n
  else
    @data[:n] = n
  end
end
operation_name=(name) click to toggle source

Set the name of the operation Spec: OpenTracing API

@params name [String] or [Symbol]

# File lib/instana/tracing/span.rb, line 294
def operation_name=(name)
  @data[:n] = name
end
parent_id() click to toggle source

Retrieve the parent ID of this span

@return [Integer] parent span ID

# File lib/instana/tracing/span.rb, line 205
def parent_id
  @data[:p]
end
parent_id=(id) click to toggle source

Set the parent ID of this span

@return [Integer] parent span ID

# File lib/instana/tracing/span.rb, line 212
def parent_id=(id)
  @data[:p] = id
end
raw() click to toggle source

Get the raw @data hash that summarizes this span

# File lib/instana/tracing/span.rb, line 266
def raw
  @data
end
set_baggage_item(key, value) click to toggle source

Set a baggage item on the span Spec: OpenTracing API

@param key [String] the key of the baggage item @param value [String] the value of the baggage item

# File lib/instana/tracing/span.rb, line 361
def set_baggage_item(key, value)
  @baggage ||= {}
  @baggage[key] = value

  # Init/Update the SpanContext item
  if @context
    @context.baggage = @baggage
  else
    @context ||= ::Instana::SpanContext.new(@data[:t], @data[:s], @level, @baggage)
  end
  self
end
set_tag(key, value) click to toggle source

Set a tag value on this span Spec: OpenTracing API

@param key [String] the key of the tag @param value [String, Numeric, Boolean] the value of the tag. If it's not a String, Numeric, or Boolean it will be encoded with to_s

# File lib/instana/tracing/span.rb, line 305
def set_tag(key, value)
  if ![Symbol, String].include?(key.class)
    key = key.to_s
  end

  # If <value> is not a Symbol, String, Array, Hash or Numeric - convert to string
  if ![Symbol, String, Array, TrueClass, FalseClass, Hash].include?(value.class) && !value.is_a?(Numeric)
    value = value.to_s
  end

  if custom?
    @data[:data][:sdk][:custom] ||= {}
    @data[:data][:sdk][:custom][:tags] ||= {}
    @data[:data][:sdk][:custom][:tags][key] = value

    if key.to_sym == :'span.kind'
      case value.to_sym
      when :entry, :server, :consumer
        @data[:data][:sdk][:type] = :entry
        @data[:k] = 1
      when :exit, :client, :producer
        @data[:data][:sdk][:type] = :exit
        @data[:k] = 2
      else
        @data[:data][:sdk][:type] = :intermediate
        @data[:k] = 3
      end
    end
  else
    if value.is_a?(Hash) && @data[:data][key].is_a?(Hash)
      @data[:data][key].merge!(value)
    else
      @data[:data][key] = value
    end
  end
  self
end
set_tags(tags) click to toggle source

Helper method to add multiple tags to this span

@params tags [Hash] @return [Span]

# File lib/instana/tracing/span.rb, line 348
def set_tags(tags)
  return unless tags.is_a?(Hash)
  tags.each do |k,v|
    set_tag(k, v)
  end
  self
end
tags(key = nil) click to toggle source

Retrieve the hash of tags for this span

# File lib/instana/tracing/span.rb, line 386
def tags(key = nil)
  if custom?
    tags = @data[:data][:sdk][:custom][:tags]
  else
    tags = @data[:data]
  end
  key ? tags[key] : tags
end
trace_id() click to toggle source

Retrieve the Trace ID for this span

@return [Integer] the Trace ID

# File lib/instana/tracing/span.rb, line 198
def trace_id
  @data[:t]
end