Module: NewRelic::Agent::Instrumentation::QueueTime

Defined in:
lib/new_relic/agent/instrumentation/queue_time.rb

Overview

docs.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.

Constant Summary collapse

REQUEST_START_HEADER =
'HTTP_X_REQUEST_START'.freeze
QUEUE_START_HEADER =
'HTTP_X_QUEUE_START'.freeze
MIDDLEWARE_START_HEADER =
'HTTP_X_MIDDLEWARE_START'.freeze
EARLIEST_ACCEPTABLE_TIME =

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

Time.at(946684800).to_f
CANDIDATE_HEADERS =
[
  REQUEST_START_HEADER,
  QUEUE_START_HEADER,
  MIDDLEWARE_START_HEADER
].freeze
DIVISORS =
[1_000_000, 1_000, 1]

Class Method Summary collapse

Class Method Details

.parse_frontend_timestamp(headers, now = Process.clock_gettime(Process::CLOCK_REALTIME)) ⇒ Object



29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
# File 'lib/new_relic/agent/instrumentation/queue_time.rb', line 29

def parse_frontend_timestamp(headers, now = Process.clock_gettime(Process::CLOCK_REALTIME))
  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}")
    earliest = now
  end

  earliest
end

.parse_timestamp(string) ⇒ Object



58
59
60
61
62
63
64
65
66
67
68
69
70
71
# File 'lib/new_relic/agent/instrumentation/queue_time.rb', line 58

def parse_timestamp(string)
  DIVISORS.each do |divisor|
    begin
      t = (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) ⇒ Object



49
50
51
52
53
54
55
56
# File 'lib/new_relic/agent/instrumentation/queue_time.rb', line 49

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