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
@@ -8,8 +8,12 @@ module Datadog
8
8
  module Event
9
9
  # Telemetry class for the 'app-started' event
10
10
  class AppStarted < Base
11
- def initialize(agent_settings:)
12
- @agent_settings = agent_settings
11
+ def initialize(components:)
12
+ # To not hold a reference to the component tree, generate
13
+ # the event payload here in the constructor.
14
+ @configuration = configuration(components.settings, components.agent_settings)
15
+ @install_signature = install_signature(components.settings)
16
+ @products = products(components)
13
17
  end
14
18
 
15
19
  def type
@@ -18,9 +22,9 @@ module Datadog
18
22
 
19
23
  def payload
20
24
  {
21
- products: products,
22
- configuration: configuration,
23
- install_signature: install_signature,
25
+ products: @products,
26
+ configuration: @configuration,
27
+ install_signature: @install_signature,
24
28
  # DEV: Not implemented yet
25
29
  # error: error, # Start-up errors
26
30
  }
@@ -28,17 +32,18 @@ module Datadog
28
32
 
29
33
  private
30
34
 
31
- def products
35
+ def products(components)
32
36
  # @type var products: Hash[Symbol, Hash[Symbol, Hash[Symbol, String | Integer] | bool | nil]]
33
37
  products = {
34
38
  appsec: {
35
- enabled: Datadog::AppSec.enabled?,
39
+ # TODO take appsec status out of component tree?
40
+ enabled: components.settings.appsec.enabled,
36
41
  },
37
42
  profiler: {
38
- enabled: Datadog::Profiling.enabled?,
43
+ enabled: !!components.profiler&.enabled?,
39
44
  },
40
45
  dynamic_instrumentation: {
41
- enabled: defined?(Datadog::DI) && Datadog::DI.respond_to?(:enabled?) && Datadog::DI.enabled?,
46
+ enabled: !!components.dynamic_instrumentation,
42
47
  }
43
48
  }
44
49
 
@@ -73,12 +78,11 @@ module Datadog
73
78
 
74
79
  # standard:disable Metrics/AbcSize
75
80
  # standard:disable Metrics/MethodLength
76
- def configuration
77
- config = Datadog.configuration
81
+ def configuration(settings, agent_settings)
78
82
  seq_id = Event.configuration_sequence.next
79
83
 
80
84
  # tracing.writer_options.buffer_size and tracing.writer_options.flush_interval have the same origin.
81
- writer_option_origin = get_telemetry_origin(config, 'tracing.writer_options')
85
+ writer_option_origin = get_telemetry_origin(settings, 'tracing.writer_options')
82
86
 
83
87
  list = [
84
88
  # Only set using env var as of June 2025
@@ -100,59 +104,59 @@ module Datadog
100
104
  ),
101
105
 
102
106
  # Mix of env var, programmatic and default config, so we use unknown
103
- conf_value('DD_AGENT_TRANSPORT', agent_transport, seq_id, 'unknown'), # rubocop:disable CustomCops/EnvStringValidationCop
107
+ conf_value('DD_AGENT_TRANSPORT', agent_transport(agent_settings), seq_id, 'unknown'), # rubocop:disable CustomCops/EnvStringValidationCop
104
108
 
105
109
  # writer_options is defined as an option that has a Hash value.
106
110
  conf_value(
107
111
  'tracing.writer_options.buffer_size',
108
- to_value(config.tracing.writer_options[:buffer_size]),
112
+ to_value(settings.tracing.writer_options[:buffer_size]),
109
113
  seq_id,
110
114
  writer_option_origin
111
115
  ),
112
116
  conf_value(
113
117
  'tracing.writer_options.flush_interval',
114
- to_value(config.tracing.writer_options[:flush_interval]),
118
+ to_value(settings.tracing.writer_options[:flush_interval]),
115
119
  seq_id,
116
120
  writer_option_origin
117
121
  ),
118
122
 
119
- conf_value('DD_AGENT_HOST', config.agent.host, seq_id, get_telemetry_origin(config, 'agent.host')),
123
+ conf_value('DD_AGENT_HOST', settings.agent.host, seq_id, get_telemetry_origin(settings, 'agent.host')),
120
124
  conf_value(
121
125
  'DD_TRACE_SAMPLE_RATE',
122
- to_value(config.tracing.sampling.default_rate),
126
+ to_value(settings.tracing.sampling.default_rate),
123
127
  seq_id,
124
- get_telemetry_origin(config, 'tracing.sampling.default_rate')
128
+ get_telemetry_origin(settings, 'tracing.sampling.default_rate')
125
129
  ),
126
130
  conf_value(
127
131
  'DD_TRACE_REMOVE_INTEGRATION_SERVICE_NAMES_ENABLED',
128
- config.tracing.contrib.global_default_service_name.enabled,
132
+ settings.tracing.contrib.global_default_service_name.enabled,
129
133
  seq_id,
130
- get_telemetry_origin(config, 'tracing.contrib.global_default_service_name.enabled')
134
+ get_telemetry_origin(settings, 'tracing.contrib.global_default_service_name.enabled')
131
135
  ),
132
136
  conf_value(
133
137
  'DD_TRACE_PEER_SERVICE_DEFAULTS_ENABLED',
134
- config.tracing.contrib.peer_service_defaults,
138
+ settings.tracing.contrib.peer_service_defaults,
135
139
  seq_id,
136
- get_telemetry_origin(config, 'tracing.contrib.peer_service_defaults')
140
+ get_telemetry_origin(settings, 'tracing.contrib.peer_service_defaults')
137
141
  ),
138
142
  conf_value(
139
143
  'DD_TRACE_DEBUG',
140
- config.diagnostics.debug,
144
+ settings.diagnostics.debug,
141
145
  seq_id,
142
- get_telemetry_origin(config, 'diagnostics.debug')
146
+ get_telemetry_origin(settings, 'diagnostics.debug')
143
147
  )
144
148
  ]
145
149
 
146
150
  peer_service_mapping_str = ''
147
- unless config.tracing.contrib.peer_service_mapping.empty?
148
- peer_service_mapping = config.tracing.contrib.peer_service_mapping
151
+ unless settings.tracing.contrib.peer_service_mapping.empty?
152
+ peer_service_mapping = settings.tracing.contrib.peer_service_mapping
149
153
  peer_service_mapping_str = peer_service_mapping.map { |key, value| "#{key}:#{value}" }.join(',')
150
154
  end
151
155
  list << conf_value(
152
156
  'DD_TRACE_PEER_SERVICE_MAPPING',
153
157
  peer_service_mapping_str,
154
158
  seq_id,
155
- get_telemetry_origin(config, 'tracing.contrib.peer_service_mapping')
159
+ get_telemetry_origin(settings, 'tracing.contrib.peer_service_mapping')
156
160
  )
157
161
 
158
162
  # Whitelist of configuration options to send in additional payload object
@@ -160,9 +164,9 @@ module Datadog
160
164
  split_option = option_path.split('.')
161
165
  list << conf_value(
162
166
  option_path,
163
- to_value(config.dig(*split_option)),
167
+ to_value(settings.dig(*split_option)),
164
168
  seq_id,
165
- get_telemetry_origin(config, option_path)
169
+ get_telemetry_origin(settings, option_path)
166
170
  )
167
171
  end
168
172
 
@@ -181,34 +185,34 @@ module Datadog
181
185
  )
182
186
 
183
187
  # Add some more custom additional payload values here
184
- if config.logger.instance
188
+ if settings.logger.instance
185
189
  list << conf_value(
186
190
  'logger.instance',
187
- config.logger.instance.class.to_s,
191
+ settings.logger.instance.class.to_s,
188
192
  seq_id,
189
- get_telemetry_origin(config, 'logger.instance')
193
+ get_telemetry_origin(settings, 'logger.instance')
190
194
  )
191
195
  end
192
- if config.respond_to?('appsec')
196
+ if settings.respond_to?('appsec')
193
197
  list << conf_value(
194
198
  'appsec.enabled',
195
- config.dig('appsec', 'enabled'),
199
+ settings.dig('appsec', 'enabled'),
196
200
  seq_id,
197
- get_telemetry_origin(config, 'appsec.enabled')
201
+ get_telemetry_origin(settings, 'appsec.enabled')
198
202
  )
199
203
  list << conf_value(
200
204
  'appsec.sca_enabled',
201
- config.dig('appsec', 'sca_enabled'),
205
+ settings.dig('appsec', 'sca_enabled'),
202
206
  seq_id,
203
- get_telemetry_origin(config, 'appsec.sca_enabled')
207
+ get_telemetry_origin(settings, 'appsec.sca_enabled')
204
208
  )
205
209
  end
206
- if config.respond_to?('ci')
210
+ if settings.respond_to?('ci')
207
211
  list << conf_value(
208
212
  'ci.enabled',
209
- config.dig('ci', 'enabled'),
213
+ settings.dig('ci', 'enabled'),
210
214
  seq_id,
211
- get_telemetry_origin(config, 'ci.enabled')
215
+ get_telemetry_origin(settings, 'ci.enabled')
212
216
  )
213
217
  end
214
218
 
@@ -218,8 +222,8 @@ module Datadog
218
222
  # standard:enable Metrics/AbcSize
219
223
  # standard:enable Metrics/MethodLength
220
224
 
221
- def agent_transport
222
- adapter = @agent_settings.adapter
225
+ def agent_transport(agent_settings)
226
+ adapter = agent_settings.adapter
223
227
  if adapter == Datadog::Core::Transport::Ext::UnixSocket::ADAPTER
224
228
  'UDS'
225
229
  else
@@ -260,23 +264,22 @@ module Datadog
260
264
  end
261
265
  end
262
266
 
263
- def install_signature
264
- config = Datadog.configuration
267
+ def install_signature(settings)
265
268
  {
266
- install_id: config.dig('telemetry', 'install_id'),
267
- install_type: config.dig('telemetry', 'install_type'),
268
- install_time: config.dig('telemetry', 'install_time'),
269
+ install_id: settings.dig('telemetry', 'install_id'),
270
+ install_type: settings.dig('telemetry', 'install_type'),
271
+ install_time: settings.dig('telemetry', 'install_time'),
269
272
  }
270
273
  end
271
274
 
272
- def get_telemetry_origin(config, config_path)
275
+ def get_telemetry_origin(settings, config_path)
273
276
  split_option = config_path.split('.')
274
277
  option_name = split_option.pop
275
278
  return 'unknown' if option_name.nil?
276
279
 
277
280
  # @type var parent_setting: Core::Configuration::Options
278
281
  # @type var option: Core::Configuration::Option
279
- parent_setting = config.dig(*split_option)
282
+ parent_setting = settings.dig(*split_option)
280
283
  option = parent_setting.send(:resolve_option, option_name.to_sym)
281
284
  option.precedence_set&.origin || 'unknown'
282
285
  end
@@ -33,7 +33,7 @@ module Datadog
33
33
 
34
34
  def payload
35
35
  {
36
- configuration: configuration,
36
+ configuration: @configuration,
37
37
  }
38
38
  end
39
39
  end
@@ -14,8 +14,8 @@ module Datadog
14
14
  # read: lib/datadog/core/telemetry/logging.rb
15
15
  module Logger
16
16
  class << self
17
- def report(exception, level: :error, description: nil, pii_safe: false)
18
- instance&.report(exception, level: level, description: description, pii_safe: pii_safe)
17
+ def report(exception, level: :error, description: nil)
18
+ instance&.report(exception, level: level, description: description)
19
19
  end
20
20
 
21
21
  def error(description)
@@ -45,17 +45,11 @@ module Datadog
45
45
  end
46
46
  end
47
47
 
48
- def report(exception, level: :error, description: nil, pii_safe: false)
48
+ def report(exception, level: :error, description: nil)
49
49
  # Anonymous exceptions to be logged as <Class:0x00007f8b1c0b3b40>
50
50
  message = +"#{exception.class.name || exception.class.inspect}" # standard:disable Style/RedundantInterpolation
51
51
 
52
- exception_message = pii_safe ? exception.message : nil
53
-
54
- if description || exception_message
55
- message << ':'
56
- message << " #{description}" if description
57
- message << " (#{exception.message})" if exception_message
58
- end
52
+ message << ": #{description}" if description
59
53
 
60
54
  event = Event::Log.new(
61
55
  message: message,
@@ -3,8 +3,8 @@
3
3
  require_relative '../../../transport/http/api/endpoint'
4
4
  require_relative '../../../transport/http/api/instance'
5
5
  require_relative '../../../transport/http/api/spec'
6
+ require_relative '../../../transport/http/client'
6
7
  require_relative '../../../transport/request'
7
- require_relative 'client'
8
8
 
9
9
  module Datadog
10
10
  module Core
@@ -12,10 +12,11 @@ module Datadog
12
12
  module Transport
13
13
  module HTTP
14
14
  module Telemetry
15
- module Client
15
+ class Client < Core::Transport::HTTP::Client
16
16
  def send_telemetry_payload(request)
17
- send_request(request) do |api, env| # steep:ignore
18
- api.send_telemetry(env)
17
+ send_request(request) do |api, env|
18
+ # TODO how to make api have the derived type for steep?
19
+ api.send_telemetry(env) # steep:ignore
19
20
  end
20
21
  end
21
22
  end
@@ -83,8 +84,6 @@ module Datadog
83
84
  end
84
85
  end
85
86
  end
86
-
87
- HTTP::Client.include(Telemetry::Client)
88
87
  end
89
88
  end
90
89
  end
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative '../../transport/parcel'
4
- require_relative 'http/client'
5
4
  require_relative 'http/telemetry'
6
5
 
7
6
  module Datadog
@@ -32,7 +31,7 @@ module Datadog
32
31
  @apis = apis
33
32
  @logger = logger
34
33
 
35
- @client = HTTP::Client.new(@apis[default_api], logger: logger)
34
+ @client = Core::Telemetry::Transport::HTTP::Telemetry::Client.new(@apis[default_api], logger: logger)
36
35
  end
37
36
 
38
37
  def send_telemetry(request_type:, payload:)
@@ -0,0 +1,69 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'env'
4
+ require_relative '../response'
5
+
6
+ module Datadog
7
+ module Core
8
+ module Transport
9
+ module HTTP
10
+ # Routes, encodes, and sends DI data to the trace agent via HTTP.
11
+ #
12
+ # @api private
13
+ class Client
14
+ attr_reader :api, :logger
15
+
16
+ def initialize(api, logger:)
17
+ @api = api
18
+ @logger = logger
19
+ end
20
+
21
+ private
22
+
23
+ def send_request(request, &block)
24
+ # Build request into env
25
+ env = build_env(request)
26
+
27
+ # Get responses from API
28
+ yield(api, env).tap do |response|
29
+ on_response(response)
30
+ end
31
+ rescue => exception
32
+ on_exception(exception)
33
+
34
+ Datadog::Core::Transport::InternalErrorResponse.new(exception)
35
+ end
36
+
37
+ def build_env(request)
38
+ Datadog::Core::Transport::HTTP::Env.new(request)
39
+ end
40
+
41
+ # Callback that is invoked if a request did not raise an exception
42
+ # (but did not necessarily complete successfully).
43
+ #
44
+ # Override in subclasses.
45
+ #
46
+ # Note that the client will return the original response -
47
+ # the return value of this method is ignored, and response should
48
+ # not be modified.
49
+ def on_response(response)
50
+ end
51
+
52
+ # Callback that is invoked if a request failed with an exception.
53
+ #
54
+ # Override in subclasses.
55
+ def on_exception(exception)
56
+ message = build_exception_message(exception)
57
+
58
+ logger.debug(message)
59
+ end
60
+
61
+ def build_exception_message(exception)
62
+ "Internal error during #{self.class.name} request. Cause: #{exception.class}: #{exception} " \
63
+ "Location: #{Array(exception.backtrace).first}"
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end
69
+ 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 AppSec
7
- module APISecurity
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 store(key, value)
34
- return @store[key] = value if @store.delete(key)
35
-
36
- # NOTE: evict the oldest entry if store reached the maximum allowed size
37
- @store.shift if @store.size >= @max_size
38
- @store[key] = value
39
- end
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 = 0)
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
@@ -71,7 +75,7 @@ module Datadog
71
75
  end
72
76
 
73
77
  def limited?
74
- !@limit.nil? && @limit.positive?
78
+ !@limit.nil?
75
79
  end
76
80
 
77
81
  def reset_ran_once_state_for_tests
@@ -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
@@ -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,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'configuration/settings'
4
+
5
+ module Datadog
6
+ module DataStreams
7
+ # Configuration for Data Streams Monitoring
8
+ module Configuration
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Datadog
4
+ module DataStreams
5
+ # Constants for Data Streams Monitoring configuration
6
+ # @public_api
7
+ module Ext
8
+ ENV_ENABLED = 'DD_DATA_STREAMS_ENABLED'
9
+ end
10
+ end
11
+ 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