class Instana::InstrumentedRequest

Constants

INSTANA_TRACE_STATE
W3_TRACE_PARENT_FORMAT

Public Instance Methods

continuing_from_trace_parent?() click to toggle source
# File lib/instana/instrumentation/instrumented_request.rb, line 88
def continuing_from_trace_parent?
  incoming_context[:from_w3]
end
correlation_data() click to toggle source
# File lib/instana/instrumentation/instrumented_request.rb, line 80
def correlation_data
  @correlation_data ||= parse_correlation_data
end
external_trace_id() click to toggle source
# File lib/instana/instrumentation/instrumented_request.rb, line 104
def external_trace_id
  incoming_context[:long_instana_id] || incoming_context[:external_trace_id]
end
external_trace_id?() click to toggle source
# File lib/instana/instrumentation/instrumented_request.rb, line 100
def external_trace_id?
  continuing_from_trace_parent? || long_instana_id?
end
extra_header_tags() click to toggle source
# File lib/instana/instrumentation/instrumented_request.rb, line 51
def extra_header_tags
  return nil unless ::Instana.agent.extra_headers
  headers = {}

  ::Instana.agent.extra_headers.each do |custom_header|
    # Headers are available in this format: HTTP_X_CAPTURE_THIS
    rack_header = 'HTTP_' + custom_header.upcase
    rack_header.tr!('-', '_')

    headers[custom_header.to_sym] = @env[rack_header] if @env.has_key?(rack_header)
  end

  headers
end
incoming_context() click to toggle source
# File lib/instana/instrumentation/instrumented_request.rb, line 20
def incoming_context
  context = if !correlation_data.empty?
              {}
            elsif @env['HTTP_X_INSTANA_T']
              context_from_instana_headers
            elsif @env['HTTP_TRACEPARENT']
              context_from_trace_parent
            elsif @env['HTTP_TRACESTATE']
              context_from_trace_state
            else
              {}
            end

  context[:level] = @env['HTTP_X_INSTANA_L'][0] if @env['HTTP_X_INSTANA_L']

  unless ::Instana.config[:w3_trace_correlation]
    trace_state = parse_trace_state

    if context[:from_w3] && trace_state.empty?
      context.delete(:span_id)
      context[:from_w3] = false
    elsif context[:from_w3] && !trace_state.empty?
      context[:trace_id] = trace_state[:t]
      context[:span_id] = trace_state[:p]
      context[:from_w3] = false
    end
  end

  context
end
instana_ancestor() click to toggle source
# File lib/instana/instrumentation/instrumented_request.rb, line 84
def instana_ancestor
  @instana_ancestor ||= parse_trace_state
end
long_instana_id?() click to toggle source
# File lib/instana/instrumentation/instrumented_request.rb, line 96
def long_instana_id?
  ::Instana::Util.header_to_id(@env['HTTP_X_INSTANA_T']).length == 32
end
request_params() click to toggle source
# File lib/instana/instrumentation/instrumented_request.rb, line 66
def request_params
  ::Instana.secrets.remove_from_query(@env['QUERY_STRING'])
end
request_tags() click to toggle source
# File lib/instana/instrumentation/instrumented_request.rb, line 70
def request_tags
  {
    method: request_method,
    url: CGI.unescape(path_info),
    host: host_with_port,
    header: extra_header_tags,
    params: request_params
  }.reject { |_, v| v.nil? }
end
skip_trace?() click to toggle source
# File lib/instana/instrumentation/instrumented_request.rb, line 15
def skip_trace?
  # Honor X-Instana-L
  @env.has_key?('HTTP_X_INSTANA_L') && @env['HTTP_X_INSTANA_L'].start_with?('0')
end
synthetic?() click to toggle source
# File lib/instana/instrumentation/instrumented_request.rb, line 92
def synthetic?
  @env.has_key?('HTTP_X_INSTANA_SYNTHETIC') && @env['HTTP_X_INSTANA_SYNTHETIC'].eql?('1')
end

Private Instance Methods

context_from_instana_headers() click to toggle source
# File lib/instana/instrumentation/instrumented_request.rb, line 110
def context_from_instana_headers
  sanitized_t = ::Instana::Util.header_to_id(@env['HTTP_X_INSTANA_T'])
  sanitized_s = ::Instana::Util.header_to_id(@env['HTTP_X_INSTANA_S'])
  external_trace_id = if @env['HTTP_TRACEPARENT']
                        context_from_trace_parent[:external_trace_id]
                      elsif long_instana_id?
                        sanitized_t
                      end

  {
    span_id: sanitized_s,
    trace_id: long_instana_id? ? sanitized_t[16..-1] : sanitized_t, # rubocop:disable Style/SlicingWithRange, Lint/RedundantCopDisableDirective
    long_instana_id: long_instana_id? ? sanitized_t : nil,
    external_trace_id: external_trace_id,
    external_state: @env['HTTP_TRACESTATE'],
    from_w3: false
  }.reject { |_, v| v.nil? }
end
context_from_trace_parent() click to toggle source
# File lib/instana/instrumentation/instrumented_request.rb, line 129
def context_from_trace_parent
  return {} unless @env.has_key?('HTTP_TRACEPARENT')
  matches = @env['HTTP_TRACEPARENT'].match(W3_TRACE_PARENT_FORMAT)
  return {} unless matches

  trace_id = ::Instana::Util.header_to_id(matches['trace'][16..-1]) # rubocop:disable Style/SlicingWithRange, Lint/RedundantCopDisableDirective
  span_id = ::Instana::Util.header_to_id(matches['parent'])

  {
    external_trace_id: matches['trace'],
    external_state: @env['HTTP_TRACESTATE'],
    trace_id: trace_id,
    span_id: span_id,
    from_w3: true
  }
end
context_from_trace_state() click to toggle source
# File lib/instana/instrumentation/instrumented_request.rb, line 146
def context_from_trace_state
  state = parse_trace_state

  {
    trace_id: state[:t],
    span_id: state[:p],
    from_w3: false
  }.reject { |_, v| v.nil? }
end
parse_correlation_data() click to toggle source
# File lib/instana/instrumentation/instrumented_request.rb, line 171
def parse_correlation_data
  return {} unless @env.has_key?('HTTP_X_INSTANA_L')
  _level, *tokens = @env['HTTP_X_INSTANA_L'].split(/[,=;]/)
  data = tokens
    .map { |t| t.strip }
    .each_slice(2)
    .select { |a| a.length == 2 }.to_h

  {
    type: data['correlationType'],
    id: data['correlationId']
  }.reject { |_, v| v.nil? }
end
parse_trace_state() click to toggle source
# File lib/instana/instrumentation/instrumented_request.rb, line 156
def parse_trace_state
  return {} unless @env.has_key?('HTTP_TRACESTATE')
  token = @env['HTTP_TRACESTATE']
    .split(/,/)
    .map { |t| t.match(INSTANA_TRACE_STATE) }
    .reject { |t| t.nil? }
    .first
  return {} unless token

  {
    t: token['trace'],
    p: token['span']
  }
end