class OpenTelemetry::Exporters::Datadog::Propagator

Injects context into carriers using the W3C Trace Context format

Constants

DD_ORIGIN
DEFAULT_EXTRACTORS
DEFAULT_INJECTORS
ORIGIN_KEY
ORIGIN_REGEX
PARENT_ID_KEY
SAMPLING_PRIORITY_KEY
TRACE_ID_KEY

Public Class Methods

auto_configure() click to toggle source
# File lib/opentelemetry/exporters/datadog/propagator.rb, line 102
def self.auto_configure
  default_propagator = new
  updated_injectors = DEFAULT_INJECTORS + [default_propagator]
  updated_extractors = DEFAULT_EXTRACTORS + [default_propagator]
  OpenTelemetry.propagation.http = OpenTelemetry::Context::Propagation::CompositePropagator.new(
    updated_injectors,
    updated_extractors
  )
end
new() click to toggle source

Returns a new Propagator

# File lib/opentelemetry/exporters/datadog/propagator.rb, line 37
def initialize
  # pass
  @truncation_helper = ::Datadog::DistributedTracing::Headers::Headers.new({})
end

Public Instance Methods

extract(carrier, context, &getter) click to toggle source

Extract a remote {Trace::SpanContext} from the supplied carrier. Invalid headers will result in a new, valid, non-remote {Trace::SpanContext}.

@param [Carrier] carrier The carrier to get the header from. @param [Context] context The context to be updated with extracted context @param [optional Callable] getter An optional callable that takes a carrier and a key and

returns the value associated with the key. If omitted the default getter will be used
which expects the carrier to respond to [] and []=.

@yield [Carrier, String] if an optional getter is provided, extract will yield the carrier

and the header key to the getter.

@return [Context] Updated context with span context from the header, or the original

context if parsing fails.
# File lib/opentelemetry/exporters/datadog/propagator.rb, line 76
def extract(carrier, context, &getter)
  getter ||= default_getter
  trace_id = getter.call(carrier, TRACE_ID_KEY) || getter.call(carrier, rack_helper(TRACE_ID_KEY))
  span_id = getter.call(carrier, PARENT_ID_KEY) || getter.call(carrier, rack_helper(PARENT_ID_KEY))
  sampled = getter.call(carrier, SAMPLING_PRIORITY_KEY) || getter.call(carrier, rack_helper(SAMPLING_PRIORITY_KEY))
  origin = getter.call(carrier, ORIGIN_KEY) || getter.call(carrier, rack_helper(ORIGIN_KEY))

  is_sampled = sampled.to_i.positive? ? 1 : 0

  tracestate = origin ? "#{DD_ORIGIN}=#{origin}" : nil

  return context if trace_id.nil? || span_id.nil?

  span_context = Trace::SpanContext.new(trace_id: Array(trace_id.to_i.to_s(16)).pack('H*'),
                                        span_id: Array(span_id.to_i.to_s(16)).pack('H*'),
                                        trace_flags: OpenTelemetry::Trace::TraceFlags.from_byte(is_sampled),
                                        tracestate: tracestate,
                                        remote: true)

  span = Trace::Span.new(span_context: span_context)
  Trace.context_with_span(span, parent_context: context)
rescue StandardError => e
  OpenTelemetry.logger.debug("error extracting datadog propagation, #{e.message}")
  context
end
inject(carrier, context, &setter) click to toggle source

Set the span context on the supplied carrier.

@param [Context] context The active {Context}. @param [optional Callable] setter An optional callable that takes a carrier and a key and

a value and assigns the key-value pair in the carrier. If omitted the default setter
will be used which expects the carrier to respond to [] and []=.

@return [Object] the carrier with context injected

# File lib/opentelemetry/exporters/datadog/propagator.rb, line 49
def inject(carrier, context, &setter)
  return carrier unless (span_context = span_context_from(context))

  sampled = span_context.trace_flags&.sampled? ? 1 : 0

  origin = get_origin_string(span_context.tracestate)
  setter ||= DEFAULT_SETTER
  setter.call(carrier, PARENT_ID_KEY, @truncation_helper.value_to_id(span_context.span_id.unpack1('H*'), 16).to_s)
  setter.call(carrier, TRACE_ID_KEY, @truncation_helper.value_to_id(span_context.trace_id.unpack1('H*'), 16).to_s)
  setter.call(carrier, SAMPLING_PRIORITY_KEY, sampled.to_s)
  setter.call(carrier, ORIGIN_KEY, origin) if origin

  carrier
end

Private Instance Methods

get_origin_string(tracestate) click to toggle source
# File lib/opentelemetry/exporters/datadog/propagator.rb, line 123
def get_origin_string(tracestate)
  return if tracestate.nil? || tracestate.index(DD_ORIGIN).nil?

  # Depending on the edge cases in tracestate values this might be
  # less efficient than mapping string => array => hash.
  origin_value = tracestate.match(ORIGIN_REGEX)
  return if origin_value.nil?

  origin_value[1]
rescue StandardError => e
  OpenTelemetry.logger.debug("error getting origin from trace state, #{e.message}")
end
rack_helper(header) click to toggle source

account for rack re-formatting of headers

# File lib/opentelemetry/exporters/datadog/propagator.rb, line 115
def rack_helper(header)
  "HTTP_#{header.to_s.upcase.gsub(/[-\s]/, '_')}"
end
span_context_from(context) click to toggle source
# File lib/opentelemetry/exporters/datadog/propagator.rb, line 119
def span_context_from(context)
  OpenTelemetry::Trace.current_span(context).context
end