module NewRelic::Agent::Instrumentation::QueueTime

newrelic.com/docs/features/tracking-front-end-time Record queue time metrics based on any of three headers which can be set on the request.

Constants

ALL_QUEUE_METRIC
CANDIDATE_HEADERS
DIVISORS
EARLIEST_ACCEPTABLE_TIME

any timestamps before this are thrown out and the parser will try again with a larger unit (2000/1/1 UTC)

MIDDLEWARE_START_HEADER
QUEUE_START_HEADER
REQUEST_START_HEADER

Public Instance Methods

parse_frontend_timestamp(headers, now=Time.now) click to toggle source
# File lib/new_relic/agent/instrumentation/queue_time.rb, line 31
def parse_frontend_timestamp(headers, now=Time.now)
  earliest = nil

  CANDIDATE_HEADERS.each do |header|
    if headers[header]
      parsed = parse_timestamp(timestamp_string_from_header_value(headers[header]))
      if parsed && (!earliest || parsed < earliest)
        earliest = parsed
      end
    end
  end

  if earliest && earliest > now
    NewRelic::Agent.logger.debug("Negative queue time detected, treating as zero: start=#{earliest.to_f} > now=#{now.to_f}")
    earliest = now
  end

  earliest
end
parse_timestamp(string) click to toggle source
# File lib/new_relic/agent/instrumentation/queue_time.rb, line 60
def parse_timestamp(string)
  DIVISORS.each do |divisor|
    begin
      t = Time.at(string.to_f / divisor)
      return t if t > EARLIEST_ACCEPTABLE_TIME
    rescue RangeError
      # On Ruby versions built with a 32-bit time_t, attempting to
      # instantiate a Time object in the far future raises a RangeError,
      # in which case we know we've chosen the wrong divisor.
    end
  end

  nil
end
timestamp_string_from_header_value(value) click to toggle source
# File lib/new_relic/agent/instrumentation/queue_time.rb, line 51
def timestamp_string_from_header_value(value)
  case value
  when /^\s*([\d+\.]+)\s*$/ then $1
  # following regexp intentionally unanchored to handle
  # (ie ignore) leading server names
  when /t=([\d+\.]+)/       then $1
  end
end