class ElasticAPM::ContextBuilder

@api private

Constants

MAX_BODY_LENGTH
SKIPPED

Attributes

config[R]

Public Class Methods

new(config) click to toggle source
# File lib/elastic_apm/context_builder.rb, line 26
def initialize(config)
  @config = config
end

Public Instance Methods

build(rack_env:, for_type:) click to toggle source
# File lib/elastic_apm/context_builder.rb, line 32
def build(rack_env:, for_type:)
  Context.new.tap do |context|
    apply_to_request(context, rack_env: rack_env, for_type: for_type)
  end
end

Private Instance Methods

apply_to_request(context, rack_env:, for_type:) click to toggle source
# File lib/elastic_apm/context_builder.rb, line 40
def apply_to_request(context, rack_env:, for_type:)
  req = rails_req?(rack_env) ? rack_env : Rack::Request.new(rack_env)

  context.request = Context::Request.new unless context.request
  request = context.request

  request.socket = Context::Request::Socket.new(req)
  request.http_version = build_http_version req
  request.method = req.request_method
  request.url = Context::Request::Url.new(req)

  request.body = should_capture_body?(for_type) ? get_body(req) : SKIPPED

  headers, env = get_headers_and_env(rack_env)
  request.env = env if config.capture_env?
  request.cookies = req.cookies.dup

  if config.capture_headers?
    request.headers = headers
    unless request.cookies.empty?
      request.headers['Cookie'] = SKIPPED if request.headers.has_key?('Cookie')
    end
  end

  context
end
build_http_version(req) click to toggle source
# File lib/elastic_apm/context_builder.rb, line 112
def build_http_version(req)
  return unless (http_version = req.env['HTTP_VERSION'])
  http_version.gsub(%r{HTTP/}, '')
end
camel_key(key) click to toggle source
# File lib/elastic_apm/context_builder.rb, line 108
def camel_key(key)
  key.gsub(/^HTTP_/, '').split('_').map(&:capitalize).join('-')
end
get_body(req) click to toggle source
# File lib/elastic_apm/context_builder.rb, line 77
def get_body(req)
  case req.media_type
  when 'application/x-www-form-urlencoded', 'multipart/form-data'
    req.POST.dup
  else
    body = req.body.read
    req.body.rewind
    body.byteslice(0, MAX_BODY_LENGTH).force_encoding('utf-8').scrub
  end
end
get_headers_and_env(rack_env) click to toggle source
# File lib/elastic_apm/context_builder.rb, line 92
def get_headers_and_env(rack_env)
  # In Rails < 5 ActionDispatch::Request inherits from Hash
  headers =
    rack_env.respond_to?(:headers) ? rack_env.headers : rack_env

  headers.each_with_object([{}, {}]) do |(key, value), (http, env)|
    next unless key == key.upcase

    if key.start_with?('HTTP_')
      http[camel_key(key)] = value
    else
      env[key] = value
    end
  end
end
rails_req?(env) click to toggle source
# File lib/elastic_apm/context_builder.rb, line 88
def rails_req?(env)
  defined?(ActionDispatch::Request) && env.is_a?(ActionDispatch::Request)
end
should_capture_body?(for_type) click to toggle source
# File lib/elastic_apm/context_builder.rb, line 67
def should_capture_body?(for_type)
  option = config.capture_body

  return true if option == 'all'
  return true if option == 'transactions' && for_type == :transaction
  return true if option == 'errors' && for_type == :error

  false
end