datadog 2.23.0 → 2.25.0
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 +67 -1
- data/ext/datadog_profiling_native_extension/collectors_stack.c +17 -5
- data/ext/datadog_profiling_native_extension/crashtracking_runtime_stacks.c +239 -0
- data/ext/datadog_profiling_native_extension/extconf.rb +4 -1
- data/ext/datadog_profiling_native_extension/private_vm_api_access.c +12 -0
- data/ext/datadog_profiling_native_extension/private_vm_api_access.h +4 -0
- data/ext/datadog_profiling_native_extension/profiling.c +2 -0
- data/lib/datadog/ai_guard/api_client.rb +82 -0
- data/lib/datadog/ai_guard/component.rb +42 -0
- data/lib/datadog/ai_guard/configuration/ext.rb +17 -0
- data/lib/datadog/ai_guard/configuration/settings.rb +98 -0
- data/lib/datadog/ai_guard/configuration.rb +11 -0
- data/lib/datadog/ai_guard/evaluation/message.rb +25 -0
- data/lib/datadog/ai_guard/evaluation/no_op_result.rb +34 -0
- data/lib/datadog/ai_guard/evaluation/request.rb +81 -0
- data/lib/datadog/ai_guard/evaluation/result.rb +43 -0
- data/lib/datadog/ai_guard/evaluation/tool_call.rb +18 -0
- data/lib/datadog/ai_guard/evaluation.rb +72 -0
- data/lib/datadog/ai_guard/ext.rb +16 -0
- data/lib/datadog/ai_guard.rb +153 -0
- data/lib/datadog/appsec/context.rb +2 -1
- data/lib/datadog/appsec/remote.rb +5 -12
- data/lib/datadog/appsec/security_engine/engine.rb +3 -3
- data/lib/datadog/appsec/security_engine/result.rb +2 -1
- data/lib/datadog/appsec/security_engine/runner.rb +2 -2
- data/lib/datadog/core/configuration/components.rb +6 -0
- data/lib/datadog/core/configuration/config_helper.rb +1 -1
- data/lib/datadog/core/configuration/deprecations.rb +2 -2
- data/lib/datadog/core/configuration/option_definition.rb +4 -2
- data/lib/datadog/core/configuration/options.rb +8 -5
- data/lib/datadog/core/configuration/settings.rb +14 -3
- data/lib/datadog/core/configuration/supported_configurations.rb +8 -1
- data/lib/datadog/core/environment/cgroup.rb +52 -25
- data/lib/datadog/core/environment/container.rb +140 -46
- data/lib/datadog/core/environment/ext.rb +1 -0
- data/lib/datadog/core/environment/process.rb +9 -1
- data/lib/datadog/core/error.rb +6 -6
- data/lib/datadog/core/pin.rb +4 -0
- data/lib/datadog/core/rate_limiter.rb +9 -1
- data/lib/datadog/core/remote/client.rb +14 -6
- data/lib/datadog/core/remote/component.rb +6 -4
- data/lib/datadog/core/remote/configuration/content.rb +15 -2
- data/lib/datadog/core/remote/configuration/digest.rb +14 -7
- data/lib/datadog/core/remote/configuration/repository.rb +1 -1
- data/lib/datadog/core/remote/configuration/target.rb +13 -6
- data/lib/datadog/core/remote/transport/config.rb +3 -16
- data/lib/datadog/core/remote/transport/http/config.rb +4 -44
- data/lib/datadog/core/remote/transport/http/negotiation.rb +0 -39
- data/lib/datadog/core/remote/transport/http.rb +13 -24
- data/lib/datadog/core/remote/transport/negotiation.rb +7 -16
- data/lib/datadog/core/semaphore.rb +1 -4
- data/lib/datadog/core/telemetry/component.rb +52 -13
- data/lib/datadog/core/telemetry/event/app_started.rb +36 -1
- data/lib/datadog/core/telemetry/event/synth_app_client_configuration_change.rb +27 -4
- data/lib/datadog/core/telemetry/metrics_manager.rb +9 -0
- data/lib/datadog/core/telemetry/request.rb +17 -3
- data/lib/datadog/core/telemetry/transport/http/telemetry.rb +2 -32
- data/lib/datadog/core/telemetry/transport/http.rb +21 -16
- data/lib/datadog/core/telemetry/transport/telemetry.rb +3 -10
- data/lib/datadog/core/telemetry/worker.rb +88 -32
- data/lib/datadog/core/transport/ext.rb +2 -0
- data/lib/datadog/core/transport/http/api/endpoint.rb +9 -4
- data/lib/datadog/core/transport/http/api/instance.rb +4 -21
- data/lib/datadog/core/transport/http/builder.rb +9 -5
- data/lib/datadog/core/transport/http/client.rb +19 -8
- data/lib/datadog/core/transport/http.rb +22 -19
- data/lib/datadog/core/transport/response.rb +12 -1
- data/lib/datadog/core/transport/transport.rb +90 -0
- data/lib/datadog/core/utils/only_once_successful.rb +2 -0
- data/lib/datadog/core/utils/safe_dup.rb +2 -2
- data/lib/datadog/core/utils/sequence.rb +2 -0
- data/lib/datadog/core/utils/time.rb +1 -1
- data/lib/datadog/core/workers/async.rb +10 -1
- data/lib/datadog/core/workers/interval_loop.rb +44 -3
- data/lib/datadog/core/workers/polling.rb +2 -0
- data/lib/datadog/core/workers/queue.rb +100 -1
- data/lib/datadog/data_streams/processor.rb +1 -1
- data/lib/datadog/data_streams/transport/http/stats.rb +1 -36
- data/lib/datadog/data_streams/transport/http.rb +5 -6
- data/lib/datadog/data_streams/transport/stats.rb +3 -17
- data/lib/datadog/di/boot.rb +4 -2
- data/lib/datadog/di/contrib/active_record.rb +30 -5
- data/lib/datadog/di/el/compiler.rb +8 -4
- data/lib/datadog/di/error.rb +5 -0
- data/lib/datadog/di/instrumenter.rb +26 -7
- data/lib/datadog/di/logger.rb +2 -2
- data/lib/datadog/di/probe_builder.rb +2 -1
- data/lib/datadog/di/probe_file_loader/railtie.rb +1 -1
- data/lib/datadog/di/probe_manager.rb +37 -31
- data/lib/datadog/di/probe_notification_builder.rb +15 -2
- data/lib/datadog/di/probe_notifier_worker.rb +5 -5
- data/lib/datadog/di/remote.rb +89 -84
- data/lib/datadog/di/transport/diagnostics.rb +7 -35
- data/lib/datadog/di/transport/http/diagnostics.rb +1 -31
- data/lib/datadog/di/transport/http/input.rb +1 -31
- data/lib/datadog/di/transport/http.rb +28 -17
- data/lib/datadog/di/transport/input.rb +7 -34
- data/lib/datadog/di.rb +61 -5
- data/lib/datadog/error_tracking/filters.rb +2 -2
- data/lib/datadog/kit/appsec/events/v2.rb +2 -3
- data/lib/datadog/open_feature/evaluation_engine.rb +2 -1
- data/lib/datadog/open_feature/remote.rb +3 -10
- data/lib/datadog/open_feature/transport.rb +9 -11
- data/lib/datadog/opentelemetry/api/baggage.rb +1 -1
- data/lib/datadog/opentelemetry/configuration/settings.rb +2 -2
- data/lib/datadog/opentelemetry/metrics.rb +21 -14
- data/lib/datadog/opentelemetry/sdk/metrics_exporter.rb +5 -8
- data/lib/datadog/profiling/collectors/code_provenance.rb +27 -2
- data/lib/datadog/profiling/collectors/info.rb +5 -4
- data/lib/datadog/profiling/component.rb +12 -11
- data/lib/datadog/profiling/ext/dir_monkey_patches.rb +18 -0
- data/lib/datadog/profiling/http_transport.rb +4 -1
- data/lib/datadog/tracing/contrib/extensions.rb +10 -2
- data/lib/datadog/tracing/contrib/karafka/patcher.rb +31 -32
- data/lib/datadog/tracing/contrib/status_range_matcher.rb +2 -1
- data/lib/datadog/tracing/contrib/utils/quantization/hash.rb +3 -1
- data/lib/datadog/tracing/contrib/waterdrop/patcher.rb +6 -3
- data/lib/datadog/tracing/contrib/waterdrop.rb +4 -0
- data/lib/datadog/tracing/diagnostics/environment_logger.rb +1 -1
- data/lib/datadog/tracing/distributed/baggage.rb +3 -2
- data/lib/datadog/tracing/remote.rb +1 -9
- data/lib/datadog/tracing/sampling/priority_sampler.rb +3 -1
- data/lib/datadog/tracing/span.rb +1 -1
- data/lib/datadog/tracing/span_event.rb +2 -2
- data/lib/datadog/tracing/span_operation.rb +20 -9
- data/lib/datadog/tracing/trace_operation.rb +44 -6
- data/lib/datadog/tracing/tracer.rb +42 -16
- data/lib/datadog/tracing/transport/http/traces.rb +2 -50
- data/lib/datadog/tracing/transport/http.rb +15 -9
- data/lib/datadog/tracing/transport/io/client.rb +1 -1
- data/lib/datadog/tracing/transport/traces.rb +6 -66
- data/lib/datadog/tracing/workers/trace_writer.rb +5 -0
- data/lib/datadog/tracing/writer.rb +1 -0
- data/lib/datadog/version.rb +2 -2
- data/lib/datadog.rb +1 -0
- metadata +24 -17
- data/lib/datadog/core/remote/transport/http/api.rb +0 -53
- data/lib/datadog/core/telemetry/transport/http/api.rb +0 -43
- data/lib/datadog/core/transport/http/api/spec.rb +0 -36
- data/lib/datadog/data_streams/transport/http/api.rb +0 -33
- data/lib/datadog/data_streams/transport/http/client.rb +0 -21
- data/lib/datadog/di/transport/http/api.rb +0 -42
- data/lib/datadog/opentelemetry/api/baggage.rbs +0 -26
- data/lib/datadog/tracing/transport/http/api.rb +0 -44
|
@@ -12,16 +12,16 @@ module Datadog
|
|
|
12
12
|
module HTTP
|
|
13
13
|
# Add adapters to registry
|
|
14
14
|
Builder::REGISTRY.set(
|
|
15
|
-
Transport::HTTP::Adapters::Net,
|
|
15
|
+
Core::Transport::HTTP::Adapters::Net,
|
|
16
16
|
Core::Configuration::Ext::Agent::HTTP::ADAPTER
|
|
17
17
|
)
|
|
18
18
|
Builder::REGISTRY.set(
|
|
19
|
-
Transport::HTTP::Adapters::Test,
|
|
20
|
-
Transport::Ext::Test::ADAPTER
|
|
19
|
+
Core::Transport::HTTP::Adapters::Test,
|
|
20
|
+
Core::Transport::Ext::Test::ADAPTER
|
|
21
21
|
)
|
|
22
22
|
Builder::REGISTRY.set(
|
|
23
|
-
Transport::HTTP::Adapters::UnixSocket,
|
|
24
|
-
Transport::Ext::UnixSocket::ADAPTER
|
|
23
|
+
Core::Transport::HTTP::Adapters::UnixSocket,
|
|
24
|
+
Core::Transport::Ext::UnixSocket::ADAPTER
|
|
25
25
|
)
|
|
26
26
|
|
|
27
27
|
module_function
|
|
@@ -29,8 +29,13 @@ module Datadog
|
|
|
29
29
|
# Helper function that delegates to Builder.new
|
|
30
30
|
# but is under HTTP namespace so that client code requires this file
|
|
31
31
|
# to get the adapters configured, and not the builder directly.
|
|
32
|
-
def build(
|
|
33
|
-
|
|
32
|
+
def build(
|
|
33
|
+
agent_settings:,
|
|
34
|
+
logger: Datadog.logger,
|
|
35
|
+
headers: nil,
|
|
36
|
+
&block
|
|
37
|
+
)
|
|
38
|
+
Builder.new(logger: logger) do |transport|
|
|
34
39
|
transport.adapter(agent_settings)
|
|
35
40
|
transport.headers(default_headers)
|
|
36
41
|
|
|
@@ -38,34 +43,32 @@ module Datadog
|
|
|
38
43
|
yield transport
|
|
39
44
|
|
|
40
45
|
# Apply any settings given by options
|
|
41
|
-
transport.default_api = api_version if api_version
|
|
42
46
|
transport.headers(headers) if headers
|
|
43
47
|
end
|
|
44
48
|
end
|
|
45
49
|
|
|
46
50
|
def default_headers
|
|
47
51
|
{
|
|
48
|
-
|
|
49
|
-
|
|
52
|
+
Core::Transport::Ext::HTTP::HEADER_CLIENT_COMPUTED_TOP_LEVEL => '1',
|
|
53
|
+
Core::Transport::Ext::HTTP::HEADER_META_LANG =>
|
|
50
54
|
Datadog::Core::Environment::Ext::LANG,
|
|
51
|
-
|
|
55
|
+
Core::Transport::Ext::HTTP::HEADER_META_LANG_VERSION =>
|
|
52
56
|
Datadog::Core::Environment::Ext::LANG_VERSION,
|
|
53
|
-
|
|
57
|
+
Core::Transport::Ext::HTTP::HEADER_META_LANG_INTERPRETER =>
|
|
54
58
|
Datadog::Core::Environment::Ext::LANG_INTERPRETER,
|
|
55
|
-
|
|
59
|
+
Core::Transport::Ext::HTTP::HEADER_META_LANG_INTERPRETER_VENDOR =>
|
|
56
60
|
Core::Environment::Ext::LANG_ENGINE,
|
|
57
|
-
|
|
61
|
+
Core::Transport::Ext::HTTP::HEADER_META_TRACER_VERSION =>
|
|
58
62
|
Datadog::Core::Environment::Ext::GEM_DATADOG_VERSION
|
|
59
63
|
}.tap do |headers|
|
|
60
|
-
# Add container
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
end
|
|
64
|
+
# Add application container info
|
|
65
|
+
headers.merge!(Core::Environment::Container.to_headers)
|
|
66
|
+
|
|
64
67
|
# TODO: inject configuration rather than reading from global here
|
|
65
68
|
unless Datadog.configuration.apm.tracing.enabled
|
|
66
69
|
# Sending this header to the agent will disable metrics computation (and billing) on the agent side
|
|
67
70
|
# by pretending it has already been done on the library side.
|
|
68
|
-
headers[
|
|
71
|
+
headers[Core::Transport::Ext::HTTP::HEADER_CLIENT_COMPUTED_STATS] = 'yes'
|
|
69
72
|
end
|
|
70
73
|
end
|
|
71
74
|
end
|
|
@@ -35,7 +35,18 @@ module Datadog
|
|
|
35
35
|
|
|
36
36
|
def inspect
|
|
37
37
|
maybe_code = if respond_to?(:code)
|
|
38
|
-
|
|
38
|
+
# Steep: `code` method may be defined by classes extending this module.
|
|
39
|
+
# There seem to be no annotation for this.
|
|
40
|
+
" code:#{code}," # steep:ignore NoMethod
|
|
41
|
+
end
|
|
42
|
+
payload = self.payload
|
|
43
|
+
# Truncation thresholds are arbitrary but we need to truncate the
|
|
44
|
+
# payload here because outputting multi-MB request body to the
|
|
45
|
+
# log is not useful.
|
|
46
|
+
#
|
|
47
|
+
# Note that payload can be nil here.
|
|
48
|
+
if payload && payload.length > 2000 # steep:ignore
|
|
49
|
+
payload = Utils::Truncation.truncate_in_middle(payload, 1500, 500) # steep:ignore
|
|
39
50
|
end
|
|
40
51
|
"#{self.class} ok?:#{ok?},#{maybe_code} unsupported?:#{unsupported?}, " \
|
|
41
52
|
"not_found?:#{not_found?}, client_error?:#{client_error?}, " \
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'http/client'
|
|
4
|
+
|
|
5
|
+
module Datadog
|
|
6
|
+
module Core
|
|
7
|
+
module Transport
|
|
8
|
+
# Raised when configured with an unknown API version
|
|
9
|
+
class UnknownApiVersionError < StandardError
|
|
10
|
+
attr_reader :version
|
|
11
|
+
|
|
12
|
+
def initialize(version)
|
|
13
|
+
super
|
|
14
|
+
|
|
15
|
+
@version = version
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def message
|
|
19
|
+
"No matching transport API for version #{version}!"
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# Raised when the API verson to downgrade to does not map to a
|
|
24
|
+
# defined API.
|
|
25
|
+
class NoDowngradeAvailableError < StandardError
|
|
26
|
+
attr_reader :version
|
|
27
|
+
|
|
28
|
+
def initialize(version)
|
|
29
|
+
super
|
|
30
|
+
|
|
31
|
+
@version = version
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def message
|
|
35
|
+
"No downgrade from transport API version #{version} is available!"
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Base class for transports.
|
|
40
|
+
class Transport
|
|
41
|
+
attr_reader :client, :apis, :default_api, :current_api_id, :logger
|
|
42
|
+
|
|
43
|
+
class << self
|
|
44
|
+
# The HTTP client class to use for requests, derived from
|
|
45
|
+
# Core::Transport::HTTP::Client.
|
|
46
|
+
#
|
|
47
|
+
# Important: this attribute is NOT inherited by derived classes -
|
|
48
|
+
# it must be set by every Transport class that wants to have a
|
|
49
|
+
# non-default HTTP::Client instance.
|
|
50
|
+
attr_accessor :http_client_class
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def initialize(apis, default_api, logger:)
|
|
54
|
+
@apis = apis
|
|
55
|
+
@default_api = default_api
|
|
56
|
+
@logger = logger
|
|
57
|
+
|
|
58
|
+
set_api!(default_api)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def current_api
|
|
62
|
+
apis[current_api_id]
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
private
|
|
66
|
+
|
|
67
|
+
def set_api!(api_id)
|
|
68
|
+
raise UnknownApiVersionError, api_id unless apis.key?(api_id)
|
|
69
|
+
|
|
70
|
+
@current_api_id = api_id
|
|
71
|
+
client_class = self.class.http_client_class || Core::Transport::HTTP::Client
|
|
72
|
+
@client = client_class.new(current_api, logger: logger) # steep:ignore
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def downgrade?(response)
|
|
76
|
+
return false unless apis.fallbacks.key?(current_api_id)
|
|
77
|
+
|
|
78
|
+
response.not_found? || response.unsupported?
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def downgrade!
|
|
82
|
+
downgrade_api_id = apis.fallbacks[current_api_id]
|
|
83
|
+
raise NoDowngradeAvailableError, current_api_id if downgrade_api_id.nil?
|
|
84
|
+
|
|
85
|
+
set_api!(downgrade_api_id)
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
@@ -5,8 +5,8 @@ module Datadog
|
|
|
5
5
|
module Utils
|
|
6
6
|
# Helper methods for safer dup
|
|
7
7
|
module SafeDup
|
|
8
|
-
#
|
|
9
|
-
def self.frozen_or_dup(v)
|
|
8
|
+
# Steep: https://github.com/soutaro/steep/issues/2001
|
|
9
|
+
def self.frozen_or_dup(v) # steep:ignore MethodBodyTypeMismatch
|
|
10
10
|
# For the case of a String we use the methods +@ and -@.
|
|
11
11
|
# Those methods are only for String objects
|
|
12
12
|
# they are faster and chepaer on the memory side.
|
|
@@ -10,7 +10,7 @@ module Datadog
|
|
|
10
10
|
# Current monotonic time
|
|
11
11
|
#
|
|
12
12
|
# @param unit [Symbol] unit for the resulting value, same as ::Process#clock_gettime, defaults to :float_second
|
|
13
|
-
# @return [
|
|
13
|
+
# @return [Float|Integer] timestamp in the requested unit, since some unspecified starting point
|
|
14
14
|
def get_time(unit = :float_second)
|
|
15
15
|
Process.clock_gettime(Process::CLOCK_MONOTONIC, unit)
|
|
16
16
|
end
|
|
@@ -8,6 +8,11 @@ module Datadog
|
|
|
8
8
|
module Async
|
|
9
9
|
# Adds threading behavior to workers
|
|
10
10
|
# to run tasks asynchronously.
|
|
11
|
+
#
|
|
12
|
+
# This module is included in Polling module, and has no other
|
|
13
|
+
# direct users.
|
|
14
|
+
#
|
|
15
|
+
# @api private
|
|
11
16
|
module Thread
|
|
12
17
|
FORK_POLICY_STOP = :stop
|
|
13
18
|
FORK_POLICY_RESTART = :restart
|
|
@@ -24,7 +29,11 @@ module Datadog
|
|
|
24
29
|
# Methods that must be prepended
|
|
25
30
|
module PrependedMethods
|
|
26
31
|
def perform(*args)
|
|
27
|
-
|
|
32
|
+
unless started?
|
|
33
|
+
start_async do
|
|
34
|
+
self.result = super(*args)
|
|
35
|
+
end
|
|
36
|
+
end
|
|
28
37
|
end
|
|
29
38
|
end
|
|
30
39
|
|
|
@@ -5,6 +5,11 @@ module Datadog
|
|
|
5
5
|
module Workers
|
|
6
6
|
# Adds looping behavior to workers, with a sleep
|
|
7
7
|
# interval between each loop.
|
|
8
|
+
#
|
|
9
|
+
# This module is included in Polling module, and has no other
|
|
10
|
+
# direct users.
|
|
11
|
+
#
|
|
12
|
+
# @api private
|
|
8
13
|
module IntervalLoop
|
|
9
14
|
BACK_OFF_RATIO = 1.2
|
|
10
15
|
BACK_OFF_MAX = 5
|
|
@@ -38,15 +43,39 @@ module Datadog
|
|
|
38
43
|
|
|
39
44
|
def stop_loop
|
|
40
45
|
mutex.synchronize do
|
|
41
|
-
|
|
42
|
-
|
|
46
|
+
# Do not call run_loop? from this method to see if the loop
|
|
47
|
+
# is running, because @run_loop is normally initialized by
|
|
48
|
+
# the background thread and if the stop is requested right
|
|
49
|
+
# after the worker starts, the background thread may be created
|
|
50
|
+
# (and scheduled) but hasn't run yet, thus skipping the
|
|
51
|
+
# write to @run_loop here would leave the thread running forever.
|
|
43
52
|
@run_loop = false
|
|
53
|
+
|
|
54
|
+
# It is possible that we don't need to signal shutdown if
|
|
55
|
+
# @run_loop was not initialized (i.e. we changed it from not
|
|
56
|
+
# defined to false above). But let's be safe and signal the
|
|
57
|
+
# shutdown anyway, I don't see what harm it can cause.
|
|
44
58
|
shutdown.signal
|
|
45
59
|
end
|
|
46
60
|
|
|
61
|
+
# Previously, this method would return false (and do nothing)
|
|
62
|
+
# if the worker was not running the loop. However, this was racy -
|
|
63
|
+
# see https://github.com/DataDog/ruby-guild/issues/279.
|
|
64
|
+
# stop_loop now always sets the state to "stop requested" and,
|
|
65
|
+
# correspondingly, always returns true.
|
|
66
|
+
#
|
|
67
|
+
# There is some test code that returns false when mocking this
|
|
68
|
+
# method - most likely this method should be treated as a void one
|
|
69
|
+
# and the caller should assume that the stop was always requested.
|
|
47
70
|
true
|
|
48
71
|
end
|
|
49
72
|
|
|
73
|
+
# TODO This overwrites Queue's +work_pending?+ method with an
|
|
74
|
+
# implementation that, to me, is at leat questionable semantically:
|
|
75
|
+
# the Queue's idea of pending work is if the buffer is not empty,
|
|
76
|
+
# but this module says that work is pending if the work processing
|
|
77
|
+
# loop is scheduled to run (in other words, as long as the background
|
|
78
|
+
# thread is running, there is always pending work).
|
|
50
79
|
def work_pending?
|
|
51
80
|
run_loop?
|
|
52
81
|
end
|
|
@@ -104,7 +133,19 @@ module Datadog
|
|
|
104
133
|
|
|
105
134
|
def perform_loop
|
|
106
135
|
mutex.synchronize do
|
|
107
|
-
@run_loop
|
|
136
|
+
unless defined?(@run_loop)
|
|
137
|
+
# This write must only happen if @run_loop is not defined
|
|
138
|
+
# (i.e., not initialized). In the case when the worker is
|
|
139
|
+
# asked to stop right after it is created, the thread may not
|
|
140
|
+
# have run yet by the time +stop_loop+ is invoked and
|
|
141
|
+
# we need to preserve the stop-requested state from
|
|
142
|
+
# +stop_loop+ to +perform_loop+.
|
|
143
|
+
#
|
|
144
|
+
# If the workers are refactored to use classes and inheritance
|
|
145
|
+
# and their state, such as @run_loop, is initialized in
|
|
146
|
+
# constructors, the write can be made unconditional.
|
|
147
|
+
@run_loop = true
|
|
148
|
+
end
|
|
108
149
|
|
|
109
150
|
shutdown.wait(mutex, loop_wait_time) if loop_wait_before_first_iteration?
|
|
110
151
|
end
|
|
@@ -5,6 +5,17 @@ module Datadog
|
|
|
5
5
|
module Workers
|
|
6
6
|
# Adds queue behavior to workers, with a buffer
|
|
7
7
|
# to which items can be queued then dequeued.
|
|
8
|
+
#
|
|
9
|
+
# This module is included in some but not all workers.
|
|
10
|
+
# Notably, Data Streams Processor uses a queue but implements it
|
|
11
|
+
# inline rather than using this module.
|
|
12
|
+
#
|
|
13
|
+
# The workers that do include Queue also include Polling, which
|
|
14
|
+
# in turn includes Async::Thread and IntervalLoop. This means
|
|
15
|
+
# we have e.g. +in_iteration?+ always available in any worker
|
|
16
|
+
# that includes Queue.
|
|
17
|
+
#
|
|
18
|
+
# @api private
|
|
8
19
|
module Queue
|
|
9
20
|
def self.included(base)
|
|
10
21
|
base.prepend(PrependedMethods)
|
|
@@ -13,11 +24,16 @@ module Datadog
|
|
|
13
24
|
# Methods that must be prepended
|
|
14
25
|
module PrependedMethods
|
|
15
26
|
def perform(*args)
|
|
16
|
-
|
|
27
|
+
if work_pending?
|
|
28
|
+
work = dequeue
|
|
29
|
+
super(*work)
|
|
30
|
+
end
|
|
17
31
|
end
|
|
18
32
|
end
|
|
19
33
|
|
|
20
34
|
def buffer
|
|
35
|
+
# Why is this an unsynchronized Array and not a Core::Buffer
|
|
36
|
+
# instance?
|
|
21
37
|
@buffer ||= []
|
|
22
38
|
end
|
|
23
39
|
|
|
@@ -34,10 +50,93 @@ module Datadog
|
|
|
34
50
|
!buffer.empty?
|
|
35
51
|
end
|
|
36
52
|
|
|
53
|
+
# Wait for the worker to finish handling all work that has already
|
|
54
|
+
# been submitted to it.
|
|
55
|
+
#
|
|
56
|
+
# If the worker is not enabled, returns nil.
|
|
57
|
+
# If the worker is enabled, returns whether, at the point of return,
|
|
58
|
+
# there was no pending or in progress work.
|
|
59
|
+
#
|
|
60
|
+
# Flushing can time out because there is a constant stream of work
|
|
61
|
+
# submitted at the same or higher rate than it is processed.
|
|
62
|
+
# Flushing can also fail if the worker thread is not running -
|
|
63
|
+
# this method will not flush from the calling thread.
|
|
64
|
+
def flush(timeout: nil)
|
|
65
|
+
# Default timeout is 5 seconds.
|
|
66
|
+
# Specific workers can override it to be more or less
|
|
67
|
+
timeout ||= 5
|
|
68
|
+
|
|
69
|
+
# Nothing needs to be done if the worker is not enabled.
|
|
70
|
+
return nil unless enabled?
|
|
71
|
+
|
|
72
|
+
unless running?
|
|
73
|
+
unless buffer.empty?
|
|
74
|
+
# If we are asked to flush but the worker is not running,
|
|
75
|
+
# do not flush from the caller thread. If the buffer is not
|
|
76
|
+
# empty, it will not be flushed. Log a warning to this effect.
|
|
77
|
+
#
|
|
78
|
+
# We are not guaranteed to have a logger as an instance method,
|
|
79
|
+
# reference the global for now - all other worker methods
|
|
80
|
+
# also reference the logger globally.
|
|
81
|
+
# TODO inject it into worker instances.
|
|
82
|
+
Datadog.logger.debug { "Asked to flush #{self} when the worker is not running" }
|
|
83
|
+
return false
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
started = Utils::Time.get_time
|
|
88
|
+
loop do
|
|
89
|
+
# The AppStarted event is triggered by the worker itself,
|
|
90
|
+
# from the worker thread. As such the main thread has no way
|
|
91
|
+
# to delay itself until that event is queued and we need some
|
|
92
|
+
# way to wait until that event is sent out to assert on it in
|
|
93
|
+
# the test suite. Check the run once flag which *should*
|
|
94
|
+
# indicate the event has been queued (at which point our queue
|
|
95
|
+
# depth check should wait until it's sent).
|
|
96
|
+
# This is still a hack because the flag can be overridden
|
|
97
|
+
# either way with or without the event being sent out.
|
|
98
|
+
# Note that if the AppStarted sending fails, this check
|
|
99
|
+
# will return false and flushing will be blocked until the
|
|
100
|
+
# 15 second timeout.
|
|
101
|
+
# Note that the first wait interval between telemetry event
|
|
102
|
+
# sending is 10 seconds, the timeout needs to be strictly
|
|
103
|
+
# greater than that.
|
|
104
|
+
return true if idle?
|
|
105
|
+
|
|
106
|
+
return false if Utils::Time.get_time - started > timeout
|
|
107
|
+
|
|
108
|
+
sleep 0.5
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
|
|
37
112
|
protected
|
|
38
113
|
|
|
39
114
|
attr_writer \
|
|
40
115
|
:buffer
|
|
116
|
+
|
|
117
|
+
# Returns whether this worker has no pending work and is not actively
|
|
118
|
+
# working.
|
|
119
|
+
#
|
|
120
|
+
# The reason why "actively working" is considered is that we use
|
|
121
|
+
# flushing to ensure all work is completed before asserting on the
|
|
122
|
+
# outcome in the tests - if work is happening in a background thread,
|
|
123
|
+
# it's too early to assert on its results.
|
|
124
|
+
def idle?
|
|
125
|
+
# We have a +work_pending?+ method in this class that semantically
|
|
126
|
+
# would be appropriate here instead of calling +buffer.empty?+.
|
|
127
|
+
# Unfortunately IntervalLoop replaces our implementation of
|
|
128
|
+
# +work_pending?+ with one that doesn't make sense at least for the
|
|
129
|
+
# Queue. And we can't change the order of module includes because
|
|
130
|
+
# they all override +perform+ and the correct behavior depends on
|
|
131
|
+
# placing IntervalLoop after Queue.
|
|
132
|
+
#
|
|
133
|
+
# The TraceWriter worker then defines +work_pending?+ to be the
|
|
134
|
+
# same as Queue implementation here... Essentially, it demands
|
|
135
|
+
# the behavior that perhaps should be applied to all workers.
|
|
136
|
+
#
|
|
137
|
+
# Until this mess is untangled, call +buffer.empty?+ here.
|
|
138
|
+
buffer.empty? && !in_iteration?
|
|
139
|
+
end
|
|
41
140
|
end
|
|
42
141
|
end
|
|
43
142
|
end
|
|
@@ -1,11 +1,8 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require_relative '../stats'
|
|
4
|
-
require_relative 'client'
|
|
5
|
-
require_relative '../../../core/transport/http/response'
|
|
6
4
|
require_relative '../../../core/transport/http/api/endpoint'
|
|
7
|
-
require_relative '../../../core/transport/http/
|
|
8
|
-
require_relative '../../../core/transport/http/api/instance'
|
|
5
|
+
require_relative '../../../core/transport/http/response'
|
|
9
6
|
|
|
10
7
|
module Datadog
|
|
11
8
|
module DataStreams
|
|
@@ -23,38 +20,6 @@ module Datadog
|
|
|
23
20
|
end
|
|
24
21
|
|
|
25
22
|
module API
|
|
26
|
-
# HTTP API Spec for DSM
|
|
27
|
-
class Spec < Core::Transport::HTTP::API::Spec
|
|
28
|
-
attr_accessor :stats
|
|
29
|
-
|
|
30
|
-
def send_stats(env, &block)
|
|
31
|
-
raise Core::Transport::HTTP::API::Spec::EndpointNotDefinedError.new('stats', self) if stats.nil?
|
|
32
|
-
|
|
33
|
-
stats.call(env, &block)
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
def encoder
|
|
37
|
-
# DSM handles encoding in the transport layer (MessagePack + gzip)
|
|
38
|
-
# so we don't need an encoder at the API level
|
|
39
|
-
nil
|
|
40
|
-
end
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
# HTTP API Instance for DSM
|
|
44
|
-
class Instance < Core::Transport::HTTP::API::Instance
|
|
45
|
-
def send_stats(env)
|
|
46
|
-
unless spec.is_a?(Stats::API::Spec)
|
|
47
|
-
raise Core::Transport::HTTP::API::Instance::EndpointNotSupportedError.new(
|
|
48
|
-
'stats', self
|
|
49
|
-
)
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
spec.send_stats(env) do |request_env|
|
|
53
|
-
call(request_env)
|
|
54
|
-
end
|
|
55
|
-
end
|
|
56
|
-
end
|
|
57
|
-
|
|
58
23
|
# Endpoint for submitting DSM stats data
|
|
59
24
|
class Endpoint < Core::Transport::HTTP::API::Endpoint
|
|
60
25
|
def initialize(path)
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require_relative '../../core/transport/http'
|
|
4
|
-
require_relative 'http/api'
|
|
5
|
-
require_relative 'http/client'
|
|
6
4
|
require_relative 'http/stats'
|
|
7
5
|
require_relative 'stats'
|
|
8
6
|
|
|
@@ -11,6 +9,10 @@ module Datadog
|
|
|
11
9
|
module Transport
|
|
12
10
|
# HTTP transport for Data Streams Monitoring
|
|
13
11
|
module HTTP
|
|
12
|
+
V01 = Stats::API::Endpoint.new(
|
|
13
|
+
'/v0.1/pipeline_stats'
|
|
14
|
+
)
|
|
15
|
+
|
|
14
16
|
module_function
|
|
15
17
|
|
|
16
18
|
# Builds a new Transport::HTTP::Client with default settings
|
|
@@ -19,7 +21,6 @@ module Datadog
|
|
|
19
21
|
logger:
|
|
20
22
|
)
|
|
21
23
|
Core::Transport::HTTP.build(
|
|
22
|
-
api_instance_class: Stats::API::Instance,
|
|
23
24
|
agent_settings: agent_settings,
|
|
24
25
|
logger: logger,
|
|
25
26
|
headers: {
|
|
@@ -27,9 +28,7 @@ module Datadog
|
|
|
27
28
|
'Content-Encoding' => 'gzip'
|
|
28
29
|
}
|
|
29
30
|
) do |transport|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
transport.api API::V01, apis[API::V01], default: true
|
|
31
|
+
transport.api 'v0.1', V01, default: true
|
|
33
32
|
|
|
34
33
|
# Call block to apply any customization, if provided
|
|
35
34
|
yield(transport) if block_given?
|
|
@@ -4,6 +4,7 @@ require 'msgpack'
|
|
|
4
4
|
require 'zlib'
|
|
5
5
|
require_relative '../../core/transport/parcel'
|
|
6
6
|
require_relative '../../core/transport/request'
|
|
7
|
+
require_relative '../../core/transport/transport'
|
|
7
8
|
|
|
8
9
|
module Datadog
|
|
9
10
|
module DataStreams
|
|
@@ -25,18 +26,7 @@ module Datadog
|
|
|
25
26
|
end
|
|
26
27
|
|
|
27
28
|
# Transport for Data Streams Monitoring stats
|
|
28
|
-
class Transport
|
|
29
|
-
attr_reader :client, :apis, :current_api_id, :logger
|
|
30
|
-
|
|
31
|
-
def initialize(apis, default_api, logger:)
|
|
32
|
-
@apis = apis
|
|
33
|
-
@logger = logger
|
|
34
|
-
@default_api = default_api
|
|
35
|
-
@current_api_id = default_api
|
|
36
|
-
|
|
37
|
-
@client = DataStreams::Transport::HTTP::Client.new(current_api, logger: @logger)
|
|
38
|
-
end
|
|
39
|
-
|
|
29
|
+
class Transport < Core::Transport::Transport
|
|
40
30
|
def send_stats(payload)
|
|
41
31
|
# MessagePack encode and gzip compress the payload
|
|
42
32
|
msgpack_data = MessagePack.pack(payload)
|
|
@@ -47,11 +37,7 @@ module Datadog
|
|
|
47
37
|
request = Request.new(parcel)
|
|
48
38
|
|
|
49
39
|
# Send to agent
|
|
50
|
-
client.
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
def current_api
|
|
54
|
-
apis[@current_api_id]
|
|
40
|
+
client.send_request(:stats, request)
|
|
55
41
|
end
|
|
56
42
|
end
|
|
57
43
|
end
|
data/lib/datadog/di/boot.rb
CHANGED
|
@@ -17,7 +17,8 @@ require_relative 'serializer'
|
|
|
17
17
|
require_relative 'transport/http'
|
|
18
18
|
require_relative 'utils'
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
# Steep: https://github.com/ruby/rbs/pull/2715
|
|
21
|
+
if %w[1 true yes].include?(Datadog::DATADOG_ENV['DD_DYNAMIC_INSTRUMENTATION_ENABLED']) # steep:ignore ArgumentTypeMismatch
|
|
21
22
|
|
|
22
23
|
# For initial release of Dynamic Instrumentation, activate code tracking
|
|
23
24
|
# only if DI is explicitly requested in the environment.
|
|
@@ -35,7 +36,8 @@ require_relative 'contrib'
|
|
|
35
36
|
|
|
36
37
|
Datadog::DI::Contrib.load_now_or_later
|
|
37
38
|
|
|
38
|
-
|
|
39
|
+
# Steep: https://github.com/ruby/rbs/pull/2715
|
|
40
|
+
if %w[1 true yes].include?(Datadog::DATADOG_ENV['DD_DYNAMIC_INSTRUMENTATION_ENABLED']) # steep:ignore ArgumentTypeMismatch
|
|
39
41
|
if Datadog::DATADOG_ENV['DD_DYNAMIC_INSTRUMENTATION_PROBE_FILE']
|
|
40
42
|
require_relative 'probe_file_loader'
|
|
41
43
|
Datadog::DI::ProbeFileLoader.load_now_or_later
|