Skip to content

Commit

Permalink
Merge pull request #371 from DataDog/feature/quantize_http_query_strings
Browse files Browse the repository at this point in the history
Add URL query string quantization to Rack
  • Loading branch information
delner committed Mar 27, 2018
2 parents 8ba47ae + dacba60 commit f9cd181
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 1 deletion.
35 changes: 35 additions & 0 deletions docs/GettingStarted.md
Original file line number Diff line number Diff line change
Expand Up @@ -142,9 +142,44 @@ Where `options` is an optional `Hash` that accepts the following parameters:
| ``service_name`` | Service name used when tracing application requests | rack |
| ``distributed_tracing`` | Enables [distributed tracing](#Distributed_Tracing) so that this service trace is connected with a trace of another service if tracing headers are received | `false` |
| ``middleware_names`` | Enable this if you want to use the middleware classes as the resource names for `rack` spans. Must provide the ``application`` option with it. | ``false`` |
| ``quantize`` | Hash containing options for quantization. May include `:query` or `:fragment`. | {} |
| ``quantize.query`` | Hash containing options for query portion of URL quantization. May include `:show` or `:exclude`. See options below. Option must be nested inside the `quantize` option. | {} |
| ``quantize.query.show`` | Defines which values should always be shown. Shows no values by default. May be an Array of strings, or `:all` to show all values. Option must be nested inside the `query` option. | ``nil`` |
| ``quantize.query.exclude`` | Defines which values should be removed entirely. Excludes nothing by default. May be an Array of strings, or `:all` to remove the query string entirely. Option must be nested inside the `query` option. | ``nil`` |
| ``quantize.fragment`` | Defines behavior for URL fragments. Removes fragments by default. May be `:show` to show URL fragments. Option must be nested inside the `quantize` option. | ``nil`` |
| ``application`` | Your Rack application. Necessary for enabling middleware resource names. | ``nil`` |
| ``tracer`` | A ``Datadog::Tracer`` instance used to instrument the application. Usually you don't need to set that. | ``Datadog.tracer`` |

Configuring URL quantization behavior:

```
Datadog.configure do |c|
# Default behavior: all values are quantized, fragment is removed.
# http://example.com/path?category_id=1&sort_by=asc#featured --> http://example.com/path?category_id&sort_by
# http://example.com/path?categories[]=1&categories[]=2 --> http://example.com/path?categories[]
# Show values for any query string parameter matching 'category_id' exactly
# http://example.com/path?category_id=1&sort_by=asc#featured --> http://example.com/path?category_id=1&sort_by
c.use :rack, quantize: { query: { show: ['category_id'] } }
# Show all values for all query string parameters
# http://example.com/path?category_id=1&sort_by=asc#featured --> http://example.com/path?category_id=1&sort_by=asc
c.use :rack, quantize: { query: { show: :all } }
# Totally exclude any query string parameter matching 'sort_by' exactly
# http://example.com/path?category_id=1&sort_by=asc#featured --> http://example.com/path?category_id
c.use :rack, quantize: { query: { exclude: ['sort_by'] } }
# Remove the query string entirely
# http://example.com/path?category_id=1&sort_by=asc#featured --> http://example.com/path
c.use :rack, quantize: { query: { exclude: :all } }
# Show URL fragments
# http://example.com/path?category_id=1&sort_by=asc#featured --> http://example.com/path?category_id&sort_by#featured
c.use :rack, quantize: { fragment: :show }
end
```

## Other libraries

### GraphQL
Expand Down
3 changes: 2 additions & 1 deletion lib/ddtrace/contrib/rack/middlewares.rb
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,8 @@ def set_request_tags!(request_span, env, status, headers, response, original_env
request_span.set_tag(Datadog::Ext::HTTP::METHOD, env['REQUEST_METHOD'])
end
if request_span.get_tag(Datadog::Ext::HTTP::URL).nil?
request_span.set_tag(Datadog::Ext::HTTP::URL, url)
options = Datadog.configuration[:rack][:quantize]
request_span.set_tag(Datadog::Ext::HTTP::URL, Datadog::Quantization::HTTP.url(url, options))
end
if request_span.get_tag(Datadog::Ext::HTTP::BASE_URL).nil?
request_obj = ::Rack::Request.new(env)
Expand Down
1 change: 1 addition & 0 deletions lib/ddtrace/contrib/rack/patcher.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ module Patcher
option :tracer, default: Datadog.tracer
option :distributed_tracing, default: false
option :middleware_names, default: false
option :quantize, default: {}
option :application
option :service_name, default: 'rack', depends_on: [:tracer] do |value|
get_option(:tracer).set_service_info(value, 'rack', Ext::AppTypes::WEB)
Expand Down
29 changes: 29 additions & 0 deletions test/contrib/rack/middleware_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,35 @@ def test_request_middleware_get_with_request_uri
assert_equal('200', span.get_tag('http.status_code'))
# Since REQUEST_URI is set (usually provided by WEBrick/Puma)
# it uses REQUEST_URI, which has query string parameters.
# However, that query string will be quantized.
assert_equal('/success?foo', span.get_tag('http.url'))
assert_equal('http://example.org', span.get_tag('http.base_url'))
assert_equal(0, span.status)
assert_nil(span.parent)
end

def test_request_middleware_get_with_request_uri_and_quantize_option
Datadog.configure do |c|
c.use :rack, quantize: { query: { show: ['foo'] } }
end

# ensure the Rack request is properly traced
get '/success?foo=bar', {}, 'REQUEST_URI' => '/success?foo=bar'
assert last_response.ok?

spans = @tracer.writer.spans
assert_equal(1, spans.length)

span = spans[0]
assert_equal('rack.request', span.name)
assert_equal('http', span.span_type)
assert_equal('rack', span.service)
assert_equal('GET 200', span.resource)
assert_equal('GET', span.get_tag('http.method'))
assert_equal('200', span.get_tag('http.status_code'))
# Since REQUEST_URI is set (usually provided by WEBrick/Puma)
# it uses REQUEST_URI, which has query string parameters.
# However, that query string will be quantized.
assert_equal('/success?foo=bar', span.get_tag('http.url'))
assert_equal('http://example.org', span.get_tag('http.base_url'))
assert_equal(0, span.status)
Expand Down

0 comments on commit f9cd181

Please sign in to comment.