-
Notifications
You must be signed in to change notification settings - Fork 375
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[rack] add request queuing option to the Rack middleware; compatibili…
…ty only for nginx
- Loading branch information
Emanuele Palazzetti
committed
Dec 14, 2017
1 parent
f2aad98
commit 9980106
Showing
4 changed files
with
170 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
module Datadog | ||
module Contrib | ||
module Rack | ||
# QueueTime simply... | ||
module QueueTime | ||
REQUEST_START = 'HTTP_X_REQUEST_START'.freeze | ||
|
||
module_function | ||
|
||
def get_request_start(env, now = Time.now.utc) | ||
header = env[REQUEST_START] | ||
return unless header | ||
|
||
# nginx header is in the format "t=1512379167.574" | ||
# TODO: this should be generic enough to work with any | ||
# frontend web server or load balancer | ||
time_string = header.split('t=')[1] | ||
return if time_string.nil? | ||
|
||
# return the request_start only if it's lesser than | ||
# current time, to avoid significant clock skew | ||
request_start = Time.at(time_string.to_f) | ||
request_start.utc > now ? nil : request_start | ||
rescue | ||
# in case of an Exception we don't create a | ||
# `request.enqueuing` span | ||
nil | ||
end | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
require 'ddtrace/contrib/rack/request_queue' | ||
|
||
class QueueTimeParserTest < Minitest::Test | ||
include Rack::Test::Methods | ||
|
||
def test_nginx_header | ||
# ensure nginx headers are properly parsed | ||
headers = {} | ||
headers['HTTP_X_REQUEST_START'] = 't=1512379167.574' | ||
request_start = Datadog::Contrib::Rack::QueueTime.get_request_start(headers) | ||
assert_equal(1512379167.574, request_start.to_f) | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
require 'contrib/rack/helpers' | ||
|
||
class RequestQueuingTest < RackBaseTest | ||
def setup | ||
super | ||
# enable request_queueing | ||
Datadog.configuration[:rack][:request_queuing] = true | ||
end | ||
|
||
def test_request_queuing_header | ||
# ensure a queuing Span is created if the header is available | ||
request_start = (Time.now.utc - 5).to_i | ||
header 'x-request-start', "t=#{request_start}" | ||
get '/success/' | ||
assert last_response.ok? | ||
|
||
spans = @tracer.writer.spans() | ||
assert_equal(2, spans.length) | ||
|
||
rack_span = spans[0] | ||
frontend_span = spans[1] | ||
assert_equal('rack.request', rack_span.name) | ||
assert_equal('request.enqueuing', frontend_span.name) | ||
|
||
assert_equal('http', rack_span.span_type) | ||
assert_equal('rack', rack_span.service) | ||
assert_equal('GET 200', rack_span.resource) | ||
assert_equal('GET', rack_span.get_tag('http.method')) | ||
assert_equal('200', rack_span.get_tag('http.status_code')) | ||
assert_equal('/success/', rack_span.get_tag('http.url')) | ||
assert_equal(0, rack_span.status) | ||
assert_equal(frontend_span.span_id, rack_span.parent_id) | ||
|
||
assert_equal('web-server', frontend_span.service) | ||
assert_equal(request_start, frontend_span.start_time.to_i) | ||
end | ||
|
||
def test_request_queuing_service_name | ||
# ensure a queuing Span is created if the header is available | ||
Datadog.configuration[:rack][:web_service_name] = 'nginx' | ||
request_start = (Time.now.utc - 5).to_i | ||
header 'x-request-start', "t=#{request_start}" | ||
get '/success/' | ||
assert last_response.ok? | ||
|
||
spans = @tracer.writer.spans() | ||
assert_equal(2, spans.length) | ||
|
||
rack_span = spans[0] | ||
frontend_span = spans[1] | ||
assert_equal('rack.request', rack_span.name) | ||
assert_equal('request.enqueuing', frontend_span.name) | ||
|
||
assert_equal('nginx', frontend_span.service) | ||
end | ||
|
||
def test_clock_skew | ||
# ensure a queuing Span is NOT created if there is a clock skew | ||
# where the starting time is greater than current host Time.now | ||
request_start = (Time.now.utc + 5).to_i | ||
header 'x-request-start', "t=#{request_start}" | ||
get '/success/' | ||
assert last_response.ok? | ||
|
||
spans = @tracer.writer.spans() | ||
assert_equal(1, spans.length) | ||
|
||
rack_span = spans[0] | ||
assert_equal('rack.request', rack_span.name) | ||
end | ||
|
||
def test_wrong_header | ||
# ensure a queuing Span is NOT created if the header is wrong | ||
header 'x-request-start', 'something_weird' | ||
get '/success/' | ||
assert last_response.ok? | ||
|
||
spans = @tracer.writer.spans() | ||
assert_equal(1, spans.length) | ||
|
||
rack_span = spans[0] | ||
assert_equal('rack.request', rack_span.name) | ||
end | ||
|
||
def test_enabled_missing_header | ||
# ensure a queuing Span is NOT created if the header is missing | ||
get '/success/' | ||
assert last_response.ok? | ||
|
||
spans = @tracer.writer.spans() | ||
assert_equal(1, spans.length) | ||
|
||
rack_span = spans[0] | ||
assert_equal('rack.request', rack_span.name) | ||
end | ||
end |