datadog 2.15.0 → 2.17.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 +74 -2
- data/ext/datadog_profiling_native_extension/datadog_ruby_common.c +1 -4
- data/ext/datadog_profiling_native_extension/datadog_ruby_common.h +7 -0
- data/ext/datadog_profiling_native_extension/encoded_profile.c +22 -12
- data/ext/datadog_profiling_native_extension/encoded_profile.h +1 -0
- data/ext/datadog_profiling_native_extension/extconf.rb +3 -0
- data/ext/datadog_profiling_native_extension/heap_recorder.c +8 -1
- data/ext/datadog_profiling_native_extension/http_transport.c +45 -72
- data/ext/datadog_profiling_native_extension/stack_recorder.c +4 -5
- data/ext/libdatadog_api/crashtracker.c +11 -12
- data/ext/libdatadog_api/crashtracker.h +5 -0
- data/ext/libdatadog_api/datadog_ruby_common.c +1 -4
- data/ext/libdatadog_api/datadog_ruby_common.h +7 -0
- data/ext/libdatadog_api/init.c +15 -0
- data/ext/libdatadog_api/library_config.c +122 -0
- data/ext/libdatadog_api/library_config.h +19 -0
- data/ext/libdatadog_api/macos_development.md +3 -3
- data/ext/libdatadog_api/process_discovery.c +117 -0
- data/ext/libdatadog_api/process_discovery.h +5 -0
- data/ext/libdatadog_extconf_helpers.rb +1 -1
- data/lib/datadog/appsec/actions_handler.rb +3 -2
- data/lib/datadog/appsec/api_security/lru_cache.rb +49 -0
- data/lib/datadog/appsec/api_security.rb +9 -0
- data/lib/datadog/appsec/assets/waf_rules/recommended.json +1344 -0
- data/lib/datadog/appsec/assets/waf_rules/strict.json +1344 -0
- data/lib/datadog/appsec/autoload.rb +1 -1
- data/lib/datadog/appsec/component.rb +11 -4
- data/lib/datadog/appsec/configuration/settings.rb +31 -18
- data/lib/datadog/appsec/context.rb +1 -1
- data/lib/datadog/appsec/contrib/active_record/instrumentation.rb +10 -12
- data/lib/datadog/appsec/contrib/active_record/integration.rb +1 -1
- data/lib/datadog/appsec/contrib/active_record/patcher.rb +22 -22
- data/lib/datadog/appsec/contrib/devise/data_extractor.rb +2 -3
- data/lib/datadog/appsec/contrib/devise/ext.rb +1 -0
- data/lib/datadog/appsec/contrib/devise/integration.rb +1 -1
- data/lib/datadog/appsec/contrib/devise/patcher.rb +3 -5
- data/lib/datadog/appsec/contrib/devise/tracking_middleware.rb +17 -4
- data/lib/datadog/appsec/contrib/excon/integration.rb +1 -1
- data/lib/datadog/appsec/contrib/excon/ssrf_detection_middleware.rb +9 -10
- data/lib/datadog/appsec/contrib/faraday/integration.rb +1 -1
- data/lib/datadog/appsec/contrib/faraday/ssrf_detection_middleware.rb +8 -9
- data/lib/datadog/appsec/contrib/graphql/gateway/watcher.rb +8 -9
- data/lib/datadog/appsec/contrib/graphql/integration.rb +1 -1
- data/lib/datadog/appsec/contrib/rack/gateway/watcher.rb +22 -32
- data/lib/datadog/appsec/contrib/rack/integration.rb +1 -1
- data/lib/datadog/appsec/contrib/rack/request_middleware.rb +16 -16
- data/lib/datadog/appsec/contrib/rails/gateway/watcher.rb +11 -13
- data/lib/datadog/appsec/contrib/rails/integration.rb +1 -1
- data/lib/datadog/appsec/contrib/rails/patcher.rb +21 -21
- data/lib/datadog/appsec/contrib/rest_client/integration.rb +1 -1
- data/lib/datadog/appsec/contrib/rest_client/request_ssrf_detection_patch.rb +10 -11
- data/lib/datadog/appsec/contrib/sinatra/gateway/watcher.rb +17 -23
- data/lib/datadog/appsec/contrib/sinatra/integration.rb +1 -1
- data/lib/datadog/appsec/event.rb +85 -95
- data/lib/datadog/appsec/instrumentation/gateway/argument.rb +5 -2
- data/lib/datadog/appsec/metrics/telemetry.rb +1 -1
- data/lib/datadog/appsec/monitor/gateway/watcher.rb +42 -12
- data/lib/datadog/appsec/processor/rule_loader.rb +26 -28
- data/lib/datadog/appsec/processor/rule_merger.rb +5 -5
- data/lib/datadog/appsec/processor.rb +1 -1
- data/lib/datadog/appsec/remote.rb +14 -13
- data/lib/datadog/appsec/response.rb +6 -6
- data/lib/datadog/appsec/security_engine/runner.rb +1 -1
- data/lib/datadog/appsec/security_event.rb +39 -0
- data/lib/datadog/appsec.rb +1 -1
- data/lib/datadog/core/buffer/random.rb +18 -2
- data/lib/datadog/core/configuration/agent_settings_resolver.rb +5 -5
- data/lib/datadog/core/configuration/agentless_settings_resolver.rb +176 -0
- data/lib/datadog/core/configuration/components.rb +48 -30
- data/lib/datadog/core/configuration/components_state.rb +23 -0
- data/lib/datadog/core/configuration/option.rb +79 -43
- data/lib/datadog/core/configuration/option_definition.rb +4 -4
- data/lib/datadog/core/configuration/options.rb +1 -1
- data/lib/datadog/core/configuration/settings.rb +20 -10
- data/lib/datadog/core/configuration/stable_config.rb +23 -0
- data/lib/datadog/core/configuration.rb +40 -16
- data/lib/datadog/core/crashtracking/component.rb +3 -10
- data/lib/datadog/core/encoding.rb +1 -1
- data/lib/datadog/core/environment/cgroup.rb +10 -12
- data/lib/datadog/core/environment/container.rb +38 -40
- data/lib/datadog/core/environment/ext.rb +6 -6
- data/lib/datadog/core/environment/git.rb +1 -0
- data/lib/datadog/core/environment/identity.rb +3 -3
- data/lib/datadog/core/environment/platform.rb +3 -3
- data/lib/datadog/core/environment/variable_helpers.rb +1 -1
- data/lib/datadog/core/error.rb +11 -9
- data/lib/datadog/core/logger.rb +2 -2
- data/lib/datadog/core/metrics/client.rb +20 -21
- data/lib/datadog/core/metrics/logging.rb +5 -5
- data/lib/datadog/core/process_discovery.rb +32 -0
- data/lib/datadog/core/rate_limiter.rb +4 -2
- data/lib/datadog/core/remote/client.rb +39 -31
- data/lib/datadog/core/remote/component.rb +3 -3
- data/lib/datadog/core/remote/configuration/digest.rb +7 -7
- data/lib/datadog/core/remote/configuration/path.rb +1 -1
- data/lib/datadog/core/remote/transport/http/client.rb +1 -1
- data/lib/datadog/core/remote/transport/http/config.rb +21 -5
- data/lib/datadog/core/remote/transport/http/negotiation.rb +1 -1
- data/lib/datadog/core/runtime/metrics.rb +4 -4
- data/lib/datadog/core/telemetry/component.rb +78 -53
- data/lib/datadog/core/telemetry/emitter.rb +23 -11
- data/lib/datadog/core/telemetry/event/app_client_configuration_change.rb +65 -0
- data/lib/datadog/core/telemetry/event/app_closing.rb +18 -0
- data/lib/datadog/core/telemetry/event/app_dependencies_loaded.rb +33 -0
- data/lib/datadog/core/telemetry/event/app_heartbeat.rb +18 -0
- data/lib/datadog/core/telemetry/event/app_integrations_change.rb +58 -0
- data/lib/datadog/core/telemetry/event/app_started.rb +179 -0
- data/lib/datadog/core/telemetry/event/base.rb +40 -0
- data/lib/datadog/core/telemetry/event/distributions.rb +18 -0
- data/lib/datadog/core/telemetry/event/generate_metrics.rb +43 -0
- data/lib/datadog/core/telemetry/event/log.rb +76 -0
- data/lib/datadog/core/telemetry/event/message_batch.rb +42 -0
- data/lib/datadog/core/telemetry/event/synth_app_client_configuration_change.rb +43 -0
- data/lib/datadog/core/telemetry/event.rb +17 -472
- data/lib/datadog/core/telemetry/http/adapters/net.rb +12 -97
- data/lib/datadog/core/telemetry/logger.rb +1 -1
- data/lib/datadog/core/telemetry/metric.rb +3 -3
- data/lib/datadog/core/telemetry/request.rb +3 -3
- data/lib/datadog/core/telemetry/transport/http/api.rb +43 -0
- data/lib/datadog/core/telemetry/transport/http/client.rb +49 -0
- data/lib/datadog/core/telemetry/transport/http/telemetry.rb +92 -0
- data/lib/datadog/core/telemetry/transport/http.rb +63 -0
- data/lib/datadog/core/telemetry/transport/telemetry.rb +51 -0
- data/lib/datadog/core/telemetry/worker.rb +90 -24
- data/lib/datadog/core/transport/http/adapters/test.rb +2 -1
- data/lib/datadog/core/transport/http/builder.rb +13 -13
- data/lib/datadog/core/utils/at_fork_monkey_patch.rb +6 -6
- data/lib/datadog/core/utils/duration.rb +32 -32
- data/lib/datadog/core/utils/forking.rb +2 -2
- data/lib/datadog/core/utils/network.rb +6 -6
- data/lib/datadog/core/utils/only_once_successful.rb +16 -5
- data/lib/datadog/core/utils/time.rb +20 -0
- data/lib/datadog/core/utils/truncation.rb +21 -0
- data/lib/datadog/core/vendor/multipart-post/multipart/post/composite_read_io.rb +1 -1
- data/lib/datadog/core/vendor/multipart-post/multipart/post/multipartable.rb +8 -8
- data/lib/datadog/core/vendor/multipart-post/multipart/post/parts.rb +7 -7
- data/lib/datadog/core/worker.rb +1 -1
- data/lib/datadog/core/workers/async.rb +29 -12
- data/lib/datadog/core/workers/interval_loop.rb +12 -1
- data/lib/datadog/core/workers/runtime_metrics.rb +2 -2
- data/lib/datadog/core.rb +8 -0
- data/lib/datadog/di/boot.rb +34 -0
- data/lib/datadog/di/remote.rb +2 -0
- data/lib/datadog/di.rb +5 -32
- data/lib/datadog/error_tracking/collector.rb +87 -0
- data/lib/datadog/error_tracking/component.rb +167 -0
- data/lib/datadog/error_tracking/configuration/settings.rb +63 -0
- data/lib/datadog/error_tracking/configuration.rb +11 -0
- data/lib/datadog/error_tracking/ext.rb +18 -0
- data/lib/datadog/error_tracking/extensions.rb +16 -0
- data/lib/datadog/error_tracking/filters.rb +77 -0
- data/lib/datadog/error_tracking.rb +18 -0
- data/lib/datadog/kit/identity.rb +1 -1
- data/lib/datadog/profiling/collectors/code_provenance.rb +1 -1
- data/lib/datadog/profiling/exporter.rb +1 -1
- data/lib/datadog/profiling/ext.rb +0 -1
- data/lib/datadog/profiling/flush.rb +1 -1
- data/lib/datadog/profiling/http_transport.rb +1 -6
- data/lib/datadog/profiling/scheduler.rb +8 -1
- data/lib/datadog/profiling/tag_builder.rb +1 -5
- data/lib/datadog/tracing/analytics.rb +1 -1
- data/lib/datadog/tracing/contrib/active_support/cache/events/cache.rb +4 -1
- data/lib/datadog/tracing/contrib/active_support/cache/instrumentation.rb +33 -0
- data/lib/datadog/tracing/contrib/active_support/cache/patcher.rb +4 -0
- data/lib/datadog/tracing/contrib/active_support/cache/redis.rb +2 -4
- data/lib/datadog/tracing/contrib/aws/instrumentation.rb +10 -0
- data/lib/datadog/tracing/contrib/aws/parsed_context.rb +5 -1
- data/lib/datadog/tracing/contrib/http/instrumentation.rb +1 -5
- data/lib/datadog/tracing/contrib/httpclient/instrumentation.rb +1 -5
- data/lib/datadog/tracing/contrib/httprb/instrumentation.rb +1 -5
- data/lib/datadog/tracing/contrib/karafka/distributed/propagation.rb +2 -0
- data/lib/datadog/tracing/contrib/karafka/monitor.rb +1 -1
- data/lib/datadog/tracing/contrib/mongodb/configuration/settings.rb +8 -0
- data/lib/datadog/tracing/contrib/mongodb/ext.rb +1 -0
- data/lib/datadog/tracing/contrib/mongodb/subscribers.rb +18 -1
- data/lib/datadog/tracing/contrib/patcher.rb +5 -2
- data/lib/datadog/tracing/contrib/support.rb +28 -0
- data/lib/datadog/tracing/distributed/b3_multi.rb +1 -1
- data/lib/datadog/tracing/distributed/b3_single.rb +1 -1
- data/lib/datadog/tracing/distributed/datadog.rb +2 -2
- data/lib/datadog/tracing/metadata/errors.rb +4 -4
- data/lib/datadog/tracing/sampling/rate_sampler.rb +2 -1
- data/lib/datadog/tracing/span_operation.rb +38 -14
- data/lib/datadog/tracing/trace_operation.rb +15 -7
- data/lib/datadog/tracing/tracer.rb +7 -3
- data/lib/datadog/tracing/utils.rb +1 -1
- data/lib/datadog/version.rb +1 -1
- data/lib/datadog.rb +2 -3
- metadata +53 -10
- data/lib/datadog/core/telemetry/http/env.rb +0 -20
- data/lib/datadog/core/telemetry/http/ext.rb +0 -28
- data/lib/datadog/core/telemetry/http/response.rb +0 -70
- data/lib/datadog/core/telemetry/http/transport.rb +0 -90
@@ -0,0 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../../../encoding'
|
4
|
+
require_relative '../../../transport/http/api/map'
|
5
|
+
require_relative '../../../transport/http/api/instance'
|
6
|
+
require_relative '../../../transport/http/api/spec'
|
7
|
+
require_relative 'telemetry'
|
8
|
+
|
9
|
+
module Datadog
|
10
|
+
module Core
|
11
|
+
module Telemetry
|
12
|
+
module Transport
|
13
|
+
module HTTP
|
14
|
+
# Namespace for API components
|
15
|
+
module API
|
16
|
+
# Default API versions
|
17
|
+
AGENT_TELEMETRY = 'agent_telemetry'
|
18
|
+
AGENTLESS_TELEMETRY = 'agentless_telemetry'
|
19
|
+
|
20
|
+
module_function
|
21
|
+
|
22
|
+
def defaults
|
23
|
+
Datadog::Core::Transport::HTTP::API::Map[
|
24
|
+
AGENT_TELEMETRY => Telemetry::API::Spec.new do |s|
|
25
|
+
s.telemetry = Telemetry::API::Endpoint.new(
|
26
|
+
'/telemetry/proxy/api/v2/apmtelemetry',
|
27
|
+
Core::Encoding::JSONEncoder,
|
28
|
+
)
|
29
|
+
end,
|
30
|
+
AGENTLESS_TELEMETRY => Telemetry::API::Spec.new do |s|
|
31
|
+
s.telemetry = Telemetry::API::Endpoint.new(
|
32
|
+
'/api/v2/apmtelemetry',
|
33
|
+
Core::Encoding::JSONEncoder,
|
34
|
+
)
|
35
|
+
end,
|
36
|
+
]
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../../../transport/http/env'
|
4
|
+
require_relative '../../../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 Core
|
13
|
+
module Telemetry
|
14
|
+
module Transport
|
15
|
+
module HTTP
|
16
|
+
# Routes, encodes, and sends DI data to the trace agent via HTTP.
|
17
|
+
class Client
|
18
|
+
attr_reader :api, :logger
|
19
|
+
|
20
|
+
def initialize(api, logger:)
|
21
|
+
@api = api
|
22
|
+
@logger = logger
|
23
|
+
end
|
24
|
+
|
25
|
+
def send_request(request, &block)
|
26
|
+
# Build request into env
|
27
|
+
env = build_env(request)
|
28
|
+
|
29
|
+
# Get responses from API
|
30
|
+
yield(api, env)
|
31
|
+
rescue => e
|
32
|
+
message =
|
33
|
+
"Internal error during #{self.class.name} request. Cause: #{e.class.name} #{e.message} " \
|
34
|
+
"Location: #{Array(e.backtrace).first}"
|
35
|
+
|
36
|
+
logger.debug(message)
|
37
|
+
|
38
|
+
Datadog::Core::Transport::InternalErrorResponse.new(e)
|
39
|
+
end
|
40
|
+
|
41
|
+
def build_env(request)
|
42
|
+
Datadog::Core::Transport::HTTP::Env.new(request)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../../../transport/http/api/endpoint'
|
4
|
+
require_relative '../../../transport/http/api/instance'
|
5
|
+
require_relative '../../../transport/http/api/spec'
|
6
|
+
require_relative '../../../transport/request'
|
7
|
+
require_relative 'client'
|
8
|
+
|
9
|
+
module Datadog
|
10
|
+
module Core
|
11
|
+
module Telemetry
|
12
|
+
module Transport
|
13
|
+
module HTTP
|
14
|
+
module Telemetry
|
15
|
+
module Client
|
16
|
+
def send_telemetry_payload(request)
|
17
|
+
send_request(request) do |api, env| # steep:ignore
|
18
|
+
api.send_telemetry(env)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
module API
|
24
|
+
class Instance < Core::Transport::HTTP::API::Instance
|
25
|
+
def send_telemetry(env)
|
26
|
+
raise Core::Transport::HTTP::API::Instance::EndpointNotSupportedError.new('telemetry', self) unless spec.is_a?(Telemetry::API::Spec)
|
27
|
+
|
28
|
+
spec.send_telemetry(env) do |request_env|
|
29
|
+
call(request_env)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
class Spec < Core::Transport::HTTP::API::Spec
|
35
|
+
attr_accessor :telemetry
|
36
|
+
|
37
|
+
def send_telemetry(env, &block)
|
38
|
+
raise Core::Transport::HTTP::API::Spec::EndpointNotDefinedError.new('telemetry', self) if telemetry.nil?
|
39
|
+
|
40
|
+
telemetry.call(env, &block)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
class Endpoint < Datadog::Core::Transport::HTTP::API::Endpoint
|
45
|
+
HEADER_CONTENT_TYPE = 'Content-Type'
|
46
|
+
|
47
|
+
attr_reader \
|
48
|
+
:encoder
|
49
|
+
|
50
|
+
def initialize(path, encoder)
|
51
|
+
super(:post, path)
|
52
|
+
@encoder = encoder
|
53
|
+
end
|
54
|
+
|
55
|
+
def call(env, &block)
|
56
|
+
# Encode body & type
|
57
|
+
env.headers[HEADER_CONTENT_TYPE] = encoder.content_type
|
58
|
+
env.headers.update(headers(
|
59
|
+
request_type: env.request.request_type,
|
60
|
+
api_key: env.request.api_key,
|
61
|
+
))
|
62
|
+
env.body = env.request.parcel.data
|
63
|
+
|
64
|
+
super
|
65
|
+
end
|
66
|
+
|
67
|
+
def headers(request_type:, api_key:, api_version: 'v2')
|
68
|
+
{
|
69
|
+
Core::Transport::Ext::HTTP::HEADER_DD_INTERNAL_UNTRACED_REQUEST => '1',
|
70
|
+
# Provided by encoder
|
71
|
+
# 'Content-Type' => 'application/json',
|
72
|
+
'DD-Telemetry-API-Version' => api_version,
|
73
|
+
'DD-Telemetry-Request-Type' => request_type,
|
74
|
+
'DD-Client-Library-Language' => Core::Environment::Ext::LANG,
|
75
|
+
'DD-Client-Library-Version' => Core::Environment::Identity.gem_datadog_version_semver2,
|
76
|
+
|
77
|
+
# Enable debug mode for telemetry
|
78
|
+
# 'DD-Telemetry-Debug-Enabled' => 'true',
|
79
|
+
}.tap do |result|
|
80
|
+
result['DD-API-KEY'] = api_key unless api_key.nil?
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
HTTP::Client.include(Telemetry::Client)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'telemetry'
|
4
|
+
require_relative 'http/api'
|
5
|
+
require_relative '../../transport/http'
|
6
|
+
|
7
|
+
module Datadog
|
8
|
+
module Core
|
9
|
+
module Telemetry
|
10
|
+
module Transport
|
11
|
+
# Namespace for HTTP transport components
|
12
|
+
module HTTP
|
13
|
+
module_function
|
14
|
+
|
15
|
+
# Builds a new Transport::HTTP::Client with default settings
|
16
|
+
# Pass a block to override any settings.
|
17
|
+
def agentless_telemetry(
|
18
|
+
agent_settings:,
|
19
|
+
logger:,
|
20
|
+
api_key: nil,
|
21
|
+
api_version: nil,
|
22
|
+
headers: nil
|
23
|
+
)
|
24
|
+
Core::Transport::HTTP.build(api_instance_class: Telemetry::API::Instance,
|
25
|
+
logger: logger,
|
26
|
+
agent_settings: agent_settings,
|
27
|
+
api_version: api_version,
|
28
|
+
headers: headers) do |transport|
|
29
|
+
apis = API.defaults
|
30
|
+
|
31
|
+
transport.api API::AGENTLESS_TELEMETRY, apis[API::AGENTLESS_TELEMETRY]
|
32
|
+
|
33
|
+
# Call block to apply any customization, if provided
|
34
|
+
yield(transport) if block_given?
|
35
|
+
end.to_transport(Core::Telemetry::Transport::Telemetry::Transport).tap do |transport|
|
36
|
+
transport.api_key = api_key
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# Builds a new Transport::HTTP::Client with default settings
|
41
|
+
# Pass a block to override any settings.
|
42
|
+
def agent_telemetry(
|
43
|
+
agent_settings:,
|
44
|
+
logger:,
|
45
|
+
api_version: nil,
|
46
|
+
headers: nil
|
47
|
+
)
|
48
|
+
Core::Transport::HTTP.build(api_instance_class: Telemetry::API::Instance,
|
49
|
+
logger: logger,
|
50
|
+
agent_settings: agent_settings, api_version: api_version, headers: headers) do |transport|
|
51
|
+
apis = API.defaults
|
52
|
+
|
53
|
+
transport.api API::AGENT_TELEMETRY, apis[API::AGENT_TELEMETRY]
|
54
|
+
|
55
|
+
# Call block to apply any customization, if provided
|
56
|
+
yield(transport) if block_given?
|
57
|
+
end.to_transport(Core::Telemetry::Transport::Telemetry::Transport)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../../transport/parcel'
|
4
|
+
require_relative 'http/client'
|
5
|
+
require_relative 'http/telemetry'
|
6
|
+
|
7
|
+
module Datadog
|
8
|
+
module Core
|
9
|
+
module Telemetry
|
10
|
+
module Transport
|
11
|
+
module Telemetry
|
12
|
+
class EncodedParcel
|
13
|
+
include Datadog::Core::Transport::Parcel
|
14
|
+
end
|
15
|
+
|
16
|
+
class Request < Datadog::Core::Transport::Request
|
17
|
+
attr_reader :request_type
|
18
|
+
attr_reader :api_key
|
19
|
+
|
20
|
+
def initialize(request_type, parcel, api_key)
|
21
|
+
@request_type = request_type
|
22
|
+
super(parcel)
|
23
|
+
@api_key = api_key
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
class Transport
|
28
|
+
attr_reader :client, :apis, :default_api, :current_api_id, :logger
|
29
|
+
attr_accessor :api_key
|
30
|
+
|
31
|
+
def initialize(apis, default_api, logger:)
|
32
|
+
@apis = apis
|
33
|
+
@logger = logger
|
34
|
+
|
35
|
+
@client = HTTP::Client.new(@apis[default_api], logger: logger)
|
36
|
+
end
|
37
|
+
|
38
|
+
def send_telemetry(request_type:, payload:)
|
39
|
+
json = JSON.dump(payload)
|
40
|
+
parcel = EncodedParcel.new(json)
|
41
|
+
request = Request.new(request_type, parcel, api_key)
|
42
|
+
|
43
|
+
@client.send_telemetry_payload(request)
|
44
|
+
# Perform no error checking here
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -17,8 +17,6 @@ module Datadog
|
|
17
17
|
DEFAULT_BUFFER_MAX_SIZE = 1000
|
18
18
|
APP_STARTED_EVENT_RETRIES = 10
|
19
19
|
|
20
|
-
TELEMETRY_STARTED_ONCE = Utils::OnlyOnceSuccessful.new(APP_STARTED_EVENT_RETRIES)
|
21
|
-
|
22
20
|
def initialize(
|
23
21
|
heartbeat_interval_seconds:,
|
24
22
|
metrics_aggregation_interval_seconds:,
|
@@ -48,14 +46,25 @@ module Datadog
|
|
48
46
|
@buffer_size = buffer_size
|
49
47
|
|
50
48
|
self.buffer = buffer_klass.new(@buffer_size)
|
49
|
+
|
50
|
+
@initial_event_once = Utils::OnlyOnceSuccessful.new(APP_STARTED_EVENT_RETRIES)
|
51
51
|
end
|
52
52
|
|
53
53
|
attr_reader :logger
|
54
|
+
attr_reader :initial_event_once
|
55
|
+
attr_reader :initial_event
|
54
56
|
|
55
|
-
|
57
|
+
# Returns true if worker thread is successfully started,
|
58
|
+
# false if worker thread was not started but telemetry is enabled,
|
59
|
+
# nil if telemetry is disabled.
|
60
|
+
def start(initial_event)
|
56
61
|
return if !enabled? || forked?
|
57
62
|
|
63
|
+
@initial_event = initial_event
|
64
|
+
|
58
65
|
# starts async worker
|
66
|
+
# perform should return true if thread was actually started,
|
67
|
+
# false otherwise
|
59
68
|
perform
|
60
69
|
end
|
61
70
|
|
@@ -65,18 +74,60 @@ module Datadog
|
|
65
74
|
super
|
66
75
|
end
|
67
76
|
|
77
|
+
# Returns true if event was enqueued, nil if not.
|
78
|
+
# While returning false may seem more reasonable, the only reason
|
79
|
+
# for not enqueueing event (presently) is that telemetry is disabled
|
80
|
+
# altogether, and in this case other methods return nil.
|
68
81
|
def enqueue(event)
|
69
82
|
return if !enabled? || forked?
|
70
83
|
|
71
84
|
buffer.push(event)
|
85
|
+
true
|
86
|
+
end
|
87
|
+
|
88
|
+
def sent_initial_event?
|
89
|
+
initial_event_once.success?
|
72
90
|
end
|
73
91
|
|
74
|
-
def
|
75
|
-
|
92
|
+
def failed_initial_event?
|
93
|
+
initial_event_once.failed?
|
76
94
|
end
|
77
95
|
|
78
|
-
def
|
79
|
-
|
96
|
+
def need_initial_event?
|
97
|
+
!sent_initial_event? && !failed_initial_event?
|
98
|
+
end
|
99
|
+
|
100
|
+
# Wait for the worker to send out all events that have already
|
101
|
+
# been queued, up to 15 seconds. Returns whether all events have
|
102
|
+
# been flushed.
|
103
|
+
#
|
104
|
+
# @api private
|
105
|
+
def flush
|
106
|
+
return true unless enabled? || !run_loop?
|
107
|
+
|
108
|
+
started = Utils::Time.get_time
|
109
|
+
loop do
|
110
|
+
# The AppStarted event is triggered by the worker itself,
|
111
|
+
# from the worker thread. As such the main thread has no way
|
112
|
+
# to delay itself until that event is queued and we need some
|
113
|
+
# way to wait until that event is sent out to assert on it in
|
114
|
+
# the test suite. Check the run once flag which *should*
|
115
|
+
# indicate the event has been queued (at which point our queue
|
116
|
+
# depth check should waint until it's sent).
|
117
|
+
# This is still a hack because the flag can be overridden
|
118
|
+
# either way with or without the event being sent out.
|
119
|
+
# Note that if the AppStarted sending fails, this check
|
120
|
+
# will return false and flushing will be blocked until the
|
121
|
+
# 15 second timeout.
|
122
|
+
# Note that the first wait interval between telemetry event
|
123
|
+
# sending is 10 seconds, the timeout needs to be strictly
|
124
|
+
# greater than that.
|
125
|
+
return true if buffer.empty? && !in_iteration? && sent_initial_event?
|
126
|
+
|
127
|
+
sleep 0.5
|
128
|
+
|
129
|
+
return false if Utils::Time.get_time - started > 15
|
130
|
+
end
|
80
131
|
end
|
81
132
|
|
82
133
|
private
|
@@ -84,11 +135,26 @@ module Datadog
|
|
84
135
|
def perform(*events)
|
85
136
|
return if !enabled? || forked?
|
86
137
|
|
87
|
-
|
138
|
+
if need_initial_event?
|
139
|
+
started!
|
140
|
+
unless sent_initial_event?
|
141
|
+
# We still haven't succeeded in sending the started event,
|
142
|
+
# which will make flush_events do nothing - but the events
|
143
|
+
# given to us as the parameter have already been removed
|
144
|
+
# from the queue.
|
145
|
+
# Put the events back to the front of the queue to not
|
146
|
+
# lose them.
|
147
|
+
buffer.unshift(*events)
|
148
|
+
return
|
149
|
+
end
|
150
|
+
end
|
88
151
|
|
89
152
|
metric_events = @metrics_manager.flush!
|
90
153
|
events = [] if events.nil?
|
91
|
-
|
154
|
+
events += metric_events
|
155
|
+
if events.any?
|
156
|
+
flush_events(events)
|
157
|
+
end
|
92
158
|
|
93
159
|
@current_ticks += 1
|
94
160
|
return if @current_ticks < @ticks_per_heartbeat
|
@@ -98,9 +164,6 @@ module Datadog
|
|
98
164
|
end
|
99
165
|
|
100
166
|
def flush_events(events)
|
101
|
-
return if events.empty?
|
102
|
-
return if !enabled? || !sent_started_event?
|
103
|
-
|
104
167
|
events = deduplicate_logs(events)
|
105
168
|
|
106
169
|
logger.debug { "Sending #{events&.count} telemetry events" }
|
@@ -108,7 +171,7 @@ module Datadog
|
|
108
171
|
end
|
109
172
|
|
110
173
|
def heartbeat!
|
111
|
-
return if !enabled? || !
|
174
|
+
return if !enabled? || !sent_initial_event?
|
112
175
|
|
113
176
|
send_event(Event::AppHeartbeat.new)
|
114
177
|
end
|
@@ -116,26 +179,29 @@ module Datadog
|
|
116
179
|
def started!
|
117
180
|
return unless enabled?
|
118
181
|
|
119
|
-
|
120
|
-
|
121
|
-
disable!
|
122
|
-
return
|
123
|
-
end
|
124
|
-
|
125
|
-
TELEMETRY_STARTED_ONCE.run do
|
126
|
-
res = send_event(Event::AppStarted.new)
|
182
|
+
initial_event_once.run do
|
183
|
+
res = send_event(initial_event)
|
127
184
|
|
128
185
|
if res.ok?
|
129
|
-
logger.debug
|
186
|
+
logger.debug { "Telemetry initial event (#{initial_event.type}) is successfully sent" }
|
130
187
|
|
131
|
-
|
188
|
+
# TODO Dependencies loaded event should probably check for new
|
189
|
+
# dependencies and send the new ones.
|
190
|
+
# System tests demand only one instance of this event per
|
191
|
+
# dependency.
|
192
|
+
send_event(Event::AppDependenciesLoaded.new) if @dependency_collection && initial_event.class.eql?(Telemetry::Event::AppStarted) # standard:disable Style/ClassEqualityComparison:
|
132
193
|
|
133
194
|
true
|
134
195
|
else
|
135
|
-
logger.debug(
|
196
|
+
logger.debug("Error sending telemetry initial event (#{initial_event.type}), retry after heartbeat interval...")
|
136
197
|
false
|
137
198
|
end
|
138
199
|
end
|
200
|
+
|
201
|
+
if failed_initial_event?
|
202
|
+
logger.debug { "Telemetry initial event (#{initial_event.type}) exhausted retries, disabling telemetry worker" }
|
203
|
+
disable!
|
204
|
+
end
|
139
205
|
end
|
140
206
|
|
141
207
|
def send_event(event)
|
@@ -41,19 +41,19 @@ module Datadog
|
|
41
41
|
|
42
42
|
def adapter(config, *args, **kwargs)
|
43
43
|
@default_adapter = case config
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
44
|
+
when Core::Configuration::AgentSettingsResolver::AgentSettings
|
45
|
+
registry_klass = REGISTRY.get(config.adapter)
|
46
|
+
raise UnknownAdapterError, config.adapter if registry_klass.nil?
|
47
|
+
|
48
|
+
registry_klass.build(config)
|
49
|
+
when Symbol
|
50
|
+
registry_klass = REGISTRY.get(config)
|
51
|
+
raise UnknownAdapterError, config if registry_klass.nil?
|
52
|
+
|
53
|
+
registry_klass.new(*args, **kwargs)
|
54
|
+
else
|
55
|
+
config
|
56
|
+
end
|
57
57
|
end
|
58
58
|
|
59
59
|
def headers(values = {})
|
@@ -51,13 +51,13 @@ module Datadog
|
|
51
51
|
def fork
|
52
52
|
# If a block is provided, it must be wrapped to trigger callbacks.
|
53
53
|
child_block = if block_given?
|
54
|
-
|
55
|
-
|
54
|
+
proc do
|
55
|
+
AtForkMonkeyPatch.run_at_fork_blocks(:child)
|
56
56
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
57
|
+
# Invoke original block
|
58
|
+
yield
|
59
|
+
end
|
60
|
+
end
|
61
61
|
|
62
62
|
# Start fork
|
63
63
|
# If a block is provided, use the wrapped version.
|
@@ -7,42 +7,42 @@ module Datadog
|
|
7
7
|
module Duration
|
8
8
|
def self.call(value, base: :s)
|
9
9
|
cast = if value.include?('.')
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
10
|
+
method(:Float)
|
11
|
+
else
|
12
|
+
method(:Integer)
|
13
|
+
end
|
14
14
|
|
15
15
|
scale = case base
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
16
|
+
when :s
|
17
|
+
1_000_000_000
|
18
|
+
when :ms
|
19
|
+
1_000_000
|
20
|
+
when :us
|
21
|
+
1000
|
22
|
+
when :ns
|
23
|
+
1
|
24
|
+
else
|
25
|
+
raise ArgumentError, "invalid base: #{base.inspect}"
|
26
|
+
end
|
27
27
|
|
28
28
|
result = case value
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
29
|
+
when /^(\d+(?:\.\d+)?)h$/
|
30
|
+
cast.call(Regexp.last_match(1)) * 1_000_000_000 * 60 * 60 / scale
|
31
|
+
when /^(\d+(?:\.\d+)?)m$/
|
32
|
+
cast.call(Regexp.last_match(1)) * 1_000_000_000 * 60 / scale
|
33
|
+
when /^(\d+(?:\.\d+)?)s$/
|
34
|
+
cast.call(Regexp.last_match(1)) * 1_000_000_000 / scale
|
35
|
+
when /^(\d+(?:\.\d+)?)ms$/
|
36
|
+
cast.call(Regexp.last_match(1)) * 1_000_000 / scale
|
37
|
+
when /^(\d+(?:\.\d+)?)us$/
|
38
|
+
cast.call(Regexp.last_match(1)) * 1_000 / scale
|
39
|
+
when /^(\d+(?:\.\d+)?)ns$/
|
40
|
+
cast.call(Regexp.last_match(1)) / scale
|
41
|
+
when /^(\d+(?:\.\d+)?)$/
|
42
|
+
cast.call(Regexp.last_match(1))
|
43
|
+
else
|
44
|
+
raise ArgumentError, "invalid duration: #{value.inspect}"
|
45
|
+
end
|
46
46
|
# @type var result: Numeric
|
47
47
|
result.round
|
48
48
|
end
|
@@ -47,12 +47,12 @@ module Datadog
|
|
47
47
|
# This wrapper prevents this by initializing the fork PID when the object is created.
|
48
48
|
if RUBY_VERSION >= '3'
|
49
49
|
def initialize(*args, **kwargs, &block)
|
50
|
-
super
|
50
|
+
super
|
51
51
|
update_fork_pid!
|
52
52
|
end
|
53
53
|
else
|
54
54
|
def initialize(*args, &block)
|
55
|
-
super
|
55
|
+
super
|
56
56
|
update_fork_pid!
|
57
57
|
end
|
58
58
|
end
|
@@ -32,7 +32,7 @@ module Datadog
|
|
32
32
|
def stripped_ip_from_request_headers(headers, ip_headers_to_check: DEFAULT_IP_HEADERS_NAMES)
|
33
33
|
ip = ip_header(headers, ip_headers_to_check)
|
34
34
|
|
35
|
-
ip
|
35
|
+
ip&.to_s
|
36
36
|
end
|
37
37
|
|
38
38
|
# @param [String] IP value.
|
@@ -40,7 +40,7 @@ module Datadog
|
|
40
40
|
# @return [nil] when no valid IP value found.
|
41
41
|
def stripped_ip(ip)
|
42
42
|
ip = ip_to_ipaddr(ip)
|
43
|
-
ip
|
43
|
+
ip&.to_s
|
44
44
|
end
|
45
45
|
|
46
46
|
private
|
@@ -52,10 +52,10 @@ module Datadog
|
|
52
52
|
return unless ip
|
53
53
|
|
54
54
|
clean_ip = if likely_ipv4?(ip)
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
55
|
+
strip_ipv4_port(ip)
|
56
|
+
else
|
57
|
+
strip_zone_specifier(strip_ipv6_port(ip))
|
58
|
+
end
|
59
59
|
|
60
60
|
begin
|
61
61
|
IPAddr.new(clean_ip)
|