datadog 2.22.0 → 2.23.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 +59 -2
- data/ext/LIBDATADOG_DEVELOPMENT.md +1 -58
- data/ext/datadog_profiling_native_extension/collectors_stack.c +4 -0
- data/ext/datadog_profiling_native_extension/datadog_ruby_common.h +1 -1
- data/ext/datadog_profiling_native_extension/extconf.rb +6 -4
- data/ext/datadog_profiling_native_extension/heap_recorder.c +1 -1
- 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/remote.rb +4 -0
- data/lib/datadog/appsec/response.rb +18 -4
- data/lib/datadog/core/configuration/components.rb +30 -3
- data/lib/datadog/core/configuration/config_helper.rb +1 -1
- data/lib/datadog/core/configuration/settings.rb +14 -0
- data/lib/datadog/core/configuration/supported_configurations.rb +330 -301
- data/lib/datadog/core/ddsketch.rb +0 -2
- data/lib/datadog/core/environment/ext.rb +6 -0
- data/lib/datadog/core/environment/process.rb +79 -0
- data/lib/datadog/core/feature_flags.rb +61 -0
- data/lib/datadog/core/remote/client/capabilities.rb +7 -0
- data/lib/datadog/core/remote/transport/config.rb +2 -10
- data/lib/datadog/core/remote/transport/http/config.rb +9 -9
- data/lib/datadog/core/remote/transport/http/negotiation.rb +17 -8
- data/lib/datadog/core/remote/transport/http.rb +2 -0
- data/lib/datadog/core/remote/transport/negotiation.rb +2 -18
- 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 +7 -3
- data/lib/datadog/core/telemetry/event/app_started.rb +52 -49
- data/lib/datadog/core/telemetry/event/synth_app_client_configuration_change.rb +1 -1
- data/lib/datadog/core/telemetry/logger.rb +2 -2
- data/lib/datadog/core/telemetry/logging.rb +2 -8
- data/lib/datadog/core/telemetry/transport/http/telemetry.rb +5 -6
- data/lib/datadog/core/telemetry/transport/telemetry.rb +1 -2
- data/lib/datadog/core/transport/http/client.rb +69 -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 +6 -2
- data/lib/datadog/core/utils.rb +2 -0
- 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/api.rb +33 -0
- data/lib/datadog/data_streams/transport/http/client.rb +21 -0
- data/lib/datadog/data_streams/transport/http/stats.rb +87 -0
- data/lib/datadog/data_streams/transport/http.rb +41 -0
- data/lib/datadog/data_streams/transport/stats.rb +60 -0
- data/lib/datadog/data_streams.rb +100 -0
- data/lib/datadog/di/component.rb +0 -16
- data/lib/datadog/di/el/evaluator.rb +1 -1
- data/lib/datadog/di/error.rb +4 -0
- data/lib/datadog/di/instrumenter.rb +76 -30
- data/lib/datadog/di/probe.rb +20 -0
- data/lib/datadog/di/probe_manager.rb +10 -2
- data/lib/datadog/di/probe_notification_builder.rb +62 -23
- data/lib/datadog/di/proc_responder.rb +32 -0
- data/lib/datadog/di/transport/diagnostics.rb +2 -2
- data/lib/datadog/di/transport/http/diagnostics.rb +2 -4
- data/lib/datadog/di/transport/http/input.rb +2 -4
- data/lib/datadog/di/transport/http.rb +6 -2
- data/lib/datadog/di/transport/input.rb +64 -4
- 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 +69 -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 +74 -0
- data/lib/datadog/open_feature/resolution_details.rb +35 -0
- data/lib/datadog/open_feature/transport.rb +72 -0
- data/lib/datadog/open_feature.rb +19 -0
- data/lib/datadog/opentelemetry/configuration/settings.rb +159 -0
- data/lib/datadog/opentelemetry/metrics.rb +110 -0
- data/lib/datadog/opentelemetry/sdk/configurator.rb +25 -1
- data/lib/datadog/opentelemetry/sdk/metrics_exporter.rb +38 -0
- data/lib/datadog/opentelemetry.rb +3 -0
- data/lib/datadog/profiling/collectors/code_provenance.rb +15 -6
- 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/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/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 +32 -0
- 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 +7 -0
- 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 +46 -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/metadata/ext.rb +1 -1
- data/lib/datadog/tracing/transport/http/client.rb +12 -26
- data/lib/datadog/tracing/transport/trace_formatter.rb +11 -0
- data/lib/datadog/tracing/transport/traces.rb +3 -5
- data/lib/datadog/version.rb +2 -2
- data/lib/datadog.rb +2 -0
- metadata +78 -15
- data/lib/datadog/core/remote/transport/http/client.rb +0 -49
- data/lib/datadog/core/telemetry/transport/http/client.rb +0 -49
- data/lib/datadog/di/transport/http/client.rb +0 -47
|
@@ -33,8 +33,14 @@ module Datadog
|
|
|
33
33
|
LANG_INTERPRETER = "#{RUBY_ENGINE}-#{RUBY_PLATFORM}"
|
|
34
34
|
LANG_PLATFORM = RUBY_PLATFORM
|
|
35
35
|
LANG_VERSION = RUBY_VERSION
|
|
36
|
+
PROCESS_TYPE = 'script' # Out of the options [jar, script, class, executable], we consider Ruby to always be a script
|
|
36
37
|
RUBY_ENGINE = ::RUBY_ENGINE # e.g. 'ruby', 'jruby', 'truffleruby'
|
|
37
38
|
TAG_ENV = 'env'
|
|
39
|
+
TAG_ENTRYPOINT_BASEDIR = "entrypoint.basedir"
|
|
40
|
+
TAG_ENTRYPOINT_NAME = "entrypoint.name"
|
|
41
|
+
TAG_ENTRYPOINT_WORKDIR = "entrypoint.workdir"
|
|
42
|
+
TAG_ENTRYPOINT_TYPE = "entrypoint.type"
|
|
43
|
+
TAG_PROCESS_TAGS = "_dd.tags.process"
|
|
38
44
|
TAG_SERVICE = 'service'
|
|
39
45
|
TAG_VERSION = 'version'
|
|
40
46
|
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'ext'
|
|
4
|
+
require_relative '../tag_normalizer'
|
|
5
|
+
|
|
6
|
+
module Datadog
|
|
7
|
+
module Core
|
|
8
|
+
module Environment
|
|
9
|
+
# Retrieves process level information such that it can be attached to various payloads
|
|
10
|
+
#
|
|
11
|
+
# @api private
|
|
12
|
+
module Process
|
|
13
|
+
# This method returns a key/value part of serialized tags in the format of k1:v1,k2:v2,k3:v3
|
|
14
|
+
# @return [String] comma-separated normalized key:value pairs
|
|
15
|
+
def self.serialized
|
|
16
|
+
return @serialized if defined?(@serialized)
|
|
17
|
+
tags = []
|
|
18
|
+
|
|
19
|
+
workdir = TagNormalizer.normalize_process_value(entrypoint_workdir.to_s)
|
|
20
|
+
tags << "#{Environment::Ext::TAG_ENTRYPOINT_WORKDIR}:#{workdir}" unless workdir.empty?
|
|
21
|
+
|
|
22
|
+
entry_name = TagNormalizer.normalize_process_value(entrypoint_name.to_s)
|
|
23
|
+
tags << "#{Environment::Ext::TAG_ENTRYPOINT_NAME}:#{entry_name}" unless entry_name.empty?
|
|
24
|
+
|
|
25
|
+
basedir = TagNormalizer.normalize_process_value(entrypoint_basedir.to_s)
|
|
26
|
+
tags << "#{Environment::Ext::TAG_ENTRYPOINT_BASEDIR}:#{basedir}" unless basedir.empty?
|
|
27
|
+
|
|
28
|
+
tags << "#{Environment::Ext::TAG_ENTRYPOINT_TYPE}:#{TagNormalizer.normalize(entrypoint_type, remove_digit_start_char: false)}"
|
|
29
|
+
|
|
30
|
+
@serialized = tags.join(',').freeze
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Returns the last segment of the working directory of the process
|
|
34
|
+
# Example: /app/myapp -> myapp
|
|
35
|
+
# @return [String] the last segment of the working directory
|
|
36
|
+
def self.entrypoint_workdir
|
|
37
|
+
File.basename(Dir.pwd)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Returns the entrypoint type of the process
|
|
41
|
+
# In Ruby, the entrypoint type is always 'script'
|
|
42
|
+
# @return [String] the type of the process, which is fixed in Ruby
|
|
43
|
+
def self.entrypoint_type
|
|
44
|
+
Environment::Ext::PROCESS_TYPE
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# Returns the last segment of the base directory of the process
|
|
48
|
+
# Example 1: /bin/mybin -> mybin
|
|
49
|
+
# Example 2: ruby /test/myapp.rb -> myapp
|
|
50
|
+
# @return [String] the last segment of base directory of the script
|
|
51
|
+
#
|
|
52
|
+
# @note Determining true entrypoint name is rather complicated. This method
|
|
53
|
+
# is the initial implementation but it does not produce optimal output in all cases.
|
|
54
|
+
# For example, all Rails applications launched via `rails server` get `rails`
|
|
55
|
+
# as their entrypoint name.
|
|
56
|
+
# We might improve the behavior in the future if there is customer demand for it.
|
|
57
|
+
def self.entrypoint_name
|
|
58
|
+
File.basename($0)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# Returns the last segment of the base directory of the process
|
|
62
|
+
# Example 1: /bin/mybin -> bin
|
|
63
|
+
# Example 2: ruby /test/myapp.js -> test
|
|
64
|
+
# @return [String] the last segment of the base directory of the script
|
|
65
|
+
#
|
|
66
|
+
# @note As with entrypoint name, determining true entrypoint directory is complicated.
|
|
67
|
+
# This method has an initial implementation that does not necessarily return good
|
|
68
|
+
# results in all cases. For example, for Rails applications launched via `rails server`
|
|
69
|
+
# the entrypoint basedir is `bin` which is not very helpful.
|
|
70
|
+
# We might improve this in the future if there is customer demand.
|
|
71
|
+
def self.entrypoint_basedir
|
|
72
|
+
File.basename(File.expand_path(File.dirname($0)))
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
private_class_method :entrypoint_workdir, :entrypoint_type, :entrypoint_name, :entrypoint_basedir
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'json'
|
|
4
|
+
|
|
5
|
+
module Datadog
|
|
6
|
+
module Core
|
|
7
|
+
# Feature flags evaluation using libdatadog
|
|
8
|
+
# The classes in this module are defined as C extensions in ext/libdatadog_api/feature_flags.c
|
|
9
|
+
#
|
|
10
|
+
# @api private
|
|
11
|
+
module FeatureFlags
|
|
12
|
+
# A top-level error raised by the extension
|
|
13
|
+
class Error < StandardError # rubocop:disable Lint/EmptyClass
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# Configuration for feature flags evaluation
|
|
17
|
+
# This class is defined in the C extension
|
|
18
|
+
class Configuration # rubocop:disable Lint/EmptyClass
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# Resolution details for a feature flag evaluation
|
|
22
|
+
# Base class is defined in the C extension, with Ruby methods added here
|
|
23
|
+
class ResolutionDetails
|
|
24
|
+
attr_writer :value
|
|
25
|
+
|
|
26
|
+
# Get the resolved value, with JSON parsing for object types
|
|
27
|
+
#
|
|
28
|
+
# @return [Object] The resolved value (parsed from JSON if object type)
|
|
29
|
+
# @raise [Datadog::Core::FeatureFlags::Error] If JSON parsing fails
|
|
30
|
+
def value
|
|
31
|
+
return @value if defined?(@value)
|
|
32
|
+
|
|
33
|
+
# NOTE: Raw value method call doesn't support memoization right now
|
|
34
|
+
value = raw_value
|
|
35
|
+
|
|
36
|
+
# NOTE: Lazy parsing of the JSON is a temporary solution and will be
|
|
37
|
+
# moved into C extension
|
|
38
|
+
@value = json?(value) ? JSON.parse(value) : value
|
|
39
|
+
rescue JSON::ParserError => e
|
|
40
|
+
raise Error, "Failed to parse JSON value: #{e.class}: #{e}"
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# Check if the resolution resulted in an error
|
|
44
|
+
#
|
|
45
|
+
# @return [Boolean] True if there was an error
|
|
46
|
+
def error?
|
|
47
|
+
reason == 'ERROR'
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
private
|
|
51
|
+
|
|
52
|
+
# NOTE: A JSON raw string will be returned by the `libdatadog` as
|
|
53
|
+
# a Ruby String class with a flag type `:object`, otherwise it's
|
|
54
|
+
# just a string.
|
|
55
|
+
def json?(value)
|
|
56
|
+
flag_type == :object && value.is_a?(String)
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
require_relative '../../utils/base64'
|
|
4
4
|
require_relative '../../../appsec/remote'
|
|
5
5
|
require_relative '../../../tracing/remote'
|
|
6
|
+
require_relative '../../../open_feature/remote'
|
|
6
7
|
|
|
7
8
|
module Datadog
|
|
8
9
|
module Core
|
|
@@ -38,6 +39,12 @@ module Datadog
|
|
|
38
39
|
register_receivers(Datadog::DI::Remote.receivers(@telemetry))
|
|
39
40
|
end
|
|
40
41
|
|
|
42
|
+
if settings.respond_to?(:open_feature) && settings.open_feature.enabled
|
|
43
|
+
register_capabilities(Datadog::OpenFeature::Remote.capabilities)
|
|
44
|
+
register_products(Datadog::OpenFeature::Remote.products)
|
|
45
|
+
register_receivers(Datadog::OpenFeature::Remote.receivers(@telemetry))
|
|
46
|
+
end
|
|
47
|
+
|
|
41
48
|
register_capabilities(Datadog::Tracing::Remote.capabilities)
|
|
42
49
|
register_products(Datadog::Tracing::Remote.products)
|
|
43
50
|
register_receivers(Datadog::Tracing::Remote.receivers(@telemetry))
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
require_relative '../../../core/transport/request'
|
|
4
4
|
require_relative '../../../core/transport/parcel'
|
|
5
|
+
require_relative 'http/config'
|
|
5
6
|
|
|
6
7
|
module Datadog
|
|
7
8
|
module Core
|
|
@@ -21,15 +22,6 @@ module Datadog
|
|
|
21
22
|
class Request < Datadog::Core::Transport::Request
|
|
22
23
|
end
|
|
23
24
|
|
|
24
|
-
# Config response
|
|
25
|
-
module Response
|
|
26
|
-
attr_reader :roots, :targets, :target_files, :client_configs
|
|
27
|
-
|
|
28
|
-
def empty?
|
|
29
|
-
@empty
|
|
30
|
-
end
|
|
31
|
-
end
|
|
32
|
-
|
|
33
25
|
# Config transport
|
|
34
26
|
class Transport
|
|
35
27
|
attr_reader :client, :apis, :default_api, :current_api_id, :logger
|
|
@@ -38,7 +30,7 @@ module Datadog
|
|
|
38
30
|
@apis = apis
|
|
39
31
|
@logger = logger
|
|
40
32
|
|
|
41
|
-
@client = HTTP::Client.new(current_api, logger: logger)
|
|
33
|
+
@client = Remote::Transport::HTTP::Config::Client.new(current_api, logger: logger)
|
|
42
34
|
end
|
|
43
35
|
|
|
44
36
|
##### there is only one transport! it's negotiation!
|
|
@@ -2,8 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
require 'json'
|
|
4
4
|
|
|
5
|
-
require_relative '
|
|
6
|
-
require_relative 'client'
|
|
5
|
+
require_relative '../../../transport/http/client'
|
|
7
6
|
require_relative '../../../utils/base64'
|
|
8
7
|
require_relative '../../../utils/truncation'
|
|
9
8
|
require_relative '../../../transport/http/response'
|
|
@@ -19,7 +18,6 @@ module Datadog
|
|
|
19
18
|
# Response from HTTP transport for remote configuration
|
|
20
19
|
class Response
|
|
21
20
|
include Datadog::Core::Transport::HTTP::Response
|
|
22
|
-
include Core::Remote::Transport::Config::Response
|
|
23
21
|
|
|
24
22
|
def initialize(http_response, options = {}) # standard:disable Metrics/AbcSize,Metrics/CyclomaticComplexity,Metrics/MethodLength,Metrics/PerceivedComplexity
|
|
25
23
|
super(http_response)
|
|
@@ -114,6 +112,12 @@ module Datadog
|
|
|
114
112
|
end.freeze
|
|
115
113
|
end
|
|
116
114
|
|
|
115
|
+
attr_reader :roots, :targets, :target_files, :client_configs
|
|
116
|
+
|
|
117
|
+
def empty?
|
|
118
|
+
@empty
|
|
119
|
+
end
|
|
120
|
+
|
|
117
121
|
def inspect
|
|
118
122
|
"#{super}, #{
|
|
119
123
|
{
|
|
@@ -174,8 +178,8 @@ module Datadog
|
|
|
174
178
|
end
|
|
175
179
|
end
|
|
176
180
|
|
|
177
|
-
#
|
|
178
|
-
|
|
181
|
+
# Remote transport HTTP client
|
|
182
|
+
class Client < Core::Transport::HTTP::Client
|
|
179
183
|
def send_config_payload(request)
|
|
180
184
|
send_request(request) do |api, env|
|
|
181
185
|
api.send_config(env)
|
|
@@ -240,10 +244,6 @@ module Datadog
|
|
|
240
244
|
end
|
|
241
245
|
end
|
|
242
246
|
end
|
|
243
|
-
|
|
244
|
-
# Add remote configuration behavior to transport components
|
|
245
|
-
###### overrides send_payload! which calls send_<endpoint>! kills any other possible endpoint!
|
|
246
|
-
HTTP::Client.include(Config::Client)
|
|
247
247
|
end
|
|
248
248
|
end
|
|
249
249
|
end
|
|
@@ -2,8 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
require 'json'
|
|
4
4
|
|
|
5
|
-
require_relative '
|
|
6
|
-
require_relative 'client'
|
|
5
|
+
require_relative '../../../transport/http/client'
|
|
7
6
|
require_relative '../../../transport/http/response'
|
|
8
7
|
require_relative '../../../transport/http/api/endpoint'
|
|
9
8
|
|
|
@@ -17,7 +16,6 @@ module Datadog
|
|
|
17
16
|
# Response from HTTP transport for agent feature negotiation
|
|
18
17
|
class Response
|
|
19
18
|
include Datadog::Core::Transport::HTTP::Response
|
|
20
|
-
include Core::Remote::Transport::Negotiation::Response
|
|
21
19
|
|
|
22
20
|
def initialize(http_response, options = {})
|
|
23
21
|
super(http_response)
|
|
@@ -29,10 +27,24 @@ module Datadog
|
|
|
29
27
|
@config = options[:config]
|
|
30
28
|
@span_events = options[:span_events]
|
|
31
29
|
end
|
|
30
|
+
|
|
31
|
+
# @!attribute [r] version
|
|
32
|
+
# The version of the agent.
|
|
33
|
+
# @return [String]
|
|
34
|
+
# @!attribute [r] endpoints
|
|
35
|
+
# The HTTP endpoints the agent supports.
|
|
36
|
+
# @return [Array<String>]
|
|
37
|
+
# @!attribute [r] config
|
|
38
|
+
# The agent configuration. These are configured by the user when starting the agent, as well as any defaults.
|
|
39
|
+
# @return [Hash]
|
|
40
|
+
# @!attribute [r] span_events
|
|
41
|
+
# Whether the agent supports the top-level span events field in flushed spans.
|
|
42
|
+
# @return [Boolean,nil]
|
|
43
|
+
attr_reader :version, :endpoints, :config, :span_events
|
|
32
44
|
end
|
|
33
45
|
|
|
34
|
-
#
|
|
35
|
-
|
|
46
|
+
# Remote negotiation HTTP client
|
|
47
|
+
class Client < Core::Transport::HTTP::Client
|
|
36
48
|
def send_info_payload(request)
|
|
37
49
|
send_request(request) do |api, env|
|
|
38
50
|
api.send_info(env)
|
|
@@ -92,9 +104,6 @@ module Datadog
|
|
|
92
104
|
end
|
|
93
105
|
end
|
|
94
106
|
end
|
|
95
|
-
|
|
96
|
-
# Add negotiation behavior to transport components
|
|
97
|
-
HTTP::Client.include(Negotiation::Client)
|
|
98
107
|
end
|
|
99
108
|
end
|
|
100
109
|
end
|
|
@@ -4,6 +4,8 @@ require_relative '../../environment/container'
|
|
|
4
4
|
require_relative '../../environment/ext'
|
|
5
5
|
require_relative '../../transport/ext'
|
|
6
6
|
require_relative '../../transport/http'
|
|
7
|
+
require_relative 'config'
|
|
8
|
+
require_relative 'negotiation'
|
|
7
9
|
|
|
8
10
|
# TODO: Improve negotiation to allow per endpoint selection
|
|
9
11
|
#
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require_relative '../../../core/transport/request'
|
|
4
|
+
require_relative 'http/negotiation'
|
|
4
5
|
|
|
5
6
|
# TODO: Resolve conceptual conundrum
|
|
6
7
|
#
|
|
@@ -30,23 +31,6 @@ module Datadog
|
|
|
30
31
|
class Request < Datadog::Core::Transport::Request
|
|
31
32
|
end
|
|
32
33
|
|
|
33
|
-
# Negotiation response
|
|
34
|
-
module Response
|
|
35
|
-
# @!attribute [r] version
|
|
36
|
-
# The version of the agent.
|
|
37
|
-
# @return [String]
|
|
38
|
-
# @!attribute [r] endpoints
|
|
39
|
-
# The HTTP endpoints the agent supports.
|
|
40
|
-
# @return [Array<String>]
|
|
41
|
-
# @!attribute [r] config
|
|
42
|
-
# The agent configuration. These are configured by the user when starting the agent, as well as any defaults.
|
|
43
|
-
# @return [Hash]
|
|
44
|
-
# @!attribute [r] span_events
|
|
45
|
-
# Whether the agent supports the top-level span events field in flushed spans.
|
|
46
|
-
# @return [Boolean,nil]
|
|
47
|
-
attr_reader :version, :endpoints, :config, :span_events
|
|
48
|
-
end
|
|
49
|
-
|
|
50
34
|
# Negotiation transport
|
|
51
35
|
class Transport
|
|
52
36
|
attr_reader :client, :apis, :default_api, :current_api_id, :logger
|
|
@@ -55,7 +39,7 @@ module Datadog
|
|
|
55
39
|
@apis = apis
|
|
56
40
|
@logger = logger
|
|
57
41
|
|
|
58
|
-
@client = HTTP::Client.new(current_api, logger: logger)
|
|
42
|
+
@client = Remote::Transport::HTTP::Negotiation::Client.new(current_api, logger: logger)
|
|
59
43
|
end
|
|
60
44
|
|
|
61
45
|
def send_info
|
|
@@ -23,51 +23,47 @@ module Datadog
|
|
|
23
23
|
attr_reader :logger
|
|
24
24
|
|
|
25
25
|
def start
|
|
26
|
-
logger.debug {
|
|
26
|
+
logger.debug { "remote worker starting (pid: #{Process.pid})" }
|
|
27
27
|
|
|
28
|
-
|
|
28
|
+
@mutex.synchronize do
|
|
29
|
+
if @stopped
|
|
30
|
+
logger.debug('remote worker: refusing to restart after previous stop')
|
|
31
|
+
return
|
|
32
|
+
end
|
|
29
33
|
|
|
30
|
-
|
|
31
|
-
logger.debug('remote worker: refusing to restart after previous stop')
|
|
32
|
-
return
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
return if @starting || @started
|
|
34
|
+
return if @starting || @started
|
|
36
35
|
|
|
37
|
-
|
|
36
|
+
@starting = true
|
|
38
37
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
38
|
+
thread = Thread.new { poll(@interval) }
|
|
39
|
+
thread.name = self.class.name
|
|
40
|
+
thread.thread_variable_set(:fork_safe, true)
|
|
41
|
+
@thr = thread
|
|
43
42
|
|
|
44
|
-
|
|
45
|
-
|
|
43
|
+
@started = true
|
|
44
|
+
@starting = false
|
|
45
|
+
end
|
|
46
46
|
|
|
47
47
|
logger.debug { 'remote worker started' }
|
|
48
|
-
ensure
|
|
49
|
-
release_lock
|
|
50
48
|
end
|
|
51
49
|
|
|
52
50
|
def stop
|
|
53
|
-
logger.debug {
|
|
51
|
+
logger.debug { "remote worker stopping (pid: #{Process.pid})" }
|
|
54
52
|
|
|
55
|
-
|
|
53
|
+
@mutex.synchronize do
|
|
54
|
+
thread = @thr
|
|
56
55
|
|
|
57
|
-
|
|
56
|
+
if thread
|
|
57
|
+
thread.kill
|
|
58
|
+
thread.join
|
|
59
|
+
end
|
|
58
60
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
61
|
+
@started = false
|
|
62
|
+
@thr = nil
|
|
63
|
+
@stopped = true
|
|
62
64
|
end
|
|
63
65
|
|
|
64
|
-
@started = false
|
|
65
|
-
@thr = nil
|
|
66
|
-
@stopped = true
|
|
67
|
-
|
|
68
66
|
logger.debug { 'remote worker stopped' }
|
|
69
|
-
ensure
|
|
70
|
-
release_lock
|
|
71
67
|
end
|
|
72
68
|
|
|
73
69
|
def started?
|
|
@@ -76,14 +72,6 @@ module Datadog
|
|
|
76
72
|
|
|
77
73
|
private
|
|
78
74
|
|
|
79
|
-
def acquire_lock
|
|
80
|
-
@mutex.lock
|
|
81
|
-
end
|
|
82
|
-
|
|
83
|
-
def release_lock
|
|
84
|
-
@mutex.unlock
|
|
85
|
-
end
|
|
86
|
-
|
|
87
75
|
def poll(interval)
|
|
88
76
|
loop do
|
|
89
77
|
break unless @mutex.synchronize { @starting || @started }
|
|
@@ -8,10 +8,6 @@ module Datadog
|
|
|
8
8
|
module Core
|
|
9
9
|
# This module builds a hash of tags.
|
|
10
10
|
#
|
|
11
|
-
# When changing or adding the tags, make sure they are kept in sync with
|
|
12
|
-
# https://docs.google.com/spreadsheets/d/1LOGMf4c4Avbtn36uZ2SWvhIGKRPLM1BoWkUP4JYj7hA/
|
|
13
|
-
# (Datadog internal link).
|
|
14
|
-
#
|
|
15
11
|
# @api private
|
|
16
12
|
module TagBuilder
|
|
17
13
|
def self.fixed_environment_tags
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'utils'
|
|
4
|
+
|
|
5
|
+
module Datadog
|
|
6
|
+
module Core
|
|
7
|
+
# @api private
|
|
8
|
+
module TagNormalizer
|
|
9
|
+
# Normalization logic used for tag keys and values that the Trace Agent has for traces
|
|
10
|
+
# Useful for ensuring that tag keys and values are normalized consistently
|
|
11
|
+
# An use case for now is Process Tags which need to be sent across various intakes (profiling, tracing, etc.) consistently
|
|
12
|
+
|
|
13
|
+
module_function
|
|
14
|
+
|
|
15
|
+
INVALID_TAG_CHARACTERS = %r{[^\p{L}0-9_\-:./]}
|
|
16
|
+
LEADING_INVALID_CHARS_NO_DIGITS = %r{\A[^\p{L}:]++}
|
|
17
|
+
LEADING_INVALID_CHARS_WITH_DIGITS = %r{\A[^\p{L}0-9:./]++}
|
|
18
|
+
MAX_BYTE_SIZE = 200 # Represents the general max tag length
|
|
19
|
+
MAX_PROCESS_VALUE_BYTE_SIZE = 100 # Represents the max tag length for process tags
|
|
20
|
+
VALID_ASCII_TAG = %r{\A[a-z:][a-z0-9:./-]*\z}
|
|
21
|
+
|
|
22
|
+
# Based on https://github.com/DataDog/datadog-agent/blob/45799c842bbd216bcda208737f9f11cade6fdd95/pkg/trace/traceutil/normalize.go#L131
|
|
23
|
+
# Specifically for general normalization:
|
|
24
|
+
# - Must be valid UTF-8
|
|
25
|
+
# - Invalid characters are replaced with an underscore
|
|
26
|
+
# - Leading non-letter characters are removed but colons are kept
|
|
27
|
+
# - Trailing non-letter characters are removed
|
|
28
|
+
# - Trailing underscores are removed
|
|
29
|
+
# - Consecutive underscores are merged into a single underscore
|
|
30
|
+
# - Maximum length is 200 characters
|
|
31
|
+
# If it's a tag value, allow it to start with a digit
|
|
32
|
+
# @param original_value [String] The original string
|
|
33
|
+
# @param remove_digit_start_char [Boolean] - whether to remove the leading digit (currently only used for tag values)
|
|
34
|
+
# @return [String] The normalized string
|
|
35
|
+
def self.normalize(original_value, remove_digit_start_char: false)
|
|
36
|
+
# DEV-3.0: Ideally this encode call should be replaced with Datadog::Core::Utils.utf8_encode once it
|
|
37
|
+
# is safe to modify the default behavior.
|
|
38
|
+
value = original_value.to_s.encode('UTF-8', invalid: :replace, undef: :replace)
|
|
39
|
+
value.strip!
|
|
40
|
+
return "" if value.empty?
|
|
41
|
+
|
|
42
|
+
return value if value.bytesize <= MAX_BYTE_SIZE &&
|
|
43
|
+
value.match?(VALID_ASCII_TAG)
|
|
44
|
+
|
|
45
|
+
if value.bytesize > MAX_BYTE_SIZE
|
|
46
|
+
value = value.byteslice(0, MAX_BYTE_SIZE)
|
|
47
|
+
value.scrub!("")
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
value.downcase!
|
|
51
|
+
value.gsub!(INVALID_TAG_CHARACTERS, '_')
|
|
52
|
+
|
|
53
|
+
# The Trace Agent allows tag values to start with a number so this logic is here too
|
|
54
|
+
leading_invalid_regex = remove_digit_start_char ? LEADING_INVALID_CHARS_NO_DIGITS : LEADING_INVALID_CHARS_WITH_DIGITS
|
|
55
|
+
value.sub!(leading_invalid_regex, "")
|
|
56
|
+
|
|
57
|
+
value.squeeze!('_') if value.include?('__')
|
|
58
|
+
value.delete_suffix!('_')
|
|
59
|
+
|
|
60
|
+
value
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# Process tags values follow an additional piece of normalization:
|
|
64
|
+
# - must not be more than 100 bytes
|
|
65
|
+
# - and must not contain colons
|
|
66
|
+
# @param value [String] The original string
|
|
67
|
+
# @return [String] The normalized string
|
|
68
|
+
def self.normalize_process_value(value)
|
|
69
|
+
value = normalize(value)
|
|
70
|
+
return value if value.empty?
|
|
71
|
+
|
|
72
|
+
value.tr!(':', '_')
|
|
73
|
+
value.squeeze!('_') if value.include?('__')
|
|
74
|
+
|
|
75
|
+
if value.bytesize > MAX_PROCESS_VALUE_BYTE_SIZE
|
|
76
|
+
value = value.byteslice(0, MAX_PROCESS_VALUE_BYTE_SIZE) || value
|
|
77
|
+
value.scrub!("")
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
value
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
@@ -109,13 +109,17 @@ module Datadog
|
|
|
109
109
|
@worker&.enabled = false
|
|
110
110
|
end
|
|
111
111
|
|
|
112
|
-
def start(initial_event_is_change = false)
|
|
112
|
+
def start(initial_event_is_change = false, components:)
|
|
113
113
|
return if !@enabled
|
|
114
114
|
|
|
115
115
|
initial_event = if initial_event_is_change
|
|
116
|
-
Event::SynthAppClientConfigurationChange.new(
|
|
116
|
+
Event::SynthAppClientConfigurationChange.new(
|
|
117
|
+
components: components,
|
|
118
|
+
)
|
|
117
119
|
else
|
|
118
|
-
Event::AppStarted.new(
|
|
120
|
+
Event::AppStarted.new(
|
|
121
|
+
components: components,
|
|
122
|
+
)
|
|
119
123
|
end
|
|
120
124
|
|
|
121
125
|
@worker.start(initial_event)
|