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

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

Overview

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'
QUEUE_START_HEADER =
'HTTP_X_QUEUE_START'
QUEUE_DURATION_HEADER =
'HTTP_X_QUEUE_TIME'
MIDDLEWARE_START_HEADER =
'HTTP_X_MIDDLEWARE_START'
ALL_QUEUE_METRIC =
'WebFrontend/QueueTime'
EARLIEST_ACCEPTABLE_TIMESTAMP =

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

946684800

Class Method Summary collapse

Class Method Details

.parse_frontend_timestamp(headers, now = Time.now) ⇒ Object



21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# File 'lib/new_relic/agent/instrumentation/queue_time.rb', line 21

def parse_frontend_timestamp(headers, now=Time.now)
  candidate_headers = [ REQUEST_START_HEADER, QUEUE_START_HEADER,
                        MIDDLEWARE_START_HEADER ]
  earliest = candidate_headers.map do |header|
    if headers[header]
      parse_timestamp(timestamp_string_from_header_value(headers[header]))
    end
  end.compact.min

  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) ⇒ Object



52
53
54
55
56
57
58
59
60
61
62
63
64
# File 'lib/new_relic/agent/instrumentation/queue_time.rb', line 52

def parse_timestamp(string)
  cut_off = Time.at(EARLIEST_ACCEPTABLE_TIMESTAMP)
  [1_000_000, 1_000, 1].map do |divisor|
    begin
      Time.at(string.to_f / divisor)
    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.
      nil
    end
  end.compact.find { |candidate| candidate > cut_off }
end

.record_frontend_metrics(start_time, now = Time.now) ⇒ Object



38
39
40
41
# File 'lib/new_relic/agent/instrumentation/queue_time.rb', line 38

def record_frontend_metrics(start_time, now=Time.now)
  NewRelic::Agent.instance.stats_engine.get_stats(ALL_QUEUE_METRIC) \
    .record_data_point((now - start_time).to_f)
end

.timestamp_string_from_header_value(value) ⇒ Object



43
44
45
46
47
48
49
50
# File 'lib/new_relic/agent/instrumentation/queue_time.rb', line 43

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