class SplunkTracing::Tracer

Constants

CARRIER_BAGGAGE_PREFIX
CARRIER_SAMPLED
CARRIER_SPAN_ID
CARRIER_TRACER_STATE_PREFIX
CARRIER_TRACE_ID
DEFAULT_MAX_LOG_RECORDS
DEFAULT_MAX_SPAN_RECORDS
MIN_MAX_LOG_RECORDS
MIN_MAX_SPAN_RECORDS

Attributes

access_token[R]
guid[R]

Public Class Methods

new(component_name:, access_token: nil, transport: nil, tags: {}) click to toggle source

Initialize a new tracer. Either an access_token or a transport must be provided. A component_name is always required. @param component_name [String] Component name to use for the tracer @param access_token [String] The project access token when pushing to SplunkTracing @param transport [SplunkTracing::Transport] How the data should be transported @param tags [Hash] Tracer-level tags @return SplunkTracing::Tracer @raise SplunkTracing::ConfigurationError if the group name or access token is not a valid string.

# File lib/splunktracing/tracer.rb, line 27
def initialize(component_name:, access_token: nil, transport: nil, tags: {})
  configure(component_name: component_name, access_token: access_token, transport: transport, tags: tags)
end

Public Instance Methods

active_span() click to toggle source

Returns the span from the active scope, if any.

@return [Span, nil] the active span. This is a shorthand for

`scope_manager.active.span`, and nil will be returned if
Scope#active is nil.
# File lib/splunktracing/tracer.rb, line 123
def active_span
  scope = scope_manager.active
  scope.span if scope
end
disable(discard: true) click to toggle source

Disables the tracer @param discard [Boolean] whether to discard queued data

# File lib/splunktracing/tracer.rb, line 208
def disable(discard: true)
  @enabled = false
  @reporter.clear if discard
  @reporter.flush
end
enable() click to toggle source

Enables the tracer

# File lib/splunktracing/tracer.rb, line 202
def enable
  @enabled = true
end
enabled?() click to toggle source

@return true if the tracer is enabled

# File lib/splunktracing/tracer.rb, line 196
def enabled?
  return @enabled if defined?(@enabled)
  @enabled = true
end
extract(format, carrier) click to toggle source

Extract a SpanContext from a carrier @param format [OpenTracing::FORMAT_TEXT_MAP, OpenTracing::FORMAT_BINARY, OpenTracing::FORMAT_RACK] @param carrier [Carrier] A carrier object of the type dictated by the specified `format` @return [SpanContext] the extracted SpanContext or nil if none could be found

# File lib/splunktracing/tracer.rb, line 180
def extract(format, carrier)
  case format
  when OpenTracing::FORMAT_TEXT_MAP
    extract_from_text_map(carrier)
  when OpenTracing::FORMAT_BINARY
    warn 'Binary join format not yet implemented'
    nil
  when OpenTracing::FORMAT_RACK
    extract_from_rack(carrier)
  else
    warn 'Unknown join format'
    nil
  end
end
finish_span(span) click to toggle source

Internal use only. @private

# File lib/splunktracing/tracer.rb, line 222
def finish_span(span)
  return unless enabled?
  @reporter.add_span(span)
end
flush() click to toggle source

Flush to the Transport

# File lib/splunktracing/tracer.rb, line 215
def flush
  return unless enabled?
  @reporter.flush
end
inject(span_context, format, carrier) click to toggle source

Inject a SpanContext into the given carrier

@param spancontext [SpanContext] @param format [OpenTracing::FORMAT_TEXT_MAP, OpenTracing::FORMAT_BINARY] @param carrier [Carrier] A carrier object of the type dictated by the specified `format`

# File lib/splunktracing/tracer.rb, line 163
def inject(span_context, format, carrier)
  case format
  when OpenTracing::FORMAT_TEXT_MAP
    inject_to_text_map(span_context, carrier)
  when OpenTracing::FORMAT_BINARY
    warn 'Binary inject format not yet implemented'
  when OpenTracing::FORMAT_RACK
    inject_to_rack(span_context, carrier)
  else
    warn 'Unknown inject format'
  end
end
max_log_records() click to toggle source
# File lib/splunktracing/tracer.rb, line 31
def max_log_records
  @max_log_records ||= DEFAULT_MAX_LOG_RECORDS
end
max_log_records=(max) click to toggle source
# File lib/splunktracing/tracer.rb, line 35
def max_log_records=(max)
  @max_log_records = [MIN_MAX_LOG_RECORDS, max].max
end
max_span_records() click to toggle source
# File lib/splunktracing/tracer.rb, line 39
def max_span_records
  @max_span_records ||= DEFAULT_MAX_SPAN_RECORDS
end
max_span_records=(max) click to toggle source
# File lib/splunktracing/tracer.rb, line 43
def max_span_records=(max)
  @max_span_records = [MIN_MAX_SPAN_RECORDS, max].max
  @reporter.max_span_records = @max_span_records
end
report_period_seconds=(seconds) click to toggle source

Set the report flushing period. If set to 0, no flushing will be done, you must manually call flush.

# File lib/splunktracing/tracer.rb, line 50
def report_period_seconds=(seconds)
  @reporter.period = seconds
end
scope_manager() click to toggle source

Creates a scope manager or returns the already-created one.

@return [ScopeManager] the current ScopeManager, which may be a no-op but

may not be nil.
# File lib/splunktracing/tracer.rb, line 60
def scope_manager
  @scope_manager ||= SplunkTracing::ScopeManager.new
end
start_active_span(operation_name, child_of: nil, references: nil, start_time: Time.now, tags: nil, ignore_active_scope: false, finish_on_close: true) { |scope| ... } click to toggle source

Returns a newly started and activated Scope.

If ScopeManager#active is not nil, no explicit references are provided, and `ignore_active_scope` is false, then an inferred References#CHILD_OF reference is created to the ScopeManager#active's SpanContext when start_active_span is invoked.

@param operation_name [String] The operation name for the Span @param child_of [SpanContext, Span] SpanContext that acts as a parent to

     the newly-started Span. If a Span instance is provided, its
     context is automatically substituted. See [Reference] for more
     information.

If specified, the `references` parameter must be omitted.

@param references [Array<Reference>] An array of reference

objects that identify one or more parent SpanContexts.

@param start_time [Time] When the Span started, if not now @param tags [Hash] Tags to assign to the Span at start time @param ignore_active_scope [Boolean] whether to create an implicit

References#CHILD_OF reference to the ScopeManager#active.

@param finish_on_close [Boolean] whether span should automatically be

finished when Scope#close is called

@yield [Scope] If an optional block is passed to start_active it will

yield the newly-started Scope. If `finish_on_close` is true then the
Span will be finished automatically after the block is executed.

@return [Scope] The newly-started and activated Scope

# File lib/splunktracing/tracer.rb, line 90
def start_active_span(operation_name,
                      child_of: nil,
                      references: nil,
                      start_time: Time.now,
                      tags: nil,
                      ignore_active_scope: false,
                      finish_on_close: true)
  if child_of.nil? && references.nil? && !ignore_active_scope
    child_of = active_span
  end

  span = start_span(
    operation_name,
    child_of: child_of,
    references: references,
    start_time: start_time,
    tags: tags,
    ignore_active_scope: ignore_active_scope
  )

  scope_manager.activate(span: span, finish_on_close: finish_on_close).tap do |scope|
    if block_given?
      yield scope
      scope.close
    end
  end
end
start_span(operation_name, child_of: nil, references: nil, start_time: nil, tags: nil, ignore_active_scope: false) click to toggle source

Starts a new span.

@param operation_name [String] The operation name for the Span @param child_of [SpanContext] SpanContext that acts as a parent to

the newly-started Span. If a Span instance is provided, its
.span_context is automatically substituted.

@param references [Array<SpanContext>] An array of SpanContexts that

identify any parent SpanContexts of newly-started Span. If Spans
are provided, their .span_context is automatically substituted.

@param start_time [Time] When the Span started, if not now @param tags [Hash] Tags to assign to the Span at start time @param ignore_active_scope [Boolean] whether to create an implicit

References#CHILD_OF reference to the ScopeManager#active.

@return [Span]

# File lib/splunktracing/tracer.rb, line 142
def start_span(operation_name, child_of: nil, references: nil, start_time: nil, tags: nil, ignore_active_scope: false)
  if child_of.nil? && references.nil? && !ignore_active_scope
    child_of = active_span
  end

  Span.new(
    tracer: self,
    operation_name: operation_name,
    child_of: child_of,
    references: references,
    start_micros: start_time.nil? ? SplunkTracing.micros(Time.now) : SplunkTracing.micros(start_time),
    tags: tags,
    max_log_records: max_log_records,
  )
end

Protected Instance Methods

configure(component_name:, access_token: nil, transport: nil, tags: {}) click to toggle source
# File lib/splunktracing/tracer.rb, line 229
def configure(component_name:, access_token: nil, transport: nil, tags: {})
  raise ConfigurationError, "component_name must be a string" unless component_name.is_a?(String)
  raise ConfigurationError, "component_name cannot be blank"  if component_name.empty?

  if transport.nil? and !access_token.nil?
    transport = Transport::HTTPJSON.new(access_token: access_token)
  end

  raise ConfigurationError, "you must provide an access token or a transport" if transport.nil?
  raise ConfigurationError, "#{transport} is not a SplunkTracing transport class" if !(SplunkTracing::Transport::Base === transport)

  @guid = SplunkTracing.guid

  @reporter = SplunkTracing::Reporter.new(
    max_span_records: max_span_records,
    transport: transport,
    guid: guid,
    component_name: component_name,
    tags: tags
  )
end

Private Instance Methods

extract_from_rack(env) click to toggle source
# File lib/splunktracing/tracer.rb, line 311
def extract_from_rack(env)
  extract_from_text_map(env.reduce({}){|memo, tuple|
    raw_header, value = tuple
    header = raw_header.to_s.gsub(/^HTTP_/, '').tr('_', '-').downcase

    memo[header] = value if header.start_with?(CARRIER_TRACER_STATE_PREFIX, CARRIER_BAGGAGE_PREFIX)
    memo
  })
end
extract_from_text_map(carrier) click to toggle source
# File lib/splunktracing/tracer.rb, line 275
def extract_from_text_map(carrier)
  # If the carrier does not have both the span_id and trace_id key
  # skip the processing and just return a normal span
  if !carrier.has_key?(CARRIER_SPAN_ID) || !carrier.has_key?(CARRIER_TRACE_ID)
    return nil
  end

  baggage = carrier.reduce({}) do |baggage, tuple|
    key, value = tuple
    if key.start_with?(CARRIER_BAGGAGE_PREFIX)
      plain_key = key.to_s[CARRIER_BAGGAGE_PREFIX.length..key.to_s.length]
      baggage[plain_key] = value
    end
    baggage
  end
  SpanContext.new(
    id: carrier[CARRIER_SPAN_ID],
    trace_id: carrier[CARRIER_TRACE_ID],
    baggage: baggage,
  )
end
inject_to_rack(span_context, carrier) click to toggle source
# File lib/splunktracing/tracer.rb, line 297
def inject_to_rack(span_context, carrier)
  carrier[CARRIER_SPAN_ID] = span_context.id
  carrier[CARRIER_TRACE_ID] = span_context.trace_id unless span_context.trace_id.nil?
  carrier[CARRIER_SAMPLED] = 'true'

  span_context.baggage.each do |key, value|
    if key =~ /[^A-Za-z0-9\-_]/
      # TODO: log the error internally
      next
    end
    carrier[CARRIER_BAGGAGE_PREFIX + key] = value
  end
end
inject_to_text_map(span_context, carrier) click to toggle source
# File lib/splunktracing/tracer.rb, line 265
def inject_to_text_map(span_context, carrier)
  carrier[CARRIER_SPAN_ID] = span_context.id
  carrier[CARRIER_TRACE_ID] = span_context.trace_id unless span_context.trace_id.nil?
  carrier[CARRIER_SAMPLED] = 'true'

  span_context.baggage.each do |key, value|
    carrier[CARRIER_BAGGAGE_PREFIX + key] = value
  end
end