Skip to content

Commit

Permalink
Provide better resource names for rack
Browse files Browse the repository at this point in the history
  • Loading branch information
p-lambert committed Dec 20, 2017
1 parent e1be29b commit c68a070
Show file tree
Hide file tree
Showing 5 changed files with 126 additions and 3 deletions.
10 changes: 9 additions & 1 deletion lib/ddtrace/contrib/rack/middlewares.rb
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ def call(env)
# the result for this request; `resource` and `tags` are expected to
# be set in another level but if they're missing, reasonable defaults
# are used.
request_span.resource = "#{env['REQUEST_METHOD']} #{status}".strip unless request_span.resource
request_span.resource ||= resource_name_for(env, status)
if request_span.get_tag(Datadog::Ext::HTTP::METHOD).nil?
request_span.set_tag(Datadog::Ext::HTTP::METHOD, env['REQUEST_METHOD'])
end
Expand All @@ -100,6 +100,14 @@ def call(env)
# memory leaks.
tracer.provider.context = Datadog::Context.new
end

def resource_name_for(env, status)
if Datadog.configuration[:rack][:middleware_names]
return "#{env['RESPONSE_MIDDLEWARE']}##{env['REQUEST_METHOD']}"
end

"#{env['REQUEST_METHOD']} #{status}".strip
end
end
end
end
Expand Down
41 changes: 39 additions & 2 deletions lib/ddtrace/contrib/rack/patcher.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,53 @@ module Rack
module Patcher
include Base
register_as :rack

option :tracer, default: Datadog.tracer
option :distributed_tracing, default: false
option :middleware_names, default: false
option :application
option :service_name, default: 'rack', depends_on: [:tracer] do |value|
get_option(:tracer).set_service_info(value, 'rack', Ext::AppTypes::WEB)
value
end

def self.patch
module_function

def patch
return true if patched?

require_relative 'middlewares'
@patched = true

return unless get_option(:middleware_names)

top = get_option(:application) || rails_app
retain_middleware_name(top)
end

def patched?
return @patched if defined?(@patched)
@patched
end

def rails_app
return unless Datadog.registry[:rails].compatible?
::Rails.application.app
end

def retain_middleware_name(middleware)
return unless middleware && middleware.respond_to?(:call)

middleware.singleton_class.class_eval do
alias_method :__call, :call

def call(env)
env['RESPONSE_MIDDLEWARE'] = self.class.to_s
__call(env)
end
end

following = middleware.instance_variable_get('@app')
retain_middleware_name(following)
end
end
end
Expand Down
2 changes: 2 additions & 0 deletions test/contrib/rack/middleware_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,8 @@ def test_middleware_builder
assert_equal(tracer, Datadog.configuration[:rack][:tracer])
assert_equal('custom-rack', Datadog.configuration[:rack][:service_name])



Datadog.configuration.use(:rack, previous_configuration)
end
end
70 changes: 70 additions & 0 deletions test/contrib/rack/resource_name_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
require_relative 'helpers'

class ResourceNameTest < Minitest::Test
include Rack::Test::Methods

def setup
@previous_configuration = Datadog.configuration[:rack].to_h
@tracer = get_test_tracer
@app = Rack::Builder.new do
use Datadog::Contrib::Rack::TraceMiddleware
use AuthMiddleware
run BottomMiddleware.new
end.to_app

remove_patch!(:rack)
Datadog.configuration.use(
:rack,
middleware_names: true,
tracer: @tracer,
application: @app
)
end

def teardown
Datadog.configuration.use(:rack, @previous_configuration)
end

def test_resource_name_full_chain
get '/', {}, { 'HTTP_AUTH_TOKEN' => '1234' }

spans = @tracer.writer.spans
assert(last_response.ok?)
assert_equal(1, spans.length)
assert_match(/BottomMiddleware#GET/, spans[0].resource)
end

def test_resource_name_short_circuited_request
get '/', env: { 'HTTP_AUTH_TOKEN' => 'Wrong' }

spans = @tracer.writer.spans
refute(last_response.ok?)
assert_equal(1, spans.length)
assert_match(/AuthMiddleware#GET/, spans[0].resource)
end

class AuthMiddleware
def initialize(app)
@app = app
end

def call(env)
if env['HTTP_AUTH_TOKEN'] != '1234'
return [401, {}, []]
end

@app.call(env)
end
end

class BottomMiddleware
def call(_)
[200, {}, []]
end
end

# template method for Rack::Test::Methods
def app
@app
end
end
6 changes: 6 additions & 0 deletions test/helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -237,3 +237,9 @@ def try_wait_until(options = {})
attempts -= 1
end
end

def remove_patch!(integration)
Datadog
.registry[integration]
.instance_variable_set('@patched', false)
end

0 comments on commit c68a070

Please sign in to comment.