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.
Files changed (152) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +59 -2
  3. data/ext/LIBDATADOG_DEVELOPMENT.md +1 -58
  4. data/ext/datadog_profiling_native_extension/collectors_stack.c +4 -0
  5. data/ext/datadog_profiling_native_extension/datadog_ruby_common.h +1 -1
  6. data/ext/datadog_profiling_native_extension/extconf.rb +6 -4
  7. data/ext/datadog_profiling_native_extension/heap_recorder.c +1 -1
  8. data/ext/libdatadog_api/datadog_ruby_common.h +1 -1
  9. data/ext/libdatadog_api/feature_flags.c +554 -0
  10. data/ext/libdatadog_api/feature_flags.h +5 -0
  11. data/ext/libdatadog_api/init.c +2 -0
  12. data/ext/libdatadog_api/library_config.c +12 -11
  13. data/ext/libdatadog_extconf_helpers.rb +1 -1
  14. data/lib/datadog/appsec/api_security/route_extractor.rb +23 -6
  15. data/lib/datadog/appsec/api_security/sampler.rb +7 -4
  16. data/lib/datadog/appsec/assets/blocked.html +8 -0
  17. data/lib/datadog/appsec/assets/blocked.json +1 -1
  18. data/lib/datadog/appsec/assets/blocked.text +3 -1
  19. data/lib/datadog/appsec/assets.rb +1 -1
  20. data/lib/datadog/appsec/remote.rb +4 -0
  21. data/lib/datadog/appsec/response.rb +18 -4
  22. data/lib/datadog/core/configuration/components.rb +30 -3
  23. data/lib/datadog/core/configuration/config_helper.rb +1 -1
  24. data/lib/datadog/core/configuration/settings.rb +14 -0
  25. data/lib/datadog/core/configuration/supported_configurations.rb +330 -301
  26. data/lib/datadog/core/ddsketch.rb +0 -2
  27. data/lib/datadog/core/environment/ext.rb +6 -0
  28. data/lib/datadog/core/environment/process.rb +79 -0
  29. data/lib/datadog/core/feature_flags.rb +61 -0
  30. data/lib/datadog/core/remote/client/capabilities.rb +7 -0
  31. data/lib/datadog/core/remote/transport/config.rb +2 -10
  32. data/lib/datadog/core/remote/transport/http/config.rb +9 -9
  33. data/lib/datadog/core/remote/transport/http/negotiation.rb +17 -8
  34. data/lib/datadog/core/remote/transport/http.rb +2 -0
  35. data/lib/datadog/core/remote/transport/negotiation.rb +2 -18
  36. data/lib/datadog/core/remote/worker.rb +25 -37
  37. data/lib/datadog/core/tag_builder.rb +0 -4
  38. data/lib/datadog/core/tag_normalizer.rb +84 -0
  39. data/lib/datadog/core/telemetry/component.rb +7 -3
  40. data/lib/datadog/core/telemetry/event/app_started.rb +52 -49
  41. data/lib/datadog/core/telemetry/event/synth_app_client_configuration_change.rb +1 -1
  42. data/lib/datadog/core/telemetry/logger.rb +2 -2
  43. data/lib/datadog/core/telemetry/logging.rb +2 -8
  44. data/lib/datadog/core/telemetry/transport/http/telemetry.rb +5 -6
  45. data/lib/datadog/core/telemetry/transport/telemetry.rb +1 -2
  46. data/lib/datadog/core/transport/http/client.rb +69 -0
  47. data/lib/datadog/core/utils/array.rb +29 -0
  48. data/lib/datadog/{appsec/api_security → core/utils}/lru_cache.rb +10 -21
  49. data/lib/datadog/core/utils/network.rb +3 -1
  50. data/lib/datadog/core/utils/only_once_successful.rb +6 -2
  51. data/lib/datadog/core/utils.rb +2 -0
  52. data/lib/datadog/data_streams/configuration/settings.rb +49 -0
  53. data/lib/datadog/data_streams/configuration.rb +11 -0
  54. data/lib/datadog/data_streams/ext.rb +11 -0
  55. data/lib/datadog/data_streams/extensions.rb +16 -0
  56. data/lib/datadog/data_streams/pathway_context.rb +169 -0
  57. data/lib/datadog/data_streams/processor.rb +509 -0
  58. data/lib/datadog/data_streams/transport/http/api.rb +33 -0
  59. data/lib/datadog/data_streams/transport/http/client.rb +21 -0
  60. data/lib/datadog/data_streams/transport/http/stats.rb +87 -0
  61. data/lib/datadog/data_streams/transport/http.rb +41 -0
  62. data/lib/datadog/data_streams/transport/stats.rb +60 -0
  63. data/lib/datadog/data_streams.rb +100 -0
  64. data/lib/datadog/di/component.rb +0 -16
  65. data/lib/datadog/di/el/evaluator.rb +1 -1
  66. data/lib/datadog/di/error.rb +4 -0
  67. data/lib/datadog/di/instrumenter.rb +76 -30
  68. data/lib/datadog/di/probe.rb +20 -0
  69. data/lib/datadog/di/probe_manager.rb +10 -2
  70. data/lib/datadog/di/probe_notification_builder.rb +62 -23
  71. data/lib/datadog/di/proc_responder.rb +32 -0
  72. data/lib/datadog/di/transport/diagnostics.rb +2 -2
  73. data/lib/datadog/di/transport/http/diagnostics.rb +2 -4
  74. data/lib/datadog/di/transport/http/input.rb +2 -4
  75. data/lib/datadog/di/transport/http.rb +6 -2
  76. data/lib/datadog/di/transport/input.rb +64 -4
  77. data/lib/datadog/open_feature/component.rb +60 -0
  78. data/lib/datadog/open_feature/configuration.rb +27 -0
  79. data/lib/datadog/open_feature/evaluation_engine.rb +69 -0
  80. data/lib/datadog/open_feature/exposures/batch_builder.rb +32 -0
  81. data/lib/datadog/open_feature/exposures/buffer.rb +43 -0
  82. data/lib/datadog/open_feature/exposures/deduplicator.rb +30 -0
  83. data/lib/datadog/open_feature/exposures/event.rb +60 -0
  84. data/lib/datadog/open_feature/exposures/reporter.rb +40 -0
  85. data/lib/datadog/open_feature/exposures/worker.rb +116 -0
  86. data/lib/datadog/open_feature/ext.rb +14 -0
  87. data/lib/datadog/open_feature/native_evaluator.rb +38 -0
  88. data/lib/datadog/open_feature/noop_evaluator.rb +26 -0
  89. data/lib/datadog/open_feature/provider.rb +141 -0
  90. data/lib/datadog/open_feature/remote.rb +74 -0
  91. data/lib/datadog/open_feature/resolution_details.rb +35 -0
  92. data/lib/datadog/open_feature/transport.rb +72 -0
  93. data/lib/datadog/open_feature.rb +19 -0
  94. data/lib/datadog/opentelemetry/configuration/settings.rb +159 -0
  95. data/lib/datadog/opentelemetry/metrics.rb +110 -0
  96. data/lib/datadog/opentelemetry/sdk/configurator.rb +25 -1
  97. data/lib/datadog/opentelemetry/sdk/metrics_exporter.rb +38 -0
  98. data/lib/datadog/opentelemetry.rb +3 -0
  99. data/lib/datadog/profiling/collectors/code_provenance.rb +15 -6
  100. data/lib/datadog/profiling/collectors/cpu_and_wall_time_worker.rb +1 -1
  101. data/lib/datadog/profiling/collectors/idle_sampling_helper.rb +1 -1
  102. data/lib/datadog/profiling/profiler.rb +4 -0
  103. data/lib/datadog/profiling/tag_builder.rb +36 -3
  104. data/lib/datadog/profiling.rb +1 -2
  105. data/lib/datadog/single_step_instrument.rb +1 -1
  106. data/lib/datadog/tracing/configuration/ext.rb +9 -0
  107. data/lib/datadog/tracing/configuration/settings.rb +74 -0
  108. data/lib/datadog/tracing/contrib/action_pack/action_controller/instrumentation.rb +4 -4
  109. data/lib/datadog/tracing/contrib/action_pack/utils.rb +1 -2
  110. data/lib/datadog/tracing/contrib/active_job/log_injection.rb +21 -7
  111. data/lib/datadog/tracing/contrib/active_job/patcher.rb +5 -1
  112. data/lib/datadog/tracing/contrib/aws/instrumentation.rb +4 -2
  113. data/lib/datadog/tracing/contrib/ethon/easy_patch.rb +4 -1
  114. data/lib/datadog/tracing/contrib/excon/configuration/settings.rb +11 -3
  115. data/lib/datadog/tracing/contrib/faraday/configuration/settings.rb +11 -7
  116. data/lib/datadog/tracing/contrib/grape/configuration/settings.rb +7 -3
  117. data/lib/datadog/tracing/contrib/graphql/unified_trace.rb +22 -17
  118. data/lib/datadog/tracing/contrib/http/configuration/settings.rb +11 -3
  119. data/lib/datadog/tracing/contrib/httpclient/configuration/settings.rb +11 -3
  120. data/lib/datadog/tracing/contrib/httprb/configuration/settings.rb +11 -3
  121. data/lib/datadog/tracing/contrib/kafka/instrumentation/consumer.rb +66 -0
  122. data/lib/datadog/tracing/contrib/kafka/instrumentation/producer.rb +66 -0
  123. data/lib/datadog/tracing/contrib/kafka/patcher.rb +14 -0
  124. data/lib/datadog/tracing/contrib/karafka/framework.rb +30 -0
  125. data/lib/datadog/tracing/contrib/karafka/monitor.rb +11 -0
  126. data/lib/datadog/tracing/contrib/karafka/patcher.rb +32 -0
  127. data/lib/datadog/tracing/contrib/rack/middlewares.rb +59 -27
  128. data/lib/datadog/tracing/contrib/rack/route_inference.rb +53 -0
  129. data/lib/datadog/tracing/contrib/rails/middlewares.rb +2 -2
  130. data/lib/datadog/tracing/contrib/rest_client/request_patch.rb +4 -1
  131. data/lib/datadog/tracing/contrib/roda/instrumentation.rb +3 -1
  132. data/lib/datadog/tracing/contrib/sinatra/tracer_middleware.rb +3 -1
  133. data/lib/datadog/tracing/contrib/status_range_matcher.rb +7 -0
  134. data/lib/datadog/tracing/contrib/waterdrop/configuration/settings.rb +27 -0
  135. data/lib/datadog/tracing/contrib/waterdrop/distributed/propagation.rb +48 -0
  136. data/lib/datadog/tracing/contrib/waterdrop/ext.rb +17 -0
  137. data/lib/datadog/tracing/contrib/waterdrop/integration.rb +43 -0
  138. data/lib/datadog/tracing/contrib/waterdrop/middleware.rb +46 -0
  139. data/lib/datadog/tracing/contrib/waterdrop/patcher.rb +46 -0
  140. data/lib/datadog/tracing/contrib/waterdrop/producer.rb +50 -0
  141. data/lib/datadog/tracing/contrib/waterdrop.rb +37 -0
  142. data/lib/datadog/tracing/contrib.rb +1 -0
  143. data/lib/datadog/tracing/metadata/ext.rb +1 -1
  144. data/lib/datadog/tracing/transport/http/client.rb +12 -26
  145. data/lib/datadog/tracing/transport/trace_formatter.rb +11 -0
  146. data/lib/datadog/tracing/transport/traces.rb +3 -5
  147. data/lib/datadog/version.rb +2 -2
  148. data/lib/datadog.rb +2 -0
  149. metadata +78 -15
  150. data/lib/datadog/core/remote/transport/http/client.rb +0 -49
  151. data/lib/datadog/core/telemetry/transport/http/client.rb +0 -49
  152. data/lib/datadog/di/transport/http/client.rb +0 -47
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'datadog/core'
4
-
5
3
  module Datadog
6
4
  module Core
7
5
  # Used to access ddsketch APIs.
@@ -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 '../config'
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
- # Extensions for HTTP client
178
- module Client
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 '../negotiation'
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
- # Extensions for HTTP client
35
- module Client
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 { 'remote worker starting' }
26
+ logger.debug { "remote worker starting (pid: #{Process.pid})" }
27
27
 
28
- acquire_lock
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
- if @stopped
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
- @starting = true
36
+ @starting = true
38
37
 
39
- thread = Thread.new { poll(@interval) }
40
- thread.name = self.class.name
41
- thread.thread_variable_set(:fork_safe, true)
42
- @thr = thread
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
- @started = true
45
- @starting = false
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 { 'remote worker stopping' }
51
+ logger.debug { "remote worker stopping (pid: #{Process.pid})" }
54
52
 
55
- acquire_lock
53
+ @mutex.synchronize do
54
+ thread = @thr
56
55
 
57
- thread = @thr
56
+ if thread
57
+ thread.kill
58
+ thread.join
59
+ end
58
60
 
59
- if thread
60
- thread.kill
61
- thread.join
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(agent_settings: @agent_settings)
116
+ Event::SynthAppClientConfigurationChange.new(
117
+ components: components,
118
+ )
117
119
  else
118
- Event::AppStarted.new(agent_settings: @agent_settings)
120
+ Event::AppStarted.new(
121
+ components: components,
122
+ )
119
123
  end
120
124
 
121
125
  @worker.start(initial_event)