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

Transport wip #4480

Draft
wants to merge 28 commits into
base: master
Choose a base branch
from
Draft
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
5 changes: 1 addition & 4 deletions lib/datadog/core/remote/component.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,8 @@ class Component
def initialize(settings, capabilities, agent_settings, logger:)
@logger = logger

transport_options = {}
transport_options[:agent_settings] = agent_settings if agent_settings

negotiation = Negotiation.new(settings, agent_settings)
transport_v7 = Datadog::Core::Remote::Transport::HTTP.v7(**transport_options) # steep:ignore
transport_v7 = Datadog::Core::Remote::Transport::HTTP.v7(agent_settings: agent_settings)

@barrier = Barrier.new(settings.remote.boot_timeout_seconds)

Expand Down
5 changes: 1 addition & 4 deletions lib/datadog/core/remote/negotiation.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,7 @@ module Remote
# Endpoint negotiation
class Negotiation
def initialize(_settings, agent_settings, suppress_logging: {})
transport_options = {}
transport_options[:agent_settings] = agent_settings if agent_settings

@transport_root = Datadog::Core::Remote::Transport::HTTP.root(**transport_options) # steep:ignore
@transport_root = Datadog::Core::Remote::Transport::HTTP.root(agent_settings: agent_settings)
@logged = suppress_logging
end

Expand Down
75 changes: 18 additions & 57 deletions lib/datadog/core/remote/transport/http.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,87 +29,48 @@ module Transport
module HTTP
module_function

# Builds a new Transport::HTTP::Client
def new(klass, &block)
Core::Transport::HTTP.build(
api_instance_class: API::Instance, &block
).to_transport(klass)
end

# Builds a new Transport::HTTP::Client with default settings
# Pass a block to override any settings.
def root(
agent_settings:,
**options
api_version: nil,
headers: nil
)
new(Core::Remote::Transport::Negotiation::Transport) do |transport|
transport.adapter(agent_settings)
transport.headers(default_headers)

Core::Transport::HTTP.build(
api_instance_class: API::Instance,
agent_settings: agent_settings,
api_version: api_version,
headers: headers
) do |transport|
apis = API.defaults

transport.api API::ROOT, apis[API::ROOT]

# Apply any settings given by options
unless options.empty?
transport.default_api = options[:api_version] if options.key?(:api_version)
transport.headers options[:headers] if options.key?(:headers)
end

# Call block to apply any customization, if provided
yield(transport) if block_given?
end
end.to_transport(Core::Remote::Transport::Negotiation::Transport)
end

# Builds a new Transport::HTTP::Client with default settings
# Pass a block to override any settings.
def v7(
agent_settings:,
**options
api_version: nil,
headers: nil
)
new(Core::Remote::Transport::Config::Transport) do |transport|
transport.adapter(agent_settings)
transport.headers default_headers

Core::Transport::HTTP.build(
api_instance_class: API::Instance,
agent_settings: agent_settings,
api_version: api_version,
headers: headers
) do |transport|
apis = API.defaults

transport.api API::V7, apis[API::V7]

# Apply any settings given by options
unless options.empty?
transport.default_api = options[:api_version] if options.key?(:api_version)
transport.headers options[:headers] if options.key?(:headers)
end

# Call block to apply any customization, if provided
yield(transport) if block_given?
end
end

def default_headers
{
Datadog::Core::Transport::Ext::HTTP::HEADER_CLIENT_COMPUTED_TOP_LEVEL => '1',
Datadog::Core::Transport::Ext::HTTP::HEADER_META_LANG => Datadog::Core::Environment::Ext::LANG,
Datadog::Core::Transport::Ext::HTTP::HEADER_META_LANG_VERSION =>
Datadog::Core::Environment::Ext::LANG_VERSION,
Datadog::Core::Transport::Ext::HTTP::HEADER_META_LANG_INTERPRETER =>
Datadog::Core::Environment::Ext::LANG_INTERPRETER,
Datadog::Core::Transport::Ext::HTTP::HEADER_META_TRACER_VERSION =>
Datadog::Core::Environment::Ext::GEM_DATADOG_VERSION
}.tap do |headers|
# Add container ID, if present.
container_id = Datadog::Core::Environment::Container.container_id
headers[Datadog::Core::Transport::Ext::HTTP::HEADER_CONTAINER_ID] = container_id unless container_id.nil?
# 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.
if Datadog.configuration.appsec.standalone.enabled
headers[Datadog::Core::Transport::Ext::HTTP::HEADER_CLIENT_COMPUTED_STATS] = 'yes'
end
end
end

def default_adapter
Datadog::Core::Configuration::Ext::Agent::HTTP::ADAPTER
end.to_transport(Core::Remote::Transport::Config::Transport)
end
end
end
Expand Down
39 changes: 7 additions & 32 deletions lib/datadog/core/remote/transport/http/config.rb
Original file line number Diff line number Diff line change
Expand Up @@ -177,51 +177,26 @@ def config=(endpoint)
end

def send_config(env, &block)
raise NoConfigEndpointDefinedError, self if config.nil?
raise Core::Transport::HTTP::API::Spec::EndpointNotDefinedError.new(self, 'config') if config.nil?

config.call(env, &block)
end

# Raised when traces sent but no traces endpoint is defined
class NoConfigEndpointDefinedError < StandardError
attr_reader :spec

def initialize(spec)
super()

@spec = spec
end

def message
'No config endpoint is defined for API specification!'
end
end
end

# Extensions for HTTP API Instance
module Instance
def send_config(env)
raise ConfigNotSupportedError, spec unless spec.is_a?(Config::API::Spec)
unless spec.is_a?(Config::API::Spec)
raise Core::Transport::HTTP::API::Instance::EndpointNotSupportedError.new(
self,
'config'
)
end

spec.send_config(env) do |request_env|
call(request_env)
end
end

# Raised when traces sent to API that does not support traces
class ConfigNotSupportedError < StandardError
attr_reader :spec

def initialize(spec)
super()

@spec = spec
end

def message
'Config not supported for this API!'
end
end
end

# Endpoint for remote configuration
Expand Down
39 changes: 7 additions & 32 deletions lib/datadog/core/remote/transport/http/negotiation.rb
Original file line number Diff line number Diff line change
Expand Up @@ -50,51 +50,26 @@ def info=(endpoint)
end

def send_info(env, &block)
raise NoNegotiationEndpointDefinedError, self if info.nil?
raise Core::Transport::HTTP::API::Spec::EndpointNotDefinedError.new(self, 'info') if info.nil?

info.call(env, &block)
end

# Raised when traces sent but no traces endpoint is defined
class NoNegotiationEndpointDefinedError < StandardError
attr_reader :spec

def initialize(spec)
super()

@spec = spec
end

def message
'No info endpoint is defined for API specification!'
end
end
end

# Extensions for HTTP API Instance
module Instance
def send_info(env)
raise NegotiationNotSupportedError, spec unless spec.is_a?(Negotiation::API::Spec)
unless spec.is_a?(Negotiation::API::Spec)
raise Core::Transport::HTTP::API::Instance::EndpointNotSupportedError.new(
self,
'info'
)
end

spec.send_info(env) do |request_env|
call(request_env)
end
end

# Raised when traces sent to API that does not support traces
class NegotiationNotSupportedError < StandardError
attr_reader :spec

def initialize(spec)
super()

@spec = spec
end

def message
'Info not supported for this API!'
end
end
end

# Endpoint for negotiation
Expand Down
41 changes: 39 additions & 2 deletions lib/datadog/core/transport/http.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,45 @@ module HTTP
# Helper function that delegates to Builder.new
# but is under HTTP namespace so that client code requires this file
# to get the adapters configured, and not the builder directly.
def build(api_instance_class:, &block)
Builder.new(api_instance_class: api_instance_class, &block)
def build(api_instance_class:, agent_settings:, api_version: nil, headers: nil, &block)
Builder.new(api_instance_class: api_instance_class) do |transport|
transport.adapter(agent_settings)
transport.headers(default_headers)

# The caller must define APIs before we set the default API.
yield transport

# Apply any settings given by options
transport.default_api = api_version if api_version
transport.headers(headers) if headers
end
end

def default_headers
{
Datadog::Core::Transport::Ext::HTTP::HEADER_CLIENT_COMPUTED_TOP_LEVEL => '1',
Datadog::Core::Transport::Ext::HTTP::HEADER_META_LANG =>
Datadog::Core::Environment::Ext::LANG,
Datadog::Core::Transport::Ext::HTTP::HEADER_META_LANG_VERSION =>
Datadog::Core::Environment::Ext::LANG_VERSION,
Datadog::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::Environment::Ext::LANG_ENGINE,
Datadog::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
end
# TODO: inject configuration rather than reading from global here
if Datadog.configuration.appsec.standalone.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'
end
end
end
end
end
Expand Down
17 changes: 17 additions & 0 deletions lib/datadog/core/transport/http/api/instance.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,23 @@ module HTTP
module API
# An API configured with adapter and routes
class Instance
# Raised when an endpoint is invoked on an API that is not the
# of expected API class for that endpoint.
class EndpointNotSupportedError < StandardError
attr_reader :spec, :endpoint_name

def initialize(spec, endpoint_name)
@spec = spec
@endpoint_name = endpoint_name

super(message)
end

def message
"#{endpoint_name} not supported for this API!"
end
end

attr_reader \
:adapter,
:headers,
Expand Down
17 changes: 17 additions & 0 deletions lib/datadog/core/transport/http/api/spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,23 @@ module API
# Specification for an HTTP API
# Defines behaviors without specific configuration details.
class Spec
# Raised when an endpoint is invoked on an API that did not
# define that endpoint.
class EndpointNotDefinedError < StandardError
attr_reader :spec, :endpoint_name

def initialize(spec, endpoint_name)
@spec = spec
@endpoint_name = endpoint_name

super(message)
end

def message
"No #{endpoint_name} endpoint is defined for API specification!"
end
end

def initialize
yield(self) if block_given?
end
Expand Down
Loading
Loading