From 5e4931ea90acd17b67a85c2e1ee2f8a9fc2ee4df Mon Sep 17 00:00:00 2001 From: Ariel Valentin Date: Sat, 17 Feb 2024 13:45:39 -0600 Subject: [PATCH] feat: faraday add support for internal spans Multiple client spans are created when both Faraday and the Driver are instrumented. This change allows for users to specify whether or not this instrumentation generates span kinds as client or internal. This is a global configuration that effects all Faraday Connections. --- .../faraday/instrumentation.rb | 1 + .../faraday/middlewares/tracer_middleware.rb | 18 ++++++++----- .../middlewares/tracer_middleware_test.rb | 27 +++++++++++++++++++ 3 files changed, 39 insertions(+), 7 deletions(-) diff --git a/instrumentation/faraday/lib/opentelemetry/instrumentation/faraday/instrumentation.rb b/instrumentation/faraday/lib/opentelemetry/instrumentation/faraday/instrumentation.rb index 0c98ea8f5..abed74af4 100644 --- a/instrumentation/faraday/lib/opentelemetry/instrumentation/faraday/instrumentation.rb +++ b/instrumentation/faraday/lib/opentelemetry/instrumentation/faraday/instrumentation.rb @@ -20,6 +20,7 @@ class Instrumentation < OpenTelemetry::Instrumentation::Base defined?(::Faraday) end + option :span_kind, default: :client, validate: %i[client internal] option :peer_service, default: nil, validate: :string private diff --git a/instrumentation/faraday/lib/opentelemetry/instrumentation/faraday/middlewares/tracer_middleware.rb b/instrumentation/faraday/lib/opentelemetry/instrumentation/faraday/middlewares/tracer_middleware.rb index 01c6da394..9289eacad 100644 --- a/instrumentation/faraday/lib/opentelemetry/instrumentation/faraday/middlewares/tracer_middleware.rb +++ b/instrumentation/faraday/lib/opentelemetry/instrumentation/faraday/middlewares/tracer_middleware.rb @@ -25,11 +25,13 @@ class TracerMiddleware < ::Faraday::Middleware def call(env) http_method = HTTP_METHODS_SYMBOL_TO_STRING[env.method] + config = Faraday::Instrumentation.instance.config + attributes = span_creation_attributes( - http_method: http_method, url: env.url + http_method: http_method, url: env.url, config: config ) tracer.in_span( - "HTTP #{http_method}", attributes: attributes, kind: :client + "HTTP #{http_method}", attributes: attributes, kind: config.fetch(:span_kind) ) do |span| OpenTelemetry.propagation.inject(env.request_headers) @@ -39,21 +41,23 @@ def call(env) private - attr_reader :app - - def span_creation_attributes(http_method:, url:) + def span_creation_attributes(http_method:, url:, config:) instrumentation_attrs = { 'http.method' => http_method, - 'http.url' => OpenTelemetry::Common::Utilities.cleanse_url(url.to_s) + 'http.url' => OpenTelemetry::Common::Utilities.cleanse_url(url.to_s), + 'faraday.adapter.name' => app.class.name } instrumentation_attrs['net.peer.name'] = url.host if url.host - config = Faraday::Instrumentation.instance.config instrumentation_attrs['peer.service'] = config[:peer_service] if config[:peer_service] + instrumentation_attrs.merge!( OpenTelemetry::Common::HTTP::ClientContext.attributes ) end + # Versions prior to 1.0 do not define an accessor for app + attr_reader :app if Gem::Version.new(Faraday::VERSION) < Gem::Version.new('1.0.0') + def tracer Faraday::Instrumentation.instance.tracer end diff --git a/instrumentation/faraday/test/opentelemetry/instrumentation/faraday/middlewares/tracer_middleware_test.rb b/instrumentation/faraday/test/opentelemetry/instrumentation/faraday/middlewares/tracer_middleware_test.rb index 417c0c367..ffed5628f 100644 --- a/instrumentation/faraday/test/opentelemetry/instrumentation/faraday/middlewares/tracer_middleware_test.rb +++ b/instrumentation/faraday/test/opentelemetry/instrumentation/faraday/middlewares/tracer_middleware_test.rb @@ -110,6 +110,33 @@ _(span.attributes['peer.service']).must_equal 'example:faraday' end + it 'defaults to span kind client' do + instrumentation.instance_variable_set(:@installed, false) + instrumentation.install + + client.get('/success') + + _(span.kind).must_equal :client + end + + it 'allows overriding the span kind to internal' do + instrumentation.instance_variable_set(:@installed, false) + instrumentation.install(span_kind: :internal) + + client.get('/success') + + _(span.kind).must_equal :internal + end + + it 'reports the name of the configured adapter' do + instrumentation.instance_variable_set(:@installed, false) + instrumentation.install + + client.get('/success') + + _(span.attributes.fetch('faraday.adapter.name')).must_equal Faraday::Adapter::Test.name + end + it 'prioritizes context attributes over config for peer service name' do instrumentation.instance_variable_set(:@installed, false) instrumentation.install(peer_service: 'example:faraday')