datadog 2.22.0 → 2.24.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 +100 -1
- data/ext/LIBDATADOG_DEVELOPMENT.md +1 -58
- data/ext/datadog_profiling_native_extension/collectors_stack.c +21 -5
- data/ext/datadog_profiling_native_extension/crashtracking_runtime_stacks.c +239 -0
- data/ext/datadog_profiling_native_extension/datadog_ruby_common.h +1 -1
- data/ext/datadog_profiling_native_extension/extconf.rb +9 -4
- data/ext/datadog_profiling_native_extension/heap_recorder.c +1 -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/ext/libdatadog_api/datadog_ruby_common.h +1 -1
- data/ext/libdatadog_api/feature_flags.c +554 -0
- data/ext/libdatadog_api/feature_flags.h +5 -0
- data/ext/libdatadog_api/init.c +2 -0
- data/ext/libdatadog_api/library_config.c +12 -11
- data/ext/libdatadog_extconf_helpers.rb +1 -1
- data/lib/datadog/appsec/api_security/route_extractor.rb +23 -6
- data/lib/datadog/appsec/api_security/sampler.rb +7 -4
- data/lib/datadog/appsec/assets/blocked.html +8 -0
- data/lib/datadog/appsec/assets/blocked.json +1 -1
- data/lib/datadog/appsec/assets/blocked.text +3 -1
- data/lib/datadog/appsec/assets.rb +1 -1
- data/lib/datadog/appsec/context.rb +2 -1
- data/lib/datadog/appsec/remote.rb +5 -9
- data/lib/datadog/appsec/response.rb +18 -4
- data/lib/datadog/appsec/security_engine/result.rb +2 -1
- data/lib/datadog/core/configuration/components.rb +30 -3
- data/lib/datadog/core/configuration/config_helper.rb +2 -2
- 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 +28 -3
- data/lib/datadog/core/configuration/supported_configurations.rb +332 -302
- data/lib/datadog/core/ddsketch.rb +0 -2
- 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 +7 -0
- data/lib/datadog/core/environment/process.rb +87 -0
- data/lib/datadog/core/feature_flags.rb +61 -0
- data/lib/datadog/core/rate_limiter.rb +9 -1
- data/lib/datadog/core/remote/client/capabilities.rb +7 -0
- 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 +4 -25
- data/lib/datadog/core/remote/transport/http/config.rb +10 -50
- data/lib/datadog/core/remote/transport/http/negotiation.rb +14 -44
- data/lib/datadog/core/remote/transport/http.rb +15 -24
- data/lib/datadog/core/remote/transport/negotiation.rb +8 -33
- data/lib/datadog/core/remote/worker.rb +25 -37
- data/lib/datadog/core/tag_builder.rb +0 -4
- data/lib/datadog/core/tag_normalizer.rb +84 -0
- data/lib/datadog/core/telemetry/component.rb +59 -16
- data/lib/datadog/core/telemetry/event/app_started.rb +86 -49
- data/lib/datadog/core/telemetry/event/synth_app_client_configuration_change.rb +27 -4
- data/lib/datadog/core/telemetry/logger.rb +2 -2
- data/lib/datadog/core/telemetry/logging.rb +2 -8
- 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 +3 -34
- data/lib/datadog/core/telemetry/transport/http.rb +21 -16
- data/lib/datadog/core/telemetry/transport/telemetry.rb +3 -11
- 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 +80 -0
- data/lib/datadog/core/transport/http.rb +22 -19
- data/lib/datadog/core/transport/response.rb +9 -0
- data/lib/datadog/core/transport/transport.rb +90 -0
- data/lib/datadog/core/utils/array.rb +29 -0
- data/lib/datadog/{appsec/api_security → core/utils}/lru_cache.rb +10 -21
- data/lib/datadog/core/utils/network.rb +3 -1
- data/lib/datadog/core/utils/only_once_successful.rb +8 -2
- data/lib/datadog/core/utils/time.rb +1 -1
- data/lib/datadog/core/utils.rb +2 -0
- 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/configuration/settings.rb +49 -0
- data/lib/datadog/data_streams/configuration.rb +11 -0
- data/lib/datadog/data_streams/ext.rb +11 -0
- data/lib/datadog/data_streams/extensions.rb +16 -0
- data/lib/datadog/data_streams/pathway_context.rb +169 -0
- data/lib/datadog/data_streams/processor.rb +509 -0
- data/lib/datadog/data_streams/transport/http/stats.rb +52 -0
- data/lib/datadog/data_streams/transport/http.rb +40 -0
- data/lib/datadog/data_streams/transport/stats.rb +46 -0
- data/lib/datadog/data_streams.rb +100 -0
- data/lib/datadog/di/component.rb +0 -16
- data/lib/datadog/di/contrib/active_record.rb +31 -5
- data/lib/datadog/di/el/compiler.rb +8 -4
- data/lib/datadog/di/el/evaluator.rb +1 -1
- data/lib/datadog/di/error.rb +9 -0
- data/lib/datadog/di/instrumenter.rb +93 -34
- data/lib/datadog/di/probe.rb +20 -0
- data/lib/datadog/di/probe_builder.rb +2 -1
- data/lib/datadog/di/probe_manager.rb +47 -33
- data/lib/datadog/di/probe_notification_builder.rb +77 -25
- data/lib/datadog/di/proc_responder.rb +32 -0
- data/lib/datadog/di/remote.rb +89 -84
- data/lib/datadog/di/transport/diagnostics.rb +8 -36
- data/lib/datadog/di/transport/http/diagnostics.rb +1 -33
- data/lib/datadog/di/transport/http/input.rb +1 -33
- data/lib/datadog/di/transport/http.rb +32 -17
- data/lib/datadog/di/transport/input.rb +67 -34
- data/lib/datadog/di.rb +61 -5
- data/lib/datadog/open_feature/component.rb +60 -0
- data/lib/datadog/open_feature/configuration.rb +27 -0
- data/lib/datadog/open_feature/evaluation_engine.rb +70 -0
- data/lib/datadog/open_feature/exposures/batch_builder.rb +32 -0
- data/lib/datadog/open_feature/exposures/buffer.rb +43 -0
- data/lib/datadog/open_feature/exposures/deduplicator.rb +30 -0
- data/lib/datadog/open_feature/exposures/event.rb +60 -0
- data/lib/datadog/open_feature/exposures/reporter.rb +40 -0
- data/lib/datadog/open_feature/exposures/worker.rb +116 -0
- data/lib/datadog/open_feature/ext.rb +14 -0
- data/lib/datadog/open_feature/native_evaluator.rb +38 -0
- data/lib/datadog/open_feature/noop_evaluator.rb +26 -0
- data/lib/datadog/open_feature/provider.rb +141 -0
- data/lib/datadog/open_feature/remote.rb +67 -0
- data/lib/datadog/open_feature/resolution_details.rb +35 -0
- data/lib/datadog/open_feature/transport.rb +70 -0
- data/lib/datadog/open_feature.rb +19 -0
- data/lib/datadog/opentelemetry/api/baggage.rb +1 -1
- data/lib/datadog/opentelemetry/configuration/settings.rb +159 -0
- data/lib/datadog/opentelemetry/metrics.rb +117 -0
- data/lib/datadog/opentelemetry/sdk/configurator.rb +25 -1
- data/lib/datadog/opentelemetry/sdk/metrics_exporter.rb +35 -0
- data/lib/datadog/opentelemetry.rb +3 -0
- data/lib/datadog/profiling/collectors/code_provenance.rb +41 -7
- data/lib/datadog/profiling/collectors/cpu_and_wall_time_worker.rb +1 -1
- data/lib/datadog/profiling/collectors/idle_sampling_helper.rb +1 -1
- data/lib/datadog/profiling/collectors/info.rb +2 -1
- data/lib/datadog/profiling/component.rb +12 -11
- data/lib/datadog/profiling/http_transport.rb +4 -1
- data/lib/datadog/profiling/profiler.rb +4 -0
- data/lib/datadog/profiling/tag_builder.rb +36 -3
- data/lib/datadog/profiling.rb +1 -2
- data/lib/datadog/single_step_instrument.rb +1 -1
- data/lib/datadog/tracing/configuration/ext.rb +9 -0
- data/lib/datadog/tracing/configuration/settings.rb +74 -0
- data/lib/datadog/tracing/contrib/action_pack/action_controller/instrumentation.rb +4 -4
- data/lib/datadog/tracing/contrib/action_pack/utils.rb +1 -2
- data/lib/datadog/tracing/contrib/active_job/log_injection.rb +21 -7
- data/lib/datadog/tracing/contrib/active_job/patcher.rb +5 -1
- data/lib/datadog/tracing/contrib/aws/instrumentation.rb +4 -2
- data/lib/datadog/tracing/contrib/ethon/easy_patch.rb +4 -1
- data/lib/datadog/tracing/contrib/excon/configuration/settings.rb +11 -3
- data/lib/datadog/tracing/contrib/extensions.rb +10 -2
- data/lib/datadog/tracing/contrib/faraday/configuration/settings.rb +11 -7
- data/lib/datadog/tracing/contrib/grape/configuration/settings.rb +7 -3
- data/lib/datadog/tracing/contrib/graphql/unified_trace.rb +22 -17
- data/lib/datadog/tracing/contrib/http/configuration/settings.rb +11 -3
- data/lib/datadog/tracing/contrib/httpclient/configuration/settings.rb +11 -3
- data/lib/datadog/tracing/contrib/httprb/configuration/settings.rb +11 -3
- data/lib/datadog/tracing/contrib/kafka/instrumentation/consumer.rb +66 -0
- data/lib/datadog/tracing/contrib/kafka/instrumentation/producer.rb +66 -0
- data/lib/datadog/tracing/contrib/kafka/patcher.rb +14 -0
- data/lib/datadog/tracing/contrib/karafka/framework.rb +30 -0
- data/lib/datadog/tracing/contrib/karafka/monitor.rb +11 -0
- data/lib/datadog/tracing/contrib/karafka/patcher.rb +35 -4
- data/lib/datadog/tracing/contrib/rack/middlewares.rb +59 -27
- data/lib/datadog/tracing/contrib/rack/route_inference.rb +53 -0
- data/lib/datadog/tracing/contrib/rails/middlewares.rb +2 -2
- data/lib/datadog/tracing/contrib/rest_client/request_patch.rb +4 -1
- data/lib/datadog/tracing/contrib/roda/instrumentation.rb +3 -1
- data/lib/datadog/tracing/contrib/sinatra/tracer_middleware.rb +3 -1
- data/lib/datadog/tracing/contrib/status_range_matcher.rb +9 -1
- data/lib/datadog/tracing/contrib/utils/quantization/hash.rb +3 -1
- data/lib/datadog/tracing/contrib/waterdrop/configuration/settings.rb +27 -0
- data/lib/datadog/tracing/contrib/waterdrop/distributed/propagation.rb +48 -0
- data/lib/datadog/tracing/contrib/waterdrop/ext.rb +17 -0
- data/lib/datadog/tracing/contrib/waterdrop/integration.rb +43 -0
- data/lib/datadog/tracing/contrib/waterdrop/middleware.rb +46 -0
- data/lib/datadog/tracing/contrib/waterdrop/patcher.rb +49 -0
- data/lib/datadog/tracing/contrib/waterdrop/producer.rb +50 -0
- data/lib/datadog/tracing/contrib/waterdrop.rb +37 -0
- data/lib/datadog/tracing/contrib.rb +1 -0
- data/lib/datadog/tracing/diagnostics/environment_logger.rb +1 -1
- data/lib/datadog/tracing/metadata/ext.rb +1 -1
- data/lib/datadog/tracing/remote.rb +1 -9
- data/lib/datadog/tracing/span_event.rb +2 -2
- data/lib/datadog/tracing/span_operation.rb +9 -4
- data/lib/datadog/tracing/trace_operation.rb +44 -6
- data/lib/datadog/tracing/tracer.rb +42 -16
- data/lib/datadog/tracing/transport/http/client.rb +12 -26
- 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/trace_formatter.rb +11 -0
- data/lib/datadog/tracing/transport/traces.rb +9 -71
- 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 +2 -0
- metadata +78 -21
- data/lib/datadog/core/remote/transport/http/api.rb +0 -53
- data/lib/datadog/core/remote/transport/http/client.rb +0 -49
- data/lib/datadog/core/telemetry/transport/http/api.rb +0 -43
- data/lib/datadog/core/telemetry/transport/http/client.rb +0 -49
- data/lib/datadog/core/transport/http/api/spec.rb +0 -36
- data/lib/datadog/di/transport/http/api.rb +0 -42
- data/lib/datadog/di/transport/http/client.rb +0 -47
- data/lib/datadog/opentelemetry/api/baggage.rbs +0 -26
- data/lib/datadog/tracing/transport/http/api.rb +0 -44
|
@@ -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
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Datadog
|
|
4
|
+
module Core
|
|
5
|
+
module Utils
|
|
6
|
+
# Common array-related utility functions.
|
|
7
|
+
module Array
|
|
8
|
+
def self.filter_map(array, &block)
|
|
9
|
+
if array.respond_to?(:filter_map)
|
|
10
|
+
# DEV Supported since Ruby 2.7, saves an intermediate object creation
|
|
11
|
+
array.filter_map(&block)
|
|
12
|
+
elsif array.is_a?(Enumerator::Lazy)
|
|
13
|
+
# You would think that .compact would work here, but it does not:
|
|
14
|
+
# the result of .map could be an Enumerator::Lazy instance which
|
|
15
|
+
# does not implement #compact on Ruby 2.5/2.6.
|
|
16
|
+
array.map(&block).reject do |item|
|
|
17
|
+
item.nil?
|
|
18
|
+
end
|
|
19
|
+
else
|
|
20
|
+
array.each_with_object([]) do |item, memo|
|
|
21
|
+
new_item = block.call(item)
|
|
22
|
+
memo.push(new_item) unless new_item.nil?
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -3,13 +3,13 @@
|
|
|
3
3
|
require 'forwardable'
|
|
4
4
|
|
|
5
5
|
module Datadog
|
|
6
|
-
module
|
|
7
|
-
module
|
|
6
|
+
module Core
|
|
7
|
+
module Utils
|
|
8
8
|
# An LRU (Least Recently Used) cache implementation that relies on the
|
|
9
9
|
# Ruby 1.9+ `Hash` implementation that guarantees insertion order.
|
|
10
10
|
#
|
|
11
11
|
# WARNING: This implementation is NOT thread-safe and should be used
|
|
12
|
-
# in a single-threaded context.
|
|
12
|
+
# in a single-threaded context or guarded by Mutex.
|
|
13
13
|
class LRUCache
|
|
14
14
|
extend Forwardable
|
|
15
15
|
|
|
@@ -30,25 +30,14 @@ module Datadog
|
|
|
30
30
|
end
|
|
31
31
|
end
|
|
32
32
|
|
|
33
|
-
def
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
# NOTE: If the key exists, it's moved to the end of the list and
|
|
42
|
-
# if does not, the given block will be executed and the result
|
|
43
|
-
# will be stored (which will add it to the end of the list).
|
|
44
|
-
def fetch_or_store(key)
|
|
45
|
-
if (entry = @store.delete(key))
|
|
46
|
-
return @store[key] = entry
|
|
33
|
+
def []=(key, value)
|
|
34
|
+
if @store.delete(key)
|
|
35
|
+
@store[key] = value
|
|
36
|
+
else
|
|
37
|
+
# NOTE: evict the oldest entry if store reached the maximum allowed size
|
|
38
|
+
@store.shift if @store.size >= @max_size
|
|
39
|
+
@store[key] = value
|
|
47
40
|
end
|
|
48
|
-
|
|
49
|
-
# NOTE: evict the oldest entry if store reached the maximum allowed size
|
|
50
|
-
@store.shift if @store.size >= @max_size
|
|
51
|
-
@store[key] = yield
|
|
52
41
|
end
|
|
53
42
|
end
|
|
54
43
|
end
|
|
@@ -21,6 +21,8 @@ module Datadog
|
|
|
21
21
|
cf-connecting-ipv6
|
|
22
22
|
].freeze
|
|
23
23
|
|
|
24
|
+
CGNAT_IP_RANGE = IPAddr.new('100.64.0.0/10')
|
|
25
|
+
|
|
24
26
|
class << self
|
|
25
27
|
# Returns a client IP associated with the request if it was
|
|
26
28
|
# retrieved successfully.
|
|
@@ -131,7 +133,7 @@ module Datadog
|
|
|
131
133
|
end
|
|
132
134
|
|
|
133
135
|
def global_ip?(parsed_ip)
|
|
134
|
-
parsed_ip && !parsed_ip.private? && !parsed_ip.loopback? && !parsed_ip.link_local?
|
|
136
|
+
parsed_ip && !parsed_ip.private? && !parsed_ip.loopback? && !parsed_ip.link_local? && !CGNAT_IP_RANGE.include?(parsed_ip)
|
|
135
137
|
end
|
|
136
138
|
end
|
|
137
139
|
end
|
|
@@ -29,7 +29,11 @@ module Datadog
|
|
|
29
29
|
# In https://github.com/DataDog/dd-trace-rb/pull/1398#issuecomment-797378810 we have a discussion of alternatives,
|
|
30
30
|
# including an alternative implementation that is Ractor-safe once spent.
|
|
31
31
|
class OnlyOnceSuccessful < OnlyOnce
|
|
32
|
-
def initialize(limit =
|
|
32
|
+
def initialize(limit = nil)
|
|
33
|
+
if limit && limit <= 0
|
|
34
|
+
raise ArgumentError, "Limit must be a positive integer if provided: #{limit}"
|
|
35
|
+
end
|
|
36
|
+
|
|
33
37
|
super()
|
|
34
38
|
|
|
35
39
|
@limit = limit
|
|
@@ -63,7 +67,9 @@ module Datadog
|
|
|
63
67
|
|
|
64
68
|
private
|
|
65
69
|
|
|
70
|
+
# Use this method only after checking that limit is not nil.
|
|
66
71
|
def check_limit!
|
|
72
|
+
# @type ivar @limit: Integer
|
|
67
73
|
if @retries >= @limit
|
|
68
74
|
@failed = true
|
|
69
75
|
@ran_once = true
|
|
@@ -71,7 +77,7 @@ module Datadog
|
|
|
71
77
|
end
|
|
72
78
|
|
|
73
79
|
def limited?
|
|
74
|
-
!@limit.nil?
|
|
80
|
+
!@limit.nil?
|
|
75
81
|
end
|
|
76
82
|
|
|
77
83
|
def reset_ran_once_state_for_tests
|
|
@@ -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
|
data/lib/datadog/core/utils.rb
CHANGED
|
@@ -38,6 +38,8 @@ module Datadog
|
|
|
38
38
|
|
|
39
39
|
# Ensure `str` is a valid UTF-8, ready to be
|
|
40
40
|
# sent through the tracer transport.
|
|
41
|
+
# DEV-3.0: This method should unconditionally handle invalid byte sequences
|
|
42
|
+
# DEV-3.0: and return a safe string to display.
|
|
41
43
|
#
|
|
42
44
|
# @param [String,#to_s] str object to be converted to a UTF-8 string
|
|
43
45
|
# @param [Boolean] binary whether to expect binary data in the `str` parameter
|
|
@@ -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
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative '../../core/environment/variable_helpers'
|
|
4
|
+
require_relative '../ext'
|
|
5
|
+
|
|
6
|
+
module Datadog
|
|
7
|
+
module DataStreams
|
|
8
|
+
module Configuration
|
|
9
|
+
# Configuration settings for Data Streams Monitoring.
|
|
10
|
+
module Settings
|
|
11
|
+
def self.extended(base)
|
|
12
|
+
base = base.singleton_class unless base.is_a?(Class)
|
|
13
|
+
add_settings!(base)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def self.add_settings!(base)
|
|
17
|
+
base.class_eval do
|
|
18
|
+
# Data Streams Monitoring configuration
|
|
19
|
+
# @public_api
|
|
20
|
+
settings :data_streams do
|
|
21
|
+
# Whether Data Streams Monitoring is enabled. When enabled, the library will
|
|
22
|
+
# collect and report data lineage information for messaging systems.
|
|
23
|
+
#
|
|
24
|
+
# @default `DD_DATA_STREAMS_ENABLED` environment variable, otherwise `false`.
|
|
25
|
+
# @return [Boolean]
|
|
26
|
+
option :enabled do |o|
|
|
27
|
+
o.type :bool
|
|
28
|
+
o.env Ext::ENV_ENABLED
|
|
29
|
+
o.default false
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# The interval (in seconds) at which Data Streams Monitoring stats are flushed.
|
|
33
|
+
#
|
|
34
|
+
# @default 10.0
|
|
35
|
+
# @env '_DD_TRACE_STATS_WRITER_INTERVAL'
|
|
36
|
+
# @return [Float]
|
|
37
|
+
# @!visibility private
|
|
38
|
+
option :interval do |o|
|
|
39
|
+
o.type :float
|
|
40
|
+
o.env '_DD_TRACE_STATS_WRITER_INTERVAL'
|
|
41
|
+
o.default 10.0
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'configuration'
|
|
4
|
+
require_relative '../core/configuration'
|
|
5
|
+
|
|
6
|
+
module Datadog
|
|
7
|
+
module DataStreams
|
|
8
|
+
# Extends Datadog with Data Streams Monitoring features
|
|
9
|
+
module Extensions
|
|
10
|
+
# Inject Data Streams settings into global configuration.
|
|
11
|
+
def self.activate!
|
|
12
|
+
Core::Configuration::Settings.extend(Configuration::Settings)
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|