Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add URL query string quantization to Rack #371

Merged
merged 1 commit into from
Mar 27, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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|
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice write up!

# 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