Skip to content
Open
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
19 changes: 3 additions & 16 deletions lib/datadog/core/remote/transport/config.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

require_relative '../../../core/transport/request'
require_relative '../../../core/transport/parcel'
require_relative '../../../core/transport/transport'
require_relative 'http/config'

module Datadog
Expand All @@ -23,27 +24,13 @@ class Request < Datadog::Core::Transport::Request
end

# Config transport
class Transport
attr_reader :client, :apis, :default_api, :current_api_id, :logger

def initialize(apis, default_api, logger: Datadog.logger)
@apis = apis
@logger = logger

@client = Remote::Transport::HTTP::Config::Client.new(current_api, logger: logger)
end

##### there is only one transport! it's negotiation!
class Transport < Core::Transport::Transport
def send_config(payload)
json = JSON.dump(payload)
parcel = EncodedParcel.new(json)
request = Request.new(parcel)

@client.send_config_payload(request)
end

def current_api
@apis[HTTP::API::V7]
@client.send_request(:config, request)
end
end
end
Expand Down
9 changes: 0 additions & 9 deletions lib/datadog/core/remote/transport/http/config.rb
Original file line number Diff line number Diff line change
Expand Up @@ -178,15 +178,6 @@ def initialize(key, value)
end
end

# Remote transport HTTP client
class Client < Core::Transport::HTTP::Client
def send_config_payload(request)
send_request(request) do |api, env|
api.send_config(env)
end
end
end

module API
# Extensions for HTTP API Spec
module Spec
Expand Down
9 changes: 0 additions & 9 deletions lib/datadog/core/remote/transport/http/negotiation.rb
Original file line number Diff line number Diff line change
Expand Up @@ -43,15 +43,6 @@ def initialize(http_response, options = {})
attr_reader :version, :endpoints, :config, :span_events
end

# Remote negotiation HTTP client
class Client < Core::Transport::HTTP::Client
def send_info_payload(request)
send_request(request) do |api, env|
api.send_info(env)
end
end
end

module API
# Extensions for HTTP API Spec
module Spec
Expand Down
18 changes: 3 additions & 15 deletions lib/datadog/core/remote/transport/negotiation.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# frozen_string_literal: true

require_relative '../../../core/transport/request'
require_relative '../../../core/transport/transport'
require_relative 'http/negotiation'

# TODO: Resolve conceptual conundrum
Expand Down Expand Up @@ -32,24 +33,11 @@ class Request < Datadog::Core::Transport::Request
end

# Negotiation transport
class Transport
attr_reader :client, :apis, :default_api, :current_api_id, :logger

def initialize(apis, default_api, logger: Datadog.logger)
@apis = apis
@logger = logger

@client = Remote::Transport::HTTP::Negotiation::Client.new(current_api, logger: logger)
end

class Transport < Core::Transport::Transport
def send_info
request = Request.new

@client.send_info_payload(request)
end

def current_api
@apis[HTTP::API::ROOT]
@client.send_request(:info, request)
end
end
end
Expand Down
9 changes: 0 additions & 9 deletions lib/datadog/core/telemetry/transport/http/telemetry.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,6 @@ module Telemetry
module Transport
module HTTP
module Telemetry
class Client < Core::Transport::HTTP::Client
def send_telemetry_payload(request)
send_request(request) do |api, env|
# TODO how to make api have the derived type for steep?
api.send_telemetry(env) # steep:ignore
end
end
end

module API
class Instance < Core::Transport::HTTP::API::Instance
def send_telemetry(env)
Expand Down
13 changes: 3 additions & 10 deletions lib/datadog/core/telemetry/transport/telemetry.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# frozen_string_literal: true

require_relative '../../transport/parcel'
require_relative '../../transport/transport'
require_relative 'http/telemetry'

module Datadog
Expand All @@ -23,23 +24,15 @@ def initialize(request_type, parcel, api_key)
end
end

class Transport
attr_reader :client, :apis, :default_api, :current_api_id, :logger
class Transport < Core::Transport::Transport
attr_accessor :api_key

def initialize(apis, default_api, logger:)
@apis = apis
@logger = logger

@client = Core::Telemetry::Transport::HTTP::Telemetry::Client.new(@apis[default_api], logger: logger)
end

def send_telemetry(request_type:, payload:)
json = JSON.dump(payload)
parcel = EncodedParcel.new(json)
request = Request.new(request_type, parcel, api_key)

@client.send_telemetry_payload(request)
@client.send_request(:telemetry, request)
# Perform no error checking here
end
end
Expand Down
26 changes: 13 additions & 13 deletions lib/datadog/core/transport/http.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,16 @@ module Transport
module HTTP
# Add adapters to registry
Builder::REGISTRY.set(
Transport::HTTP::Adapters::Net,
Core::Transport::HTTP::Adapters::Net,
Core::Configuration::Ext::Agent::HTTP::ADAPTER
)
Builder::REGISTRY.set(
Transport::HTTP::Adapters::Test,
Transport::Ext::Test::ADAPTER
Core::Transport::HTTP::Adapters::Test,
Core::Transport::Ext::Test::ADAPTER
)
Builder::REGISTRY.set(
Transport::HTTP::Adapters::UnixSocket,
Transport::Ext::UnixSocket::ADAPTER
Core::Transport::HTTP::Adapters::UnixSocket,
Core::Transport::Ext::UnixSocket::ADAPTER
)

module_function
Expand All @@ -45,27 +45,27 @@ def build(api_instance_class:, agent_settings:, logger: Datadog.logger, api_vers

def default_headers
{
Datadog::Core::Transport::Ext::HTTP::HEADER_CLIENT_COMPUTED_TOP_LEVEL => '1',
Datadog::Core::Transport::Ext::HTTP::HEADER_META_LANG =>
Core::Transport::Ext::HTTP::HEADER_CLIENT_COMPUTED_TOP_LEVEL => '1',
Core::Transport::Ext::HTTP::HEADER_META_LANG =>
Datadog::Core::Environment::Ext::LANG,
Datadog::Core::Transport::Ext::HTTP::HEADER_META_LANG_VERSION =>
Core::Transport::Ext::HTTP::HEADER_META_LANG_VERSION =>
Datadog::Core::Environment::Ext::LANG_VERSION,
Datadog::Core::Transport::Ext::HTTP::HEADER_META_LANG_INTERPRETER =>
Core::Transport::Ext::HTTP::HEADER_META_LANG_INTERPRETER =>
Datadog::Core::Environment::Ext::LANG_INTERPRETER,
Datadog::Core::Transport::Ext::HTTP::HEADER_META_LANG_INTERPRETER_VENDOR =>
Core::Transport::Ext::HTTP::HEADER_META_LANG_INTERPRETER_VENDOR =>
Core::Environment::Ext::LANG_ENGINE,
Datadog::Core::Transport::Ext::HTTP::HEADER_META_TRACER_VERSION =>
Core::Transport::Ext::HTTP::HEADER_META_TRACER_VERSION =>
Datadog::Core::Environment::Ext::GEM_DATADOG_VERSION
}.tap do |headers|
# Add container ID, if present.
if (container_id = Datadog::Core::Environment::Container.container_id)
headers[Datadog::Core::Transport::Ext::HTTP::HEADER_CONTAINER_ID] = container_id
headers[Core::Transport::Ext::HTTP::HEADER_CONTAINER_ID] = container_id
end
# TODO: inject configuration rather than reading from global here
unless Datadog.configuration.apm.tracing.enabled
# Sending this header to the agent will disable metrics computation (and billing) on the agent side
# by pretending it has already been done on the library side.
headers[Datadog::Core::Transport::Ext::HTTP::HEADER_CLIENT_COMPUTED_STATS] = 'yes'
headers[Core::Transport::Ext::HTTP::HEADER_CLIENT_COMPUTED_STATS] = 'yes'
end
end
end
Expand Down
6 changes: 6 additions & 0 deletions lib/datadog/core/transport/http/builder.rb
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,12 @@ def api(key, spec, options = {})
@apis[key] = spec

# Apply as default API, if specified to do so.
#
# This code also sets the first defined API to be the default API.
# In APIs without fallbacks (currently, everything other than
# tracing's Traces, though DI Input will also have fallbacks soon)
# there is only one declaration of `transport.api`, and that
# API is set as the default API in the transport by this line.
@default_api = key if options.delete(:default) || @default_api.nil?

# Save all other settings for initialization
Expand Down
6 changes: 2 additions & 4 deletions lib/datadog/core/transport/http/client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,12 @@ def initialize(api, logger:)
@logger = logger
end

private

def send_request(request, &block)
def send_request(action, request)
# Build request into env
env = build_env(request)

# Get responses from API
yield(api, env).tap do |response|
api.public_send("send_#{action}", env).tap do |response|
on_response(response)
end
rescue => exception
Expand Down
90 changes: 90 additions & 0 deletions lib/datadog/core/transport/transport.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
# frozen_string_literal: true

require_relative 'http/client'

module Datadog
module Core
module Transport
# Raised when configured with an unknown API version
class UnknownApiVersionError < StandardError
attr_reader :version

def initialize(version)
super

@version = version
end

def message
"No matching transport API for version #{version}!"
end
end

# Raised when the API verson to downgrade to does not map to a
# defined API.
class NoDowngradeAvailableError < StandardError
attr_reader :version

def initialize(version)
super

@version = version
end

def message
"No downgrade from transport API version #{version} is available!"
end
end
Comment on lines +8 to +37
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So I realize this already partially existed before.

Having said that -- these two situations only happen when we have a bug in our code that can't be recovered from, and we don't particularly have a need to access the version or to recover from the individual errors.

So my suggestion is -- let's get rid of these and replace them with raise ArgumentError, "Unknown API version: #{api_id}" (or similar) below. I think that saves us some code and we can always introduce the more specific classes if we ever need to do anything with them.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can do this, I don't think I'm strongly attached to the existing exceptions.


# Base class for transports.
class Transport
attr_reader :client, :apis, :default_api, :current_api_id, :logger
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor: I think some (all?) of these can be made private


class << self
# The HTTP client class to use for requests, derived from
# Core::Transport::HTTP::Client.
#
# Important: this attribute is NOT inherited by derived classes -
# it must be set by every Transport class that wants to have a
# non-default HTTP::Client instance.
attr_accessor :http_client_class
end
Comment on lines +43 to +51
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This... is a kinda weird pattern. May I suggest making it an argument that gets passed to the constructor, or a regular method that needs to be overwritten by subclasses?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My thinking in general was to make the transports more declarative but I can try a version with an instance method.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So I think declarative sometimes works really well...

In our case, I think it's made it really hard to reason and fix things with the current transport design. My thinking is that at this point we should strip out as much as possible of it until we get to a better state. Then, once we're happier with the transport design, we can reintroduce the declarative features as a nicer DSL for underpinnings we're happy with, and it won't affect with the overall design we're trying to fix.


def initialize(apis, default_api, logger:)
@apis = apis
@default_api = default_api
@logger = logger

set_api!(default_api)
end

def current_api
apis[current_api_id]
end

private

def set_api!(api_id)
raise UnknownApiVersionError, api_id unless apis.key?(api_id)

@current_api_id = api_id
client_class = self.class.http_client_class || Core::Transport::HTTP::Client
@client = client_class.new(current_api, logger: logger)
end

def downgrade?(response)
return false unless apis.fallbacks.key?(current_api_id)

response.not_found? || response.unsupported?
end

def downgrade!
downgrade_api_id = apis.fallbacks[current_api_id]
raise NoDowngradeAvailableError, current_api_id if downgrade_api_id.nil?

set_api!(downgrade_api_id)
end
end
end
end
end
1 change: 0 additions & 1 deletion lib/datadog/data_streams/transport/http.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

require_relative '../../core/transport/http'
require_relative 'http/api'
require_relative 'http/client'
require_relative 'http/stats'
require_relative 'stats'

Expand Down
21 changes: 0 additions & 21 deletions lib/datadog/data_streams/transport/http/client.rb

This file was deleted.

1 change: 0 additions & 1 deletion lib/datadog/data_streams/transport/http/stats.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
# frozen_string_literal: true

require_relative '../stats'
require_relative 'client'
require_relative '../../../core/transport/http/response'
require_relative '../../../core/transport/http/api/endpoint'
require_relative '../../../core/transport/http/api/spec'
Expand Down
Loading
Loading