diff --git a/lib/ddtrace.rb b/lib/ddtrace.rb index 62604d19d8..75f0925921 100644 --- a/lib/ddtrace.rb +++ b/lib/ddtrace.rb @@ -52,7 +52,7 @@ def configure(target = configuration, opts = {}) require 'ddtrace/contrib/delayed_job/integration' require 'ddtrace/contrib/elasticsearch/integration' require 'ddtrace/contrib/excon/integration' -require 'ddtrace/contrib/faraday/patcher' +require 'ddtrace/contrib/faraday/integration' require 'ddtrace/contrib/grape/integration' require 'ddtrace/contrib/graphql/patcher' require 'ddtrace/contrib/http/integration' diff --git a/lib/ddtrace/contrib/faraday/configuration/settings.rb b/lib/ddtrace/contrib/faraday/configuration/settings.rb new file mode 100644 index 0000000000..b7cc1a8758 --- /dev/null +++ b/lib/ddtrace/contrib/faraday/configuration/settings.rb @@ -0,0 +1,22 @@ +require 'ddtrace/contrib/configuration/settings' +require 'ddtrace/ext/http' +require 'ddtrace/contrib/faraday/ext' + +module Datadog + module Contrib + module Faraday + module Configuration + # Custom settings for the Faraday integration + class Settings < Contrib::Configuration::Settings + DEFAULT_ERROR_HANDLER = lambda do |env| + Datadog::Ext::HTTP::ERROR_RANGE.cover?(env[:status]) + end + + option :distributed_tracing, default: false + option :error_handler, default: DEFAULT_ERROR_HANDLER + option :service_name, default: Ext::SERVICE_NAME + end + end + end + end +end diff --git a/lib/ddtrace/contrib/faraday/ext.rb b/lib/ddtrace/contrib/faraday/ext.rb new file mode 100644 index 0000000000..8b90d447ae --- /dev/null +++ b/lib/ddtrace/contrib/faraday/ext.rb @@ -0,0 +1,13 @@ +module Datadog + module Contrib + module Faraday + # Faraday integration constants + module Ext + APP = 'faraday'.freeze + SERVICE_NAME = 'faraday'.freeze + + SPAN_REQUEST = 'faraday.request'.freeze + end + end + end +end diff --git a/lib/ddtrace/contrib/faraday/integration.rb b/lib/ddtrace/contrib/faraday/integration.rb new file mode 100644 index 0000000000..9d6aeb5e28 --- /dev/null +++ b/lib/ddtrace/contrib/faraday/integration.rb @@ -0,0 +1,36 @@ +require 'ddtrace/contrib/integration' +require 'ddtrace/contrib/faraday/configuration/settings' +require 'ddtrace/contrib/faraday/patcher' + +module Datadog + module Contrib + module Faraday + # Description of Faraday integration + class Integration + include Contrib::Integration + + register_as :faraday, auto_patch: true + + def self.version + Gem.loaded_specs['faraday'] && Gem.loaded_specs['faraday'].version + end + + def self.present? + super && defined?(::Faraday) + end + + def self.compatible? + super && version < Gem::Version.new('1.0.0') + end + + def default_configuration + Configuration::Settings.new + end + + def patcher + Patcher + end + end + end + end +end diff --git a/lib/ddtrace/contrib/faraday/middleware.rb b/lib/ddtrace/contrib/faraday/middleware.rb index fa53fbc25e..e3e4558a48 100644 --- a/lib/ddtrace/contrib/faraday/middleware.rb +++ b/lib/ddtrace/contrib/faraday/middleware.rb @@ -2,23 +2,24 @@ require 'ddtrace/ext/http' require 'ddtrace/ext/net' require 'ddtrace/propagation/http_propagator' +require 'ddtrace/contrib/faraday/ext' module Datadog module Contrib module Faraday # Middleware implements a faraday-middleware for ddtrace instrumentation class Middleware < ::Faraday::Middleware - include Ext::DistributedTracing + include Datadog::Ext::DistributedTracing def initialize(app, options = {}) super(app) - @options = Datadog.configuration[:faraday].merge(options) + @options = Datadog.configuration[:faraday].to_h.merge(options) @tracer = Pin.get_from(::Faraday).tracer setup_service! end def call(env) - tracer.trace(NAME) do |span| + tracer.trace(Ext::SPAN_REQUEST) do |span| annotate!(span, env) propagate!(span, env) if options[:distributed_tracing] && tracer.enabled app.call(env).on_complete { |resp| handle_response(span, resp) } @@ -32,11 +33,11 @@ def call(env) def annotate!(span, env) span.resource = env[:method].to_s.upcase span.service = service_name(env) - span.span_type = Ext::HTTP::TYPE - span.set_tag(Ext::HTTP::URL, env[:url].path) - span.set_tag(Ext::HTTP::METHOD, env[:method].to_s.upcase) - span.set_tag(Ext::NET::TARGET_HOST, env[:url].host) - span.set_tag(Ext::NET::TARGET_PORT, env[:url].port) + span.span_type = Datadog::Ext::HTTP::TYPE + span.set_tag(Datadog::Ext::HTTP::URL, env[:url].path) + span.set_tag(Datadog::Ext::HTTP::METHOD, env[:method].to_s.upcase) + span.set_tag(Datadog::Ext::NET::TARGET_HOST, env[:url].host) + span.set_tag(Datadog::Ext::NET::TARGET_PORT, env[:url].port) end def handle_response(span, env) @@ -44,7 +45,7 @@ def handle_response(span, env) span.set_error(["Error #{env[:status]}", env[:body]]) end - span.set_tag(Ext::HTTP::STATUS_CODE, env[:status]) + span.set_tag(Datadog::Ext::HTTP::STATUS_CODE, env[:status]) end def propagate!(span, env) diff --git a/lib/ddtrace/contrib/faraday/patcher.rb b/lib/ddtrace/contrib/faraday/patcher.rb index 0d390cbfae..4cc556618e 100644 --- a/lib/ddtrace/contrib/faraday/patcher.rb +++ b/lib/ddtrace/contrib/faraday/patcher.rb @@ -1,71 +1,56 @@ +require 'ddtrace/contrib/patcher' +require 'ddtrace/ext/app_types' +require 'ddtrace/contrib/faraday/ext' + module Datadog module Contrib module Faraday - COMPATIBLE_UNTIL = Gem::Version.new('1.0.0') - SERVICE = 'faraday'.freeze - NAME = 'faraday.request'.freeze - - # Responsible for hooking the instrumentation into faraday + # Patcher enables patching of 'faraday' module. module Patcher - include Base + include Contrib::Patcher - register_as :faraday, auto_patch: true + module_function - DEFAULT_ERROR_HANDLER = lambda do |env| - Ext::HTTP::ERROR_RANGE.cover?(env[:status]) + def patched? + done?(:faraday) end - option :service_name, default: SERVICE - option :distributed_tracing, default: false - option :error_handler, default: DEFAULT_ERROR_HANDLER - option :tracer, default: Datadog.tracer - - @patched = false - - class << self - def patch - return @patched if patched? || !compatible? - - require 'ddtrace/ext/app_types' - require 'ddtrace/contrib/faraday/middleware' - - add_pin - add_middleware - - @patched = true - rescue => e - Tracer.log.error("Unable to apply Faraday integration: #{e}") - @patched - end - - def patched? - @patched - end + def patch + do_once(:faraday) do + begin + require 'ddtrace/contrib/faraday/middleware' - def register_service(name) - get_option(:tracer).set_service_info(name, 'faraday', Ext::AppTypes::WEB) + add_pin + add_middleware + rescue StandardError => e + Datadog::Tracer.log.error("Unable to apply Faraday integration: #{e}") + end end + end - private - - def compatible? - return unless defined?(::Faraday::VERSION) + def add_pin + Pin.new( + get_option(:service_name), + app: Ext::APP, + app_type: Datadog::Ext::AppTypes::WEB, + tracer: get_option(:tracer) + ).onto(::Faraday) + end - Gem::Version.new(::Faraday::VERSION) < COMPATIBLE_UNTIL - end + def add_middleware + ::Faraday::Middleware.register_middleware(ddtrace: Middleware) + end - def add_pin - Pin.new( - get_option(:service_name), - app: 'faraday', - app_type: Ext::AppTypes::WEB, - tracer: get_option(:tracer) - ).onto(::Faraday) - end + def register_service(name) + get_option(:tracer).set_service_info( + name, + Ext::APP, + Datadog::Ext::AppTypes::WEB + ) + end - def add_middleware - ::Faraday::Middleware.register_middleware(ddtrace: Middleware) - end + def get_option(option) + Datadog.configuration[:faraday].get_option(option) end end end diff --git a/spec/ddtrace/contrib/faraday/middleware_spec.rb b/spec/ddtrace/contrib/faraday/middleware_spec.rb index e87f7761d2..04dc8bc654 100644 --- a/spec/ddtrace/contrib/faraday/middleware_spec.rb +++ b/spec/ddtrace/contrib/faraday/middleware_spec.rb @@ -22,7 +22,7 @@ let(:configuration_options) { { tracer: tracer } } let(:request_span) do - tracer.writer.spans(:keep).find { |span| span.name == Datadog::Contrib::Faraday::NAME } + tracer.writer.spans(:keep).find { |span| span.name == Datadog::Contrib::Faraday::Ext::SPAN_REQUEST } end before(:each) do @@ -51,8 +51,8 @@ it do expect(request_span).to_not be nil - expect(request_span.service).to eq(Datadog::Contrib::Faraday::SERVICE) - expect(request_span.name).to eq(Datadog::Contrib::Faraday::NAME) + expect(request_span.service).to eq(Datadog::Contrib::Faraday::Ext::SERVICE_NAME) + expect(request_span.name).to eq(Datadog::Contrib::Faraday::Ext::SPAN_REQUEST) expect(request_span.resource).to eq('GET') expect(request_span.get_tag(Datadog::Ext::HTTP::METHOD)).to eq('GET') expect(request_span.get_tag(Datadog::Ext::HTTP::STATUS_CODE)).to eq('200') @@ -68,8 +68,8 @@ subject!(:response) { client.post('/failure') } it do - expect(request_span.service).to eq(Datadog::Contrib::Faraday::SERVICE) - expect(request_span.name).to eq(Datadog::Contrib::Faraday::NAME) + expect(request_span.service).to eq(Datadog::Contrib::Faraday::Ext::SERVICE_NAME) + expect(request_span.name).to eq(Datadog::Contrib::Faraday::Ext::SPAN_REQUEST) expect(request_span.resource).to eq('POST') expect(request_span.get_tag(Datadog::Ext::HTTP::METHOD)).to eq('POST') expect(request_span.get_tag(Datadog::Ext::HTTP::URL)).to eq('/failure') @@ -103,7 +103,7 @@ let(:middleware_options) { { split_by_domain: true } } it do - expect(request_span.name).to eq(Datadog::Contrib::Faraday::NAME) + expect(request_span.name).to eq(Datadog::Contrib::Faraday::Ext::SPAN_REQUEST) expect(request_span.service).to eq('example.com') expect(request_span.resource).to eq('GET') end