class NewRelic::Agent::DistributedTracing::TraceContext

Constants

COMMA
EQUALS
INVALID_PARENT_ID
INVALID_TRACE_ID
INVALID_VERSION
MAX_TRACE_STATE_ENTRY_SIZE
MAX_TRACE_STATE_SIZE
PARENT_ID_KEY
SUPPORTABILITY_TRACE_PARENT_PARSE_EXCEPTION
SUPPORTABILITY_TRACE_STATE_INVALID_NR_ENTRY
SUPPORTABILITY_TRACE_STATE_PARSE_EXCEPTION
TP_PARENT_ID
TP_TRACE_FLAGS
TP_TRACE_ID
TP_UNDEFINED_FIELDS
TP_VERSION
TRACE_FLAGS_KEY
TRACE_ID_KEY
TRACE_PARENT_FORMAT_STRING
TRACE_PARENT_REGEX
UNDEFINED_FIELDS_KEY
VERSION
VERSION_KEY

Public Class Methods

create_trace_state_entry(entry_key, payload) click to toggle source
# File lib/new_relic/agent/distributed_tracing/trace_context.rb, line 80
def create_trace_state_entry(entry_key, payload)
  +"#{entry_key}=#{payload}"
end
insert(format: NewRelic::FORMAT_NON_RACK, carrier: nil, parent_id: nil, trace_id: nil, trace_flags: nil, trace_state: nil) click to toggle source
# File lib/new_relic/agent/distributed_tracing/trace_context.rb, line 42
def insert(format: NewRelic::FORMAT_NON_RACK,
  carrier: nil,
  parent_id: nil,
  trace_id: nil,
  trace_flags: nil,
  trace_state: nil)

  trace_parent_header = trace_parent_header_for_format(format)
  carrier[trace_parent_header] = format_trace_parent( \
    trace_id: trace_id,
    parent_id: parent_id,
    trace_flags: trace_flags
  )

  trace_state_header = trace_state_header_for_format(format)
  carrier[trace_state_header] = trace_state if trace_state && !trace_state.empty?
end
parse(format: NewRelic::FORMAT_NON_RACK, carrier: nil, trace_state_entry_key: nil) click to toggle source
# File lib/new_relic/agent/distributed_tracing/trace_context.rb, line 60
def parse(format: NewRelic::FORMAT_NON_RACK,
  carrier: nil,
  trace_state_entry_key: nil)
  trace_parent = extract_traceparent(format, carrier)
  unless trace_parent_valid?(trace_parent)
    NewRelic::Agent.increment_metric(SUPPORTABILITY_TRACE_PARENT_PARSE_EXCEPTION)
    return nil
  end

  begin
    if header_data = extract_tracestate(format, carrier, trace_state_entry_key)
      header_data.trace_parent = trace_parent
      header_data
    end
  rescue Exception
    NewRelic::Agent.increment_metric(SUPPORTABILITY_TRACE_STATE_PARSE_EXCEPTION)
    return nil
  end
end

Private Class Methods

decode_payload(payload) click to toggle source
# File lib/new_relic/agent/distributed_tracing/trace_context.rb, line 167
def decode_payload(payload)
  TraceContextPayload.from_s(payload)
rescue
  if payload
    NewRelic::Agent.increment_metric(SUPPORTABILITY_TRACE_STATE_INVALID_NR_ENTRY)
  end
  return nil
end
extract_traceparent(format, carrier) click to toggle source
# File lib/new_relic/agent/distributed_tracing/trace_context.rb, line 96
def extract_traceparent(format, carrier)
  header_name = trace_parent_header_for_format(format)
  return unless header = carrier[header_name]

  if matchdata = header.match(TRACE_PARENT_REGEX)
    TRACE_PARENT_REGEX.named_captures.inject({}) do |hash, (name, (index))|
      hash[name] = matchdata[index]
      hash
    end
  end
end
extract_tracestate(format, carrier, trace_state_entry_key) click to toggle source
# File lib/new_relic/agent/distributed_tracing/trace_context.rb, line 134
def extract_tracestate(format, carrier, trace_state_entry_key)
  header_name = trace_state_header_for_format(format)
  header = carrier[header_name]
  return HeaderData.create if header.nil? || header.empty?

  payload = nil
  trace_state_size = 0
  trace_state_vendors = +''
  trace_state = header.split(COMMA).map(&:strip)
  trace_state.reject! do |entry|
    if entry == NewRelic::EMPTY_STR
      false
    else
      vendor_id = entry.slice(0, entry.index(EQUALS))
      if vendor_id == trace_state_entry_key
        payload = entry.slice!(trace_state_entry_key.size + 1, entry.size)
        true
      else
        trace_state_size += entry.size
        trace_state_vendors << vendor_id << COMMA
        false
      end
    end
  end

  trace_state_vendors.chomp!(COMMA)

  HeaderData.create(trace_state_payload: payload ? decode_payload(payload) : nil,
    trace_state_entries: trace_state,
    trace_state_size: trace_state_size,
    trace_state_vendors: trace_state_vendors)
end
format_trace_parent(trace_id: nil, parent_id: nil, trace_flags: nil) click to toggle source
# File lib/new_relic/agent/distributed_tracing/trace_context.rb, line 86
def format_trace_parent(trace_id: nil,
  parent_id: nil,
  trace_flags: nil)
  sprintf(TRACE_PARENT_FORMAT_STRING,
    VERSION,
    trace_id,
    parent_id,
    trace_flags)
end
trace_parent_header_for_format(format) click to toggle source
# File lib/new_relic/agent/distributed_tracing/trace_context.rb, line 118
def trace_parent_header_for_format(format)
  if format == NewRelic::FORMAT_RACK
    NewRelic::HTTP_TRACEPARENT_KEY
  else
    NewRelic::TRACEPARENT_KEY
  end
end
trace_parent_valid?(trace_parent) click to toggle source
# File lib/new_relic/agent/distributed_tracing/trace_context.rb, line 108
def trace_parent_valid?(trace_parent)
  return false if trace_parent.nil?
  return false if trace_parent[TRACE_ID_KEY] == INVALID_TRACE_ID
  return false if trace_parent[PARENT_ID_KEY] == INVALID_PARENT_ID
  return false if trace_parent[VERSION_KEY] == INVALID_VERSION
  return false if trace_parent[VERSION_KEY].to_i(16) == VERSION && !trace_parent[UNDEFINED_FIELDS_KEY].nil?

  true
end
trace_state_header_for_format(format) click to toggle source
# File lib/new_relic/agent/distributed_tracing/trace_context.rb, line 126
def trace_state_header_for_format(format)
  if format == NewRelic::FORMAT_RACK
    NewRelic::HTTP_TRACESTATE_KEY
  else
    NewRelic::TRACESTATE_KEY
  end
end