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 HTTP multiplexing #953

Merged
merged 5 commits into from
Mar 27, 2020
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
17 changes: 15 additions & 2 deletions Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,21 @@ namespace :spec do
end

RSpec::Core::RakeTask.new(:contrib) do |t, args|
# rubocop:disable Metrics/LineLength
t.pattern = 'spec/**/contrib/{analytics,configurable,extensions,integration,patchable,patcher,registerable,registry,configuration/*}_spec.rb'
contrib_paths = [
'analytics',
'configurable',
'configuration/*',
'configuration/resolvers/*',
'extensions',
'integration',
'patchable',
'patcher',
'registerable',
'registry',
'registry/*'
].join(',')

t.pattern = "spec/**/contrib/{#{contrib_paths}}_spec.rb"
t.rspec_opts = args.to_a.join(' ')
end

Expand Down
26 changes: 26 additions & 0 deletions docs/GettingStarted.md
Original file line number Diff line number Diff line change
Expand Up @@ -674,6 +674,12 @@ require 'ddtrace'

Datadog.configure do |c|
c.use :ethon, options

# optionally, specify a different service name for hostnames matching a regex
c.use :ethon, describes: /user-[^.]+\.example\.com/ do |ethon|
ethon.service_name = 'user.example.com'
ethon.split_by_domain = false # Only necessary if split_by_domain is true by default
end
end
```

Expand All @@ -684,6 +690,7 @@ Where `options` is an optional `Hash` that accepts the following parameters:
| `analytics_enabled` | Enable analytics for spans produced by this integration. `true` for on, `nil` to defer to global setting, `false` for off. | `false` |
| `distributed_tracing` | Enables [distributed tracing](#distributed-tracing) | `true` |
| `service_name` | Service name for `ethon` instrumentation. | `'ethon'` |
| `split_by_domain` | Uses the request domain as the service name when set to `true`. | `false` |
| `tracer` | `Datadog::Tracer` used to perform instrumentation. Usually you don't need to set this. | `Datadog.tracer` |

### Excon
Expand All @@ -697,6 +704,12 @@ require 'ddtrace'
# Configure default Excon tracing behavior
Datadog.configure do |c|
c.use :excon, options

# optionally, specify a different service name for hostnames matching a regex
c.use :excon, describes: /user-[^.]+\.example\.com/ do |excon|
excon.service_name = 'user.example.com'
excon.split_by_domain = false # Only necessary if split_by_domain is true by default
end
end

connection = Excon.new('https://example.com')
Expand Down Expand Up @@ -750,6 +763,12 @@ require 'ddtrace'
# Configure default Faraday tracing behavior
Datadog.configure do |c|
c.use :faraday, options

# optionally, specify a different service name for hostnames matching a regex
c.use :faraday, describes: /user-[^.]+\.example\.com/ do |faraday|
faraday.service_name = 'user.example.com'
faraday.split_by_domain = false # Only necessary if split_by_domain is true by default
end
end

# Configure Faraday tracing behavior for single connection
Expand Down Expand Up @@ -991,6 +1010,12 @@ require 'ddtrace'

Datadog.configure do |c|
c.use :http, options

# optionally, specify a different service name for hostnames matching a regex
c.use :http, describes: /user-[^.]+\.example\.com/ do |http|
http.service_name = 'user.example.com'
http.split_by_domain = false # Only necessary if split_by_domain is true by default
end
end

Net::HTTP.start('127.0.0.1', 8080) do |http|
Expand All @@ -1008,6 +1033,7 @@ Where `options` is an optional `Hash` that accepts the following parameters:
| `analytics_enabled` | Enable analytics for spans produced by this integration. `true` for on, `nil` to defer to global setting, `false` for off. | `false` |
| `distributed_tracing` | Enables [distributed tracing](#distributed-tracing) | `true` |
| `service_name` | Service name used for `http` instrumentation | `'net/http'` |
| `split_by_domain` | Uses the request domain as the service name when set to `true`. | `false` |
| `tracer` | `Datadog::Tracer` used to perform instrumentation. Usually you don't need to set this. | `Datadog.tracer` |

If you wish to configure each connection object individually, you may use the `Datadog.configure` as it follows:
Expand Down
39 changes: 39 additions & 0 deletions lib/ddtrace/contrib/configuration/resolvers/pattern_resolver.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
require 'ddtrace/contrib/configuration/resolver'

module Datadog
module Contrib
module Configuration
# Resolves a value to a configuration key
module Resolvers
# Matches strings against Regexps.
class PatternResolver < Datadog::Contrib::Configuration::Resolver
def resolve(name)
# Try to find a matching pattern
matching_pattern = patterns.find do |pattern|
# Rubocop incorrectly thinks assignment is done here...
# rubocop:disable Style/ConditionalAssignment
if pattern.is_a?(Proc)
pattern === name
else
pattern === name.to_s # Co-erce to string
end
end

# Return match or default
matching_pattern || :default
end

def add(pattern)
patterns << (pattern.is_a?(Regexp) || pattern.is_a?(Proc) ? pattern : pattern.to_s)
end

private

def patterns
@patterns ||= Set.new
end
end
end
end
end
end
1 change: 1 addition & 0 deletions lib/ddtrace/contrib/ethon/configuration/settings.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ class Settings < Contrib::Configuration::Settings

option :distributed_tracing, default: true
option :service_name, default: Ext::SERVICE_NAME
option :split_by_domain, default: false
end
end
end
Expand Down
35 changes: 22 additions & 13 deletions lib/ddtrace/contrib/ethon/easy_patch.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
require 'ddtrace/ext/distributed'
require 'ddtrace/propagation/http_propagator'
require 'ddtrace/contrib/ethon/ext'
require 'ddtrace/contrib/http_annotation_helper'

module Datadog
module Contrib
Expand All @@ -14,7 +15,10 @@ def self.included(base)

# InstanceMethods - implementing instrumentation
module InstanceMethods
include Datadog::Contrib::HttpAnnotationHelper

def http_request(url, action_name, options = {})
load_datadog_configuration_for(url)
return super unless tracer_enabled?

# It's tricky to get HTTP method from libcurl
Expand All @@ -23,14 +27,13 @@ def http_request(url, action_name, options = {})
end

def headers=(headers)
return super unless tracer_enabled?

# Store headers to call this method again when span is ready
@datadog_original_headers = headers
super
end

def perform
load_datadog_configuration_for(url)
return super unless tracer_enabled?
datadog_before_request
super
Expand Down Expand Up @@ -61,17 +64,17 @@ def complete
def reset
super
ensure
if tracer_enabled?
@datadog_span = nil
@datadog_method = nil
@datadog_original_headers = nil
end
@datadog_span = nil
@datadog_method = nil
@datadog_original_headers = nil
@datadog_configuration = nil
end

def datadog_before_request(parent_span: nil)
load_datadog_configuration_for(url)
@datadog_span = datadog_configuration[:tracer].trace(
Ext::SPAN_REQUEST,
service: datadog_configuration[:service_name],
service: uri ? service_name(uri.host, datadog_configuration) : datadog_configuration[:service_name],
span_type: Datadog::Ext::HTTP::TYPE_OUTBOUND
)
@datadog_span.parent = parent_span unless parent_span.nil?
Expand All @@ -91,9 +94,10 @@ def datadog_span_started?

private

attr_reader :datadog_configuration

def datadog_tag_request
span = @datadog_span
uri = URI.parse(url)
method = 'N/A'
if instance_variable_defined?(:@datadog_method) && !@datadog_method.nil?
method = @datadog_method.to_s
Expand All @@ -103,12 +107,11 @@ def datadog_tag_request
# Set analytics sample rate
Contrib::Analytics.set_sample_rate(span, analytics_sample_rate) if analytics_enabled?

return unless uri
span.set_tag(Datadog::Ext::HTTP::URL, uri.path)
span.set_tag(Datadog::Ext::HTTP::METHOD, method)
span.set_tag(Datadog::Ext::NET::TARGET_HOST, uri.host)
span.set_tag(Datadog::Ext::NET::TARGET_PORT, uri.port)
rescue URI::InvalidURIError
return
end

def set_span_error_message(message)
Expand All @@ -117,8 +120,14 @@ def set_span_error_message(message)
@datadog_span.set_tag(Datadog::Ext::Errors::MSG, message)
end

def datadog_configuration
Datadog.configuration[:ethon]
def uri
URI.parse(url)
# rubocop:disable Lint/HandleExceptions
rescue URI::InvalidURIError
end

def load_datadog_configuration_for(host = :default)
@datadog_configuration = Datadog.configuration[:ethon, host]
end

def tracer_enabled?
Expand Down
5 changes: 5 additions & 0 deletions lib/ddtrace/contrib/ethon/integration.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
require 'ddtrace/contrib/integration'
require 'ddtrace/contrib/ethon/configuration/settings'
require 'ddtrace/contrib/configuration/resolvers/pattern_resolver'
require 'ddtrace/contrib/ethon/patcher'

module Datadog
Expand Down Expand Up @@ -32,6 +33,10 @@ def default_configuration
def patcher
Patcher
end

def resolver
@resolver ||= Contrib::Configuration::Resolvers::PatternResolver.new
end
end
end
end
Expand Down
5 changes: 5 additions & 0 deletions lib/ddtrace/contrib/excon/integration.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
require 'ddtrace/contrib/integration'
require 'ddtrace/contrib/excon/configuration/settings'
require 'ddtrace/contrib/configuration/resolvers/pattern_resolver'
require 'ddtrace/contrib/excon/patcher'

module Datadog
Expand Down Expand Up @@ -32,6 +33,10 @@ def default_configuration
def patcher
Patcher
end

def resolver
@resolver ||= Contrib::Configuration::Resolvers::PatternResolver.new
end
end
end
end
Expand Down
21 changes: 12 additions & 9 deletions lib/ddtrace/contrib/excon/middleware.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,24 +5,28 @@
require 'ddtrace/propagation/http_propagator'
require 'ddtrace/contrib/analytics'
require 'ddtrace/contrib/excon/ext'
require 'ddtrace/contrib/http_annotation_helper'

module Datadog
module Contrib
module Excon
# Middleware implements an excon-middleware for ddtrace instrumentation
class Middleware < ::Excon::Middleware::Base
include Datadog::Contrib::HttpAnnotationHelper

DEFAULT_ERROR_HANDLER = lambda do |response|
Datadog::Ext::HTTP::ERROR_RANGE.cover?(response[:status])
end

def initialize(stack, options = {})
super(stack)
@options = Datadog.configuration[:excon].options_hash.merge(options)
@default_options = datadog_configuration.options_hash.merge(options)
end

def request_call(datum)
begin
unless datum.key?(:datadog_span)
@options = build_request_options!(datum)
tracer.trace(Ext::SPAN_REQUEST).tap do |span|
datum[:datadog_span] = span
annotate!(span, datum)
Expand Down Expand Up @@ -99,13 +103,9 @@ def error_handler
@options[:error_handler] || DEFAULT_ERROR_HANDLER
end

def split_by_domain?
@options[:split_by_domain] == true
end

def annotate!(span, datum)
span.resource = datum[:method].to_s.upcase
span.service = service_name(datum)
span.service = service_name(datum[:host], @options)
span.span_type = Datadog::Ext::HTTP::TYPE_OUTBOUND

# Set analytics sample rate
Expand Down Expand Up @@ -144,9 +144,12 @@ def propagate!(span, datum)
Datadog::HTTPPropagator.inject!(span.context, datum[:headers])
end

def service_name(datum)
# TODO: Change this to implement more sensible multiplexing
split_by_domain? ? datum[:host] : @options[:service_name]
def build_request_options!(datum)
datadog_configuration(datum[:host]).options_hash.merge(@default_options)
end

def datadog_configuration(host = :default)
Datadog.configuration[:excon, host]
end
end
end
Expand Down
5 changes: 5 additions & 0 deletions lib/ddtrace/contrib/faraday/integration.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
require 'ddtrace/contrib/integration'
require 'ddtrace/contrib/configuration/resolvers/pattern_resolver'
require 'ddtrace/contrib/faraday/configuration/settings'
require 'ddtrace/contrib/faraday/patcher'

Expand Down Expand Up @@ -32,6 +33,10 @@ def default_configuration
def patcher
Patcher
end

def resolver
@resolver ||= Contrib::Configuration::Resolvers::PatternResolver.new
end
end
end
end
Expand Down
Loading