datadog 2.11.0 → 2.12.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +20 -2
- data/lib/datadog/appsec/contrib/active_record/instrumentation.rb +23 -6
- data/lib/datadog/appsec/contrib/active_record/patcher.rb +63 -12
- data/lib/datadog/appsec/contrib/rest_client/integration.rb +45 -0
- data/lib/datadog/appsec/contrib/rest_client/patcher.rb +28 -0
- data/lib/datadog/appsec/contrib/rest_client/request_ssrf_detection_patch.rb +39 -0
- data/lib/datadog/appsec.rb +1 -0
- data/lib/datadog/core/configuration/components.rb +10 -9
- data/lib/datadog/core/metrics/client.rb +9 -8
- data/lib/datadog/core/remote/client.rb +5 -4
- data/lib/datadog/core/remote/component.rb +14 -12
- data/lib/datadog/core/remote/negotiation.rb +1 -1
- data/lib/datadog/core/remote/transport/http.rb +4 -33
- data/lib/datadog/core/remote/worker.rb +10 -7
- data/lib/datadog/core/telemetry/component.rb +5 -1
- data/lib/datadog/core/telemetry/worker.rb +9 -5
- data/lib/datadog/core/transport/http.rb +38 -0
- data/lib/datadog/core/workers/runtime_metrics.rb +1 -1
- data/lib/datadog/di/component.rb +1 -3
- data/lib/datadog/di/probe_notifier_worker.rb +20 -4
- data/lib/datadog/di/transport/diagnostics.rb +61 -0
- data/lib/datadog/di/transport/http/api.rb +52 -0
- data/lib/datadog/di/transport/http/client.rb +46 -0
- data/lib/datadog/di/transport/http/diagnostics.rb +92 -0
- data/lib/datadog/di/transport/http/input.rb +94 -0
- data/lib/datadog/di/transport/http.rb +105 -0
- data/lib/datadog/di/transport/input.rb +61 -0
- data/lib/datadog/di.rb +2 -1
- data/lib/datadog/tracing/component.rb +1 -0
- data/lib/datadog/tracing/sync_writer.rb +9 -4
- data/lib/datadog/tracing/tracer.rb +15 -7
- data/lib/datadog/tracing/transport/http.rb +3 -32
- data/lib/datadog/tracing/workers/trace_writer.rb +10 -3
- data/lib/datadog/tracing/workers.rb +5 -4
- data/lib/datadog/tracing/writer.rb +12 -4
- data/lib/datadog/version.rb +2 -2
- metadata +15 -5
- data/lib/datadog/di/transport.rb +0 -79
@@ -5,7 +5,7 @@ module Datadog
|
|
5
5
|
module Remote
|
6
6
|
# Worker executes a block every interval on a separate Thread
|
7
7
|
class Worker
|
8
|
-
def initialize(interval:, &block)
|
8
|
+
def initialize(interval:, logger:, &block)
|
9
9
|
@mutex = Mutex.new
|
10
10
|
@thr = nil
|
11
11
|
|
@@ -14,18 +14,21 @@ module Datadog
|
|
14
14
|
@stopped = false
|
15
15
|
|
16
16
|
@interval = interval
|
17
|
+
@logger = logger
|
17
18
|
raise ArgumentError, 'can not initialize a worker without a block' unless block
|
18
19
|
|
19
20
|
@block = block
|
20
21
|
end
|
21
22
|
|
23
|
+
attr_reader :logger
|
24
|
+
|
22
25
|
def start
|
23
|
-
|
26
|
+
logger.debug { 'remote worker starting' }
|
24
27
|
|
25
28
|
acquire_lock
|
26
29
|
|
27
30
|
if @stopped
|
28
|
-
|
31
|
+
logger.debug('remote worker: refusing to restart after previous stop')
|
29
32
|
return
|
30
33
|
end
|
31
34
|
|
@@ -41,13 +44,13 @@ module Datadog
|
|
41
44
|
@started = true
|
42
45
|
@starting = false
|
43
46
|
|
44
|
-
|
47
|
+
logger.debug { 'remote worker started' }
|
45
48
|
ensure
|
46
49
|
release_lock
|
47
50
|
end
|
48
51
|
|
49
52
|
def stop
|
50
|
-
|
53
|
+
logger.debug { 'remote worker stopping' }
|
51
54
|
|
52
55
|
acquire_lock
|
53
56
|
|
@@ -62,7 +65,7 @@ module Datadog
|
|
62
65
|
@thr = nil
|
63
66
|
@stopped = true
|
64
67
|
|
65
|
-
|
68
|
+
logger.debug { 'remote worker stopped' }
|
66
69
|
ensure
|
67
70
|
release_lock
|
68
71
|
end
|
@@ -92,7 +95,7 @@ module Datadog
|
|
92
95
|
end
|
93
96
|
|
94
97
|
def call
|
95
|
-
|
98
|
+
logger.debug { 'remote worker perform' }
|
96
99
|
|
97
100
|
@block.call
|
98
101
|
end
|
@@ -16,7 +16,7 @@ module Datadog
|
|
16
16
|
# Telemetry entrypoint, coordinates sending telemetry events at various points in app lifecycle.
|
17
17
|
# Note: Telemetry does not spawn its worker thread in fork processes, thus no telemetry is sent in forked processes.
|
18
18
|
class Component
|
19
|
-
attr_reader :enabled
|
19
|
+
attr_reader :enabled, :logger
|
20
20
|
|
21
21
|
include Core::Utils::Forking
|
22
22
|
include Telemetry::Logging
|
@@ -52,6 +52,7 @@ module Datadog
|
|
52
52
|
heartbeat_interval_seconds: settings.telemetry.heartbeat_interval_seconds,
|
53
53
|
metrics_aggregation_interval_seconds: settings.telemetry.metrics_aggregation_interval_seconds,
|
54
54
|
dependency_collection: settings.telemetry.dependency_collection,
|
55
|
+
logger: logger,
|
55
56
|
shutdown_timeout_seconds: settings.telemetry.shutdown_timeout_seconds,
|
56
57
|
log_collection_enabled: settings.telemetry.log_collection_enabled
|
57
58
|
)
|
@@ -66,6 +67,7 @@ module Datadog
|
|
66
67
|
heartbeat_interval_seconds:,
|
67
68
|
metrics_aggregation_interval_seconds:,
|
68
69
|
dependency_collection:,
|
70
|
+
logger:,
|
69
71
|
http_transport:,
|
70
72
|
shutdown_timeout_seconds:,
|
71
73
|
enabled: true,
|
@@ -74,6 +76,7 @@ module Datadog
|
|
74
76
|
)
|
75
77
|
@enabled = enabled
|
76
78
|
@log_collection_enabled = log_collection_enabled
|
79
|
+
@logger = logger
|
77
80
|
|
78
81
|
@metrics_manager = MetricsManager.new(
|
79
82
|
enabled: enabled && metrics_enabled,
|
@@ -87,6 +90,7 @@ module Datadog
|
|
87
90
|
emitter: Emitter.new(http_transport: http_transport),
|
88
91
|
metrics_manager: @metrics_manager,
|
89
92
|
dependency_collection: dependency_collection,
|
93
|
+
logger: logger,
|
90
94
|
shutdown_timeout: shutdown_timeout_seconds
|
91
95
|
)
|
92
96
|
|
@@ -25,6 +25,7 @@ module Datadog
|
|
25
25
|
emitter:,
|
26
26
|
metrics_manager:,
|
27
27
|
dependency_collection:,
|
28
|
+
logger:,
|
28
29
|
enabled: true,
|
29
30
|
shutdown_timeout: Workers::Polling::DEFAULT_SHUTDOWN_TIMEOUT,
|
30
31
|
buffer_size: DEFAULT_BUFFER_MAX_SIZE
|
@@ -32,6 +33,7 @@ module Datadog
|
|
32
33
|
@emitter = emitter
|
33
34
|
@metrics_manager = metrics_manager
|
34
35
|
@dependency_collection = dependency_collection
|
36
|
+
@logger = logger
|
35
37
|
|
36
38
|
@ticks_per_heartbeat = (heartbeat_interval_seconds / metrics_aggregation_interval_seconds).to_i
|
37
39
|
@current_ticks = 0
|
@@ -48,6 +50,8 @@ module Datadog
|
|
48
50
|
self.buffer = buffer_klass.new(@buffer_size)
|
49
51
|
end
|
50
52
|
|
53
|
+
attr_reader :logger
|
54
|
+
|
51
55
|
def start
|
52
56
|
return if !enabled? || forked?
|
53
57
|
|
@@ -99,7 +103,7 @@ module Datadog
|
|
99
103
|
|
100
104
|
events = deduplicate_logs(events)
|
101
105
|
|
102
|
-
|
106
|
+
logger.debug { "Sending #{events&.count} telemetry events" }
|
103
107
|
send_event(Event::MessageBatch.new(events))
|
104
108
|
end
|
105
109
|
|
@@ -113,7 +117,7 @@ module Datadog
|
|
113
117
|
return unless enabled?
|
114
118
|
|
115
119
|
if failed_to_start?
|
116
|
-
|
120
|
+
logger.debug('Telemetry app-started event exhausted retries, disabling telemetry worker')
|
117
121
|
disable!
|
118
122
|
return
|
119
123
|
end
|
@@ -122,13 +126,13 @@ module Datadog
|
|
122
126
|
res = send_event(Event::AppStarted.new)
|
123
127
|
|
124
128
|
if res.ok?
|
125
|
-
|
129
|
+
logger.debug('Telemetry app-started event is successfully sent')
|
126
130
|
|
127
131
|
send_event(Event::AppDependenciesLoaded.new) if @dependency_collection
|
128
132
|
|
129
133
|
true
|
130
134
|
else
|
131
|
-
|
135
|
+
logger.debug('Error sending telemetry app-started event, retry after heartbeat interval...')
|
132
136
|
false
|
133
137
|
end
|
134
138
|
end
|
@@ -166,7 +170,7 @@ module Datadog
|
|
166
170
|
def disable_on_not_found!(response)
|
167
171
|
return unless response.not_found?
|
168
172
|
|
169
|
-
|
173
|
+
logger.debug('Agent does not support telemetry; disabling future telemetry events.')
|
170
174
|
disable!
|
171
175
|
end
|
172
176
|
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'http/builder'
|
4
|
+
require_relative 'http/adapters/net'
|
5
|
+
require_relative 'http/adapters/unix_socket'
|
6
|
+
require_relative 'http/adapters/test'
|
7
|
+
|
8
|
+
module Datadog
|
9
|
+
module Core
|
10
|
+
module Transport
|
11
|
+
# HTTP transport
|
12
|
+
module HTTP
|
13
|
+
# Add adapters to registry
|
14
|
+
Builder::REGISTRY.set(
|
15
|
+
Transport::HTTP::Adapters::Net,
|
16
|
+
Core::Configuration::Ext::Agent::HTTP::ADAPTER
|
17
|
+
)
|
18
|
+
Builder::REGISTRY.set(
|
19
|
+
Transport::HTTP::Adapters::Test,
|
20
|
+
Transport::Ext::Test::ADAPTER
|
21
|
+
)
|
22
|
+
Builder::REGISTRY.set(
|
23
|
+
Transport::HTTP::Adapters::UnixSocket,
|
24
|
+
Transport::Ext::UnixSocket::ADAPTER
|
25
|
+
)
|
26
|
+
|
27
|
+
module_function
|
28
|
+
|
29
|
+
# Helper function that delegates to Builder.new
|
30
|
+
# but is under HTTP namespace so that client code requires this file
|
31
|
+
# to get the adapters configured, and not the builder directly.
|
32
|
+
def build(api_instance_class:, &block)
|
33
|
+
Builder.new(api_instance_class: api_instance_class, &block)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -21,7 +21,7 @@ module Datadog
|
|
21
21
|
:metrics
|
22
22
|
|
23
23
|
def initialize(options = {})
|
24
|
-
@metrics = options.fetch(:metrics) { Core::Runtime::Metrics.new }
|
24
|
+
@metrics = options.fetch(:metrics) { Core::Runtime::Metrics.new(logger: options[:logger]) }
|
25
25
|
|
26
26
|
# Workers::Async::Thread settings
|
27
27
|
self.fork_policy = options.fetch(:fork_policy, Workers::Async::Thread::FORK_POLICY_STOP)
|
data/lib/datadog/di/component.rb
CHANGED
@@ -81,8 +81,7 @@ module Datadog
|
|
81
81
|
@redactor = Redactor.new(settings)
|
82
82
|
@serializer = Serializer.new(settings, redactor, telemetry: telemetry)
|
83
83
|
@instrumenter = Instrumenter.new(settings, serializer, logger, code_tracker: code_tracker, telemetry: telemetry)
|
84
|
-
@
|
85
|
-
@probe_notifier_worker = ProbeNotifierWorker.new(settings, transport, logger, telemetry: telemetry)
|
84
|
+
@probe_notifier_worker = ProbeNotifierWorker.new(settings, logger, agent_settings: agent_settings, telemetry: telemetry)
|
86
85
|
@probe_notification_builder = ProbeNotificationBuilder.new(settings, serializer)
|
87
86
|
@probe_manager = ProbeManager.new(settings, instrumenter, probe_notification_builder, probe_notifier_worker, logger, telemetry: telemetry)
|
88
87
|
probe_notifier_worker.start
|
@@ -94,7 +93,6 @@ module Datadog
|
|
94
93
|
attr_reader :telemetry
|
95
94
|
attr_reader :code_tracker
|
96
95
|
attr_reader :instrumenter
|
97
|
-
attr_reader :transport
|
98
96
|
attr_reader :probe_notifier_worker
|
99
97
|
attr_reader :probe_notification_builder
|
100
98
|
attr_reader :probe_manager
|
@@ -23,12 +23,12 @@ module Datadog
|
|
23
23
|
#
|
24
24
|
# @api private
|
25
25
|
class ProbeNotifierWorker
|
26
|
-
def initialize(settings,
|
26
|
+
def initialize(settings, logger, agent_settings:, telemetry: nil)
|
27
27
|
@settings = settings
|
28
28
|
@telemetry = telemetry
|
29
29
|
@status_queue = []
|
30
30
|
@snapshot_queue = []
|
31
|
-
@
|
31
|
+
@agent_settings = agent_settings
|
32
32
|
@logger = logger
|
33
33
|
@lock = Mutex.new
|
34
34
|
@wake = Core::Semaphore.new
|
@@ -43,6 +43,7 @@ module Datadog
|
|
43
43
|
attr_reader :settings
|
44
44
|
attr_reader :logger
|
45
45
|
attr_reader :telemetry
|
46
|
+
attr_reader :agent_settings
|
46
47
|
|
47
48
|
def start
|
48
49
|
return if @thread && @pid == Process.pid
|
@@ -154,7 +155,6 @@ module Datadog
|
|
154
155
|
|
155
156
|
private
|
156
157
|
|
157
|
-
attr_reader :transport
|
158
158
|
attr_reader :wake
|
159
159
|
attr_reader :thread
|
160
160
|
|
@@ -170,6 +170,22 @@ module Datadog
|
|
170
170
|
|
171
171
|
attr_reader :last_sent
|
172
172
|
|
173
|
+
def status_transport
|
174
|
+
@status_transport ||= DI::Transport::HTTP.diagnostics(agent_settings: agent_settings)
|
175
|
+
end
|
176
|
+
|
177
|
+
def do_send_status(batch)
|
178
|
+
status_transport.send_diagnostics(batch)
|
179
|
+
end
|
180
|
+
|
181
|
+
def snapshot_transport
|
182
|
+
@snapshot_transport ||= DI::Transport::HTTP.input(agent_settings: agent_settings)
|
183
|
+
end
|
184
|
+
|
185
|
+
def do_send_snapshot(batch)
|
186
|
+
snapshot_transport.send_input(batch)
|
187
|
+
end
|
188
|
+
|
173
189
|
[
|
174
190
|
[:status, 'probe status'],
|
175
191
|
[:snapshot, 'snapshot'],
|
@@ -245,7 +261,7 @@ module Datadog
|
|
245
261
|
if batch.any? # steep:ignore
|
246
262
|
begin
|
247
263
|
logger.trace { "di: sending #{batch.length} #{event_type} event(s) to agent" } # steep:ignore
|
248
|
-
|
264
|
+
send("do_send_#{event_type}", batch)
|
249
265
|
time = Core::Utils::Time.get_time
|
250
266
|
@lock.synchronize do
|
251
267
|
@last_sent = time
|
@@ -0,0 +1,61 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../../core/transport/parcel'
|
4
|
+
require_relative 'http/client'
|
5
|
+
|
6
|
+
module Datadog
|
7
|
+
module DI
|
8
|
+
module Transport
|
9
|
+
module Diagnostics
|
10
|
+
class EncodedParcel
|
11
|
+
include Datadog::Core::Transport::Parcel
|
12
|
+
end
|
13
|
+
|
14
|
+
class Request < Datadog::Core::Transport::Request
|
15
|
+
end
|
16
|
+
|
17
|
+
class Transport
|
18
|
+
attr_reader :client, :apis, :default_api, :current_api_id
|
19
|
+
|
20
|
+
def initialize(apis, default_api)
|
21
|
+
@apis = apis
|
22
|
+
|
23
|
+
@client = HTTP::Client.new(current_api)
|
24
|
+
end
|
25
|
+
|
26
|
+
def current_api
|
27
|
+
@apis[HTTP::API::DIAGNOSTICS]
|
28
|
+
end
|
29
|
+
|
30
|
+
def send_diagnostics(payload)
|
31
|
+
json = JSON.dump(payload)
|
32
|
+
parcel = EncodedParcel.new(json)
|
33
|
+
request = Request.new(parcel)
|
34
|
+
|
35
|
+
response = @client.send_diagnostics_payload(request)
|
36
|
+
unless response.ok?
|
37
|
+
# TODO Datadog::Core::Transport::InternalErrorResponse
|
38
|
+
# does not have +code+ method, what is the actual API of
|
39
|
+
# these response objects?
|
40
|
+
raise Error::AgentCommunicationError, "send_diagnostics failed: #{begin
|
41
|
+
response.code
|
42
|
+
rescue
|
43
|
+
"???"
|
44
|
+
end}: #{response.payload}"
|
45
|
+
end
|
46
|
+
rescue Error::AgentCommunicationError
|
47
|
+
raise
|
48
|
+
# Datadog::Core::Transport does not perform any exception mapping,
|
49
|
+
# therefore we could have any exception here from failure to parse
|
50
|
+
# agent URI for example.
|
51
|
+
# If we ever implement retries for network errors, we should distinguish
|
52
|
+
# actual network errors from non-network errors that are raised by
|
53
|
+
# transport code.
|
54
|
+
rescue => exc
|
55
|
+
raise Error::AgentCommunicationError, "send_diagnostics failed: #{exc.class}: #{exc}"
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../../../core/encoding'
|
4
|
+
require_relative '../../../core/transport/http/api/map'
|
5
|
+
require_relative '../../../core/transport/http/api/instance'
|
6
|
+
require_relative '../../../core/transport/http/api/spec'
|
7
|
+
require_relative 'diagnostics'
|
8
|
+
require_relative 'input'
|
9
|
+
|
10
|
+
module Datadog
|
11
|
+
module DI
|
12
|
+
module Transport
|
13
|
+
module HTTP
|
14
|
+
# Namespace for API components
|
15
|
+
module API
|
16
|
+
# Default API versions
|
17
|
+
DIAGNOSTICS = 'diagnostics'
|
18
|
+
INPUT = 'input'
|
19
|
+
|
20
|
+
module_function
|
21
|
+
|
22
|
+
def defaults
|
23
|
+
Datadog::Core::Transport::HTTP::API::Map[
|
24
|
+
DIAGNOSTICS => Spec.new do |s|
|
25
|
+
s.diagnostics = Diagnostics::API::Endpoint.new(
|
26
|
+
'/debugger/v1/diagnostics',
|
27
|
+
Core::Encoding::JSONEncoder,
|
28
|
+
)
|
29
|
+
end,
|
30
|
+
INPUT => Spec.new do |s|
|
31
|
+
s.input = Input::API::Endpoint.new(
|
32
|
+
'/debugger/v1/input',
|
33
|
+
Core::Encoding::JSONEncoder,
|
34
|
+
)
|
35
|
+
end,
|
36
|
+
]
|
37
|
+
end
|
38
|
+
|
39
|
+
class Instance < Core::Transport::HTTP::API::Instance
|
40
|
+
include Diagnostics::API::Instance
|
41
|
+
include Input::API::Instance
|
42
|
+
end
|
43
|
+
|
44
|
+
class Spec < Core::Transport::HTTP::API::Spec
|
45
|
+
include Diagnostics::API::Spec
|
46
|
+
include Input::API::Spec
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../../../core/transport/http/env'
|
4
|
+
require_relative '../../../core/transport/http/response'
|
5
|
+
|
6
|
+
# TODO: Decouple transport/http/client
|
7
|
+
#
|
8
|
+
# The standard one does `include Transport::HTTP::Statistics` and performs
|
9
|
+
# stats updates, which may or may not be desirable in general.
|
10
|
+
|
11
|
+
module Datadog
|
12
|
+
module DI
|
13
|
+
module Transport
|
14
|
+
module HTTP
|
15
|
+
# Routes, encodes, and sends DI data to the trace agent via HTTP.
|
16
|
+
class Client
|
17
|
+
attr_reader :api
|
18
|
+
|
19
|
+
def initialize(api)
|
20
|
+
@api = api
|
21
|
+
end
|
22
|
+
|
23
|
+
def send_request(request, &block)
|
24
|
+
# Build request into env
|
25
|
+
env = build_env(request)
|
26
|
+
|
27
|
+
# Get responses from API
|
28
|
+
yield(api, env)
|
29
|
+
rescue => e
|
30
|
+
message =
|
31
|
+
"Internal error during #{self.class.name} request. Cause: #{e.class.name} #{e.message} " \
|
32
|
+
"Location: #{Array(e.backtrace).first}"
|
33
|
+
|
34
|
+
Datadog.logger.debug(message)
|
35
|
+
|
36
|
+
Datadog::Core::Transport::InternalErrorResponse.new(e)
|
37
|
+
end
|
38
|
+
|
39
|
+
def build_env(request)
|
40
|
+
Datadog::Core::Transport::HTTP::Env.new(request)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'client'
|
4
|
+
|
5
|
+
module Datadog
|
6
|
+
module DI
|
7
|
+
module Transport
|
8
|
+
module HTTP
|
9
|
+
module Diagnostics
|
10
|
+
module Client
|
11
|
+
def send_diagnostics_payload(request)
|
12
|
+
send_request(request) do |api, env|
|
13
|
+
api.send_diagnostics(env)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
module API
|
19
|
+
module Instance
|
20
|
+
def send_diagnostics(env)
|
21
|
+
raise DiagnosticsNotSupportedError, spec unless spec.is_a?(Diagnostics::API::Spec)
|
22
|
+
|
23
|
+
spec.send_diagnostics(env) do |request_env|
|
24
|
+
call(request_env)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
class DiagnosticsNotSupportedError < StandardError
|
29
|
+
attr_reader :spec
|
30
|
+
|
31
|
+
def initialize(spec)
|
32
|
+
super
|
33
|
+
|
34
|
+
@spec = spec
|
35
|
+
end
|
36
|
+
|
37
|
+
def message
|
38
|
+
'Diagnostics not supported for this API!'
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
module Spec
|
44
|
+
attr_accessor :diagnostics
|
45
|
+
|
46
|
+
def send_diagnostics(env, &block)
|
47
|
+
raise NoDiagnosticsEndpointDefinedError, self if diagnostics.nil?
|
48
|
+
|
49
|
+
diagnostics.call(env, &block)
|
50
|
+
end
|
51
|
+
|
52
|
+
class NoDiagnosticsEndpointDefinedError < StandardError
|
53
|
+
attr_reader :spec
|
54
|
+
|
55
|
+
def initialize(spec)
|
56
|
+
super
|
57
|
+
|
58
|
+
@spec = spec
|
59
|
+
end
|
60
|
+
|
61
|
+
def message
|
62
|
+
'No diagnostics endpoint is defined for API specification!'
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
# Endpoint for negotiation
|
68
|
+
class Endpoint < Datadog::Core::Transport::HTTP::API::Endpoint
|
69
|
+
attr_reader :encoder
|
70
|
+
|
71
|
+
def initialize(path, encoder)
|
72
|
+
super(:post, path)
|
73
|
+
@encoder = encoder
|
74
|
+
end
|
75
|
+
|
76
|
+
def call(env, &block)
|
77
|
+
event_payload = Core::Vendor::Multipart::Post::UploadIO.new(
|
78
|
+
StringIO.new(env.request.parcel.data), 'application/json', 'event.json'
|
79
|
+
)
|
80
|
+
env.form = {'event' => event_payload}
|
81
|
+
|
82
|
+
super(env, &block)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
HTTP::Client.include(Diagnostics::Client)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'client'
|
4
|
+
|
5
|
+
module Datadog
|
6
|
+
module DI
|
7
|
+
module Transport
|
8
|
+
module HTTP
|
9
|
+
module Input
|
10
|
+
module Client
|
11
|
+
def send_input_payload(request)
|
12
|
+
send_request(request) do |api, env|
|
13
|
+
api.send_input(env)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
module API
|
19
|
+
module Instance
|
20
|
+
def send_input(env)
|
21
|
+
raise InputNotSupportedError, spec unless spec.is_a?(Input::API::Spec)
|
22
|
+
|
23
|
+
spec.send_input(env) do |request_env|
|
24
|
+
call(request_env)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
class InputNotSupportedError < StandardError
|
29
|
+
attr_reader :spec
|
30
|
+
|
31
|
+
def initialize(spec)
|
32
|
+
super
|
33
|
+
|
34
|
+
@spec = spec
|
35
|
+
end
|
36
|
+
|
37
|
+
def message
|
38
|
+
'Input not supported for this API!'
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
module Spec
|
44
|
+
attr_accessor :input
|
45
|
+
|
46
|
+
def send_input(env, &block)
|
47
|
+
raise NoInputEndpointDefinedError, self if input.nil?
|
48
|
+
|
49
|
+
input.call(env, &block)
|
50
|
+
end
|
51
|
+
|
52
|
+
class NoInputEndpointDefinedError < StandardError
|
53
|
+
attr_reader :spec
|
54
|
+
|
55
|
+
def initialize(spec)
|
56
|
+
super
|
57
|
+
|
58
|
+
@spec = spec
|
59
|
+
end
|
60
|
+
|
61
|
+
def message
|
62
|
+
'No input endpoint is defined for API specification!'
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
# Endpoint for negotiation
|
68
|
+
class Endpoint < Datadog::Core::Transport::HTTP::API::Endpoint
|
69
|
+
HEADER_CONTENT_TYPE = 'Content-Type'
|
70
|
+
|
71
|
+
attr_reader \
|
72
|
+
:encoder
|
73
|
+
|
74
|
+
def initialize(path, encoder)
|
75
|
+
super(:post, path)
|
76
|
+
@encoder = encoder
|
77
|
+
end
|
78
|
+
|
79
|
+
def call(env, &block)
|
80
|
+
# Encode body & type
|
81
|
+
env.headers[HEADER_CONTENT_TYPE] = encoder.content_type
|
82
|
+
env.body = env.request.parcel.data
|
83
|
+
|
84
|
+
super(env, &block)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
HTTP::Client.include(Input::Client)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|