lib/httpx/adapters/datadog.rb in httpx-0.19.7 vs lib/httpx/adapters/datadog.rb in httpx-0.19.8

- old
+ new

@@ -1,119 +1,163 @@ # frozen_string_literal: true -require "ddtrace/contrib/integration" -require "ddtrace/contrib/rest_client/configuration/settings" -require "ddtrace/contrib/rest_client/patcher" +if defined?(::DDTrace) && ::DDTrace::VERSION::STRING >= "1.0.0" + require "datadog/tracing/contrib/integration" + require "datadog/tracing/contrib/configuration/settings" + require "datadog/tracing/contrib/patcher" -module Datadog + TRACING_MODULE = Datadog::Tracing +else + + require "ddtrace/contrib/integration" + require "ddtrace/contrib/configuration/settings" + require "ddtrace/contrib/patcher" + + TRACING_MODULE = Datadog +end + +module TRACING_MODULE # rubocop:disable Naming/ClassAndModuleCamelCase module Contrib module HTTPX + if defined?(::DDTrace) && ::DDTrace::VERSION::STRING >= "1.0.0" + METADATA_MODULE = TRACING_MODULE::Metadata + + TYPE_OUTBOUND = TRACING_MODULE::Metadata::Ext::HTTP::TYPE_OUTBOUND + + TAG_PEER_SERVICE = TRACING_MODULE::Metadata::Ext::TAG_PEER_SERVICE + + TAG_URL = TRACING_MODULE::Metadata::Ext::HTTP::TAG_URL + TAG_METHOD = TRACING_MODULE::Metadata::Ext::HTTP::TAG_METHOD + TAG_TARGET_HOST = TRACING_MODULE::Metadata::Ext::NET::TAG_TARGET_HOST + TAG_TARGET_PORT = TRACING_MODULE::Metadata::Ext::NET::TAG_TARGET_PORT + + TAG_STATUS_CODE = TRACING_MODULE::Metadata::Ext::HTTP::TAG_STATUS_CODE + + else + + METADATA_MODULE = Datadog + + TYPE_OUTBOUND = TRACING_MODULE::Ext::HTTP::TYPE_OUTBOUND + TAG_PEER_SERVICE = TRACING_MODULE::Ext::Integration::TAG_PEER_SERVICE + TAG_URL = TRACING_MODULE::Ext::HTTP::URL + TAG_METHOD = TRACING_MODULE::Ext::HTTP::METHOD + TAG_TARGET_HOST = TRACING_MODULE::Ext::NET::TARGET_HOST + TAG_TARGET_PORT = TRACING_MODULE::Ext::NET::TARGET_PORT + TAG_STATUS_CODE = Datadog::Ext::HTTP::STATUS_CODE + PROPAGATOR = TRACING_MODULE::HTTPPropagator + + end + # HTTPX Datadog Plugin # # Enables tracing for httpx requests. A span will be created for each individual requests, # and it'll trace since the moment it is fed to the connection, until the moment the response is # fed back to the session. # module Plugin class RequestTracer + include Contrib::HttpAnnotationHelper + SPAN_REQUEST = "httpx.request" def initialize(request) @request = request end def call - return if skip_tracing? + return unless tracing_enabled? @request.on(:response, &method(:finish)) verb = @request.verb.to_s.upcase uri = @request.uri - @span = datadog_pin.tracer.trace(SPAN_REQUEST) - service_name = datadog_config[:split_by_domain] ? uri.host : datadog_pin.service_name + @span = build_span - begin - @span.service = service_name - @span.span_type = Datadog::Ext::HTTP::TYPE_OUTBOUND - @span.resource = verb + @span.resource = verb - Datadog::HTTPPropagator.inject!(@span.context, @request.headers) if datadog_pin.tracer.enabled && !skip_distributed_tracing? + # Add additional request specific tags to the span. - # Add additional request specific tags to the span. + @span.set_tag(TAG_URL, @request.path) + @span.set_tag(TAG_METHOD, verb) - @span.set_tag(Datadog::Ext::HTTP::URL, @request.path) - @span.set_tag(Datadog::Ext::HTTP::METHOD, verb) + @span.set_tag(TAG_TARGET_HOST, uri.host) + @span.set_tag(TAG_TARGET_PORT, uri.port.to_s) - @span.set_tag(Datadog::Ext::NET::TARGET_HOST, uri.host) - @span.set_tag(Datadog::Ext::NET::TARGET_PORT, uri.port.to_s) + # Tag as an external peer service + @span.set_tag(TAG_PEER_SERVICE, @span.service) - # Tag as an external peer service - @span.set_tag(Datadog::Ext::Integration::TAG_PEER_SERVICE, @span.service) + propagate_headers if @configuration[:distributed_tracing] - # Set analytics sample rate - if Contrib::Analytics.enabled?(datadog_config[:analytics_enabled]) - Contrib::Analytics.set_sample_rate(@span, datadog_config[:analytics_sample_rate]) - end - rescue StandardError => e - Datadog.logger.error("error preparing span for http request: #{e}") + # Set analytics sample rate + if Contrib::Analytics.enabled?(@configuration[:analytics_enabled]) + Contrib::Analytics.set_sample_rate(@span, @configuration[:analytics_sample_rate]) end rescue StandardError => e - Datadog.logger.debug("Failed to start span: #{e}") + Datadog.logger.error("error preparing span for http request: #{e}") + Datadog.logger.error(e.backtrace) end def finish(response) return unless @span if response.is_a?(::HTTPX::ErrorResponse) @span.set_error(response.error) else - @span.set_tag(Datadog::Ext::HTTP::STATUS_CODE, response.status.to_s) + @span.set_tag(TAG_STATUS_CODE, response.status.to_s) @span.set_error(::HTTPX::HTTPError.new(response)) if response.status >= 400 && response.status <= 599 end @span.finish end private - def skip_tracing? - return true if @request.headers.key?(Datadog::Ext::Transport::HTTP::HEADER_META_TRACER_VERSION) + if defined?(::DDTrace) && ::DDTrace::VERSION::STRING >= "1.0.0" - return false unless @datadog_pin + def build_span + TRACING_MODULE.trace( + SPAN_REQUEST, + service: service_name(@request.uri.host, configuration, Datadog.configuration_for(self)), + span_type: TYPE_OUTBOUND + ) + end - span = @datadog_pin.tracer.active_span + def propagate_headers + TRACING_MODULE::Propagation::HTTP.inject!(TRACING_MODULE.active_trace, @request.headers) + end - return true if span && (span.name == SPAN_REQUEST) + def configuration + @configuration ||= Datadog.configuration.tracing[:httpx, @request.uri.host] + end - false - end + def tracing_enabled? + TRACING_MODULE.enabled? + end + else + def build_span + service_name = configuration[:split_by_domain] ? @request.uri.host : configuration[:service_name] + configuration[:tracer].trace( + SPAN_REQUEST, + service: service_name, + span_type: TYPE_OUTBOUND + ) + end - def skip_distributed_tracing? - return !datadog_pin.config[:distributed_tracing] if datadog_pin.config && datadog_pin.config.key?(:distributed_tracing) + def propagate_headers + Datadog::HTTPPropagator.inject!(@span.context, @request.headers) + end - !Datadog.configuration[:httpx][:distributed_tracing] - end + def configuration + @configuration ||= Datadog.configuration[:httpx, @request.uri.host] + end - def datadog_pin - @datadog_pin ||= begin - service = datadog_config[:service_name] - tracer = datadog_config[:tracer] - - Datadog::Pin.new( - service, - app: "httpx", - app_type: Datadog::Ext::AppTypes::WEB, - tracer: -> { tracer } - ) + def tracing_enabled? + configuration[:tracer].enabled end end - - def datadog_config - @datadog_config ||= Datadog.configuration[:httpx, @request.uri.host] - end end module ConnectionMethods def send(request) RequestTracer.new(request).call @@ -123,11 +167,15 @@ end module Configuration # Default settings for httpx # - class Settings < Datadog::Contrib::Configuration::Settings + class Settings < TRACING_MODULE::Contrib::Configuration::Settings + DEFAULT_ERROR_HANDLER = lambda do |response| + Datadog::Ext::HTTP::ERROR_RANGE.cover?(response.status) + end + option :service_name, default: "httpx" option :distributed_tracing, default: true option :split_by_domain, default: false option :enabled do |o| @@ -143,18 +191,18 @@ option :analytics_sample_rate do |o| o.default { env_to_float(%w[DD_TRACE_HTTPX_ANALYTICS_SAMPLE_RATE DD_HTTPX_ANALYTICS_SAMPLE_RATE], 1.0) } o.lazy end - option :error_handler, default: Datadog::Tracer::DEFAULT_ON_ERROR + option :error_handler, default: DEFAULT_ERROR_HANDLER end end # Patcher enables patching of 'httpx' with datadog components. # module Patcher - include Datadog::Contrib::Patcher + include TRACING_MODULE::Contrib::Patcher module_function def target_version Integration.version @@ -190,11 +238,17 @@ def self.compatible? super && version >= MINIMUM_VERSION end - def default_configuration - Configuration::Settings.new + if defined?(::DDTrace) && ::DDTrace::VERSION::STRING >= "1.0.0" + def new_configuration + Configuration::Settings.new + end + else + def default_configuration + Configuration::Settings.new + end end def patcher Patcher end