datadog 2.21.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 (205) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +106 -2
  3. data/ext/LIBDATADOG_DEVELOPMENT.md +3 -0
  4. data/ext/datadog_profiling_native_extension/collectors_discrete_dynamic_sampler.c +1 -1
  5. data/ext/datadog_profiling_native_extension/collectors_stack.c +4 -0
  6. data/ext/datadog_profiling_native_extension/datadog_ruby_common.h +1 -1
  7. data/ext/datadog_profiling_native_extension/extconf.rb +6 -4
  8. data/ext/datadog_profiling_native_extension/heap_recorder.c +1 -1
  9. data/ext/libdatadog_api/datadog_ruby_common.h +1 -1
  10. data/ext/libdatadog_api/ddsketch.c +106 -0
  11. data/ext/libdatadog_api/feature_flags.c +554 -0
  12. data/ext/libdatadog_api/feature_flags.h +5 -0
  13. data/ext/libdatadog_api/init.c +5 -0
  14. data/ext/libdatadog_api/library_config.c +34 -25
  15. data/ext/libdatadog_api/process_discovery.c +19 -13
  16. data/ext/libdatadog_extconf_helpers.rb +1 -1
  17. data/lib/datadog/appsec/api_security/endpoint_collection/grape_route_serializer.rb +26 -0
  18. data/lib/datadog/appsec/api_security/endpoint_collection/rails_collector.rb +59 -0
  19. data/lib/datadog/appsec/api_security/endpoint_collection/rails_route_serializer.rb +29 -0
  20. data/lib/datadog/appsec/api_security/endpoint_collection/sinatra_route_serializer.rb +26 -0
  21. data/lib/datadog/appsec/api_security/endpoint_collection.rb +10 -0
  22. data/lib/datadog/appsec/api_security/route_extractor.rb +23 -6
  23. data/lib/datadog/appsec/api_security/sampler.rb +7 -4
  24. data/lib/datadog/appsec/assets/blocked.html +8 -0
  25. data/lib/datadog/appsec/assets/blocked.json +1 -1
  26. data/lib/datadog/appsec/assets/blocked.text +3 -1
  27. data/lib/datadog/appsec/assets/waf_rules/README.md +30 -36
  28. data/lib/datadog/appsec/assets/waf_rules/recommended.json +359 -4
  29. data/lib/datadog/appsec/assets/waf_rules/strict.json +43 -2
  30. data/lib/datadog/appsec/assets.rb +1 -1
  31. data/lib/datadog/appsec/compressed_json.rb +1 -1
  32. data/lib/datadog/appsec/configuration/settings.rb +9 -0
  33. data/lib/datadog/appsec/contrib/active_record/instrumentation.rb +3 -1
  34. data/lib/datadog/appsec/contrib/excon/ssrf_detection_middleware.rb +3 -2
  35. data/lib/datadog/appsec/contrib/faraday/ssrf_detection_middleware.rb +3 -1
  36. data/lib/datadog/appsec/contrib/graphql/gateway/watcher.rb +3 -1
  37. data/lib/datadog/appsec/contrib/rack/gateway/watcher.rb +9 -4
  38. data/lib/datadog/appsec/contrib/rack/request_middleware.rb +5 -1
  39. data/lib/datadog/appsec/contrib/rails/gateway/watcher.rb +7 -2
  40. data/lib/datadog/appsec/contrib/rails/patcher.rb +30 -0
  41. data/lib/datadog/appsec/contrib/rest_client/request_ssrf_detection_patch.rb +3 -1
  42. data/lib/datadog/appsec/contrib/sinatra/gateway/watcher.rb +10 -4
  43. data/lib/datadog/appsec/event.rb +12 -14
  44. data/lib/datadog/appsec/metrics/collector.rb +19 -3
  45. data/lib/datadog/appsec/metrics/telemetry_exporter.rb +2 -1
  46. data/lib/datadog/appsec/monitor/gateway/watcher.rb +4 -4
  47. data/lib/datadog/appsec/remote.rb +29 -13
  48. data/lib/datadog/appsec/response.rb +18 -4
  49. data/lib/datadog/appsec/security_engine/result.rb +28 -9
  50. data/lib/datadog/appsec/security_engine/runner.rb +17 -7
  51. data/lib/datadog/appsec/security_event.rb +5 -7
  52. data/lib/datadog/core/configuration/components.rb +44 -9
  53. data/lib/datadog/core/configuration/config_helper.rb +1 -1
  54. data/lib/datadog/core/configuration/settings.rb +14 -0
  55. data/lib/datadog/core/configuration/stable_config.rb +10 -0
  56. data/lib/datadog/core/configuration/supported_configurations.rb +330 -299
  57. data/lib/datadog/core/configuration.rb +1 -1
  58. data/lib/datadog/core/ddsketch.rb +19 -0
  59. data/lib/datadog/core/environment/ext.rb +6 -0
  60. data/lib/datadog/core/environment/process.rb +79 -0
  61. data/lib/datadog/core/environment/yjit.rb +2 -1
  62. data/lib/datadog/core/feature_flags.rb +61 -0
  63. data/lib/datadog/core/pin.rb +4 -8
  64. data/lib/datadog/core/process_discovery.rb +4 -2
  65. data/lib/datadog/core/remote/client/capabilities.rb +7 -0
  66. data/lib/datadog/core/remote/component.rb +4 -6
  67. data/lib/datadog/core/remote/transport/config.rb +2 -10
  68. data/lib/datadog/core/remote/transport/http/config.rb +9 -9
  69. data/lib/datadog/core/remote/transport/http/negotiation.rb +17 -8
  70. data/lib/datadog/core/remote/transport/http.rb +2 -0
  71. data/lib/datadog/core/remote/transport/negotiation.rb +2 -18
  72. data/lib/datadog/core/remote/worker.rb +25 -37
  73. data/lib/datadog/core/tag_builder.rb +0 -4
  74. data/lib/datadog/core/tag_normalizer.rb +84 -0
  75. data/lib/datadog/core/telemetry/component.rb +18 -3
  76. data/lib/datadog/core/telemetry/emitter.rb +6 -6
  77. data/lib/datadog/core/telemetry/event/app_endpoints_loaded.rb +30 -0
  78. data/lib/datadog/core/telemetry/event/app_started.rb +52 -49
  79. data/lib/datadog/core/telemetry/event/synth_app_client_configuration_change.rb +1 -1
  80. data/lib/datadog/core/telemetry/event.rb +1 -0
  81. data/lib/datadog/core/telemetry/logger.rb +2 -2
  82. data/lib/datadog/core/telemetry/logging.rb +2 -8
  83. data/lib/datadog/core/telemetry/transport/http/telemetry.rb +5 -6
  84. data/lib/datadog/core/telemetry/transport/telemetry.rb +1 -2
  85. data/lib/datadog/core/transport/http/client.rb +69 -0
  86. data/lib/datadog/core/transport/response.rb +4 -1
  87. data/lib/datadog/core/utils/array.rb +29 -0
  88. data/lib/datadog/{appsec/api_security → core/utils}/lru_cache.rb +10 -21
  89. data/lib/datadog/core/utils/network.rb +22 -1
  90. data/lib/datadog/core/utils/only_once_successful.rb +6 -2
  91. data/lib/datadog/core/utils.rb +2 -0
  92. data/lib/datadog/data_streams/configuration/settings.rb +49 -0
  93. data/lib/datadog/data_streams/configuration.rb +11 -0
  94. data/lib/datadog/data_streams/ext.rb +11 -0
  95. data/lib/datadog/data_streams/extensions.rb +16 -0
  96. data/lib/datadog/data_streams/pathway_context.rb +169 -0
  97. data/lib/datadog/data_streams/processor.rb +509 -0
  98. data/lib/datadog/data_streams/transport/http/api.rb +33 -0
  99. data/lib/datadog/data_streams/transport/http/client.rb +21 -0
  100. data/lib/datadog/data_streams/transport/http/stats.rb +87 -0
  101. data/lib/datadog/data_streams/transport/http.rb +41 -0
  102. data/lib/datadog/data_streams/transport/stats.rb +60 -0
  103. data/lib/datadog/data_streams.rb +100 -0
  104. data/lib/datadog/di/boot.rb +1 -0
  105. data/lib/datadog/di/component.rb +14 -16
  106. data/lib/datadog/di/context.rb +70 -0
  107. data/lib/datadog/di/el/compiler.rb +164 -0
  108. data/lib/datadog/di/el/evaluator.rb +159 -0
  109. data/lib/datadog/di/el/expression.rb +42 -0
  110. data/lib/datadog/di/el.rb +5 -0
  111. data/lib/datadog/di/error.rb +29 -0
  112. data/lib/datadog/di/instrumenter.rb +163 -48
  113. data/lib/datadog/di/probe.rb +55 -15
  114. data/lib/datadog/di/probe_builder.rb +39 -1
  115. data/lib/datadog/di/probe_manager.rb +13 -4
  116. data/lib/datadog/di/probe_notification_builder.rb +105 -67
  117. data/lib/datadog/di/proc_responder.rb +32 -0
  118. data/lib/datadog/di/serializer.rb +151 -7
  119. data/lib/datadog/di/transport/diagnostics.rb +2 -2
  120. data/lib/datadog/di/transport/http/diagnostics.rb +2 -4
  121. data/lib/datadog/di/transport/http/input.rb +2 -4
  122. data/lib/datadog/di/transport/http.rb +6 -2
  123. data/lib/datadog/di/transport/input.rb +64 -4
  124. data/lib/datadog/open_feature/component.rb +60 -0
  125. data/lib/datadog/open_feature/configuration.rb +27 -0
  126. data/lib/datadog/open_feature/evaluation_engine.rb +69 -0
  127. data/lib/datadog/open_feature/exposures/batch_builder.rb +32 -0
  128. data/lib/datadog/open_feature/exposures/buffer.rb +43 -0
  129. data/lib/datadog/open_feature/exposures/deduplicator.rb +30 -0
  130. data/lib/datadog/open_feature/exposures/event.rb +60 -0
  131. data/lib/datadog/open_feature/exposures/reporter.rb +40 -0
  132. data/lib/datadog/open_feature/exposures/worker.rb +116 -0
  133. data/lib/datadog/open_feature/ext.rb +14 -0
  134. data/lib/datadog/open_feature/native_evaluator.rb +38 -0
  135. data/lib/datadog/open_feature/noop_evaluator.rb +26 -0
  136. data/lib/datadog/open_feature/provider.rb +141 -0
  137. data/lib/datadog/open_feature/remote.rb +74 -0
  138. data/lib/datadog/open_feature/resolution_details.rb +35 -0
  139. data/lib/datadog/open_feature/transport.rb +72 -0
  140. data/lib/datadog/open_feature.rb +19 -0
  141. data/lib/datadog/opentelemetry/configuration/settings.rb +159 -0
  142. data/lib/datadog/opentelemetry/metrics.rb +110 -0
  143. data/lib/datadog/opentelemetry/sdk/configurator.rb +25 -1
  144. data/lib/datadog/opentelemetry/sdk/metrics_exporter.rb +38 -0
  145. data/lib/datadog/opentelemetry.rb +3 -0
  146. data/lib/datadog/profiling/collectors/code_provenance.rb +15 -6
  147. data/lib/datadog/profiling/collectors/cpu_and_wall_time_worker.rb +1 -1
  148. data/lib/datadog/profiling/collectors/idle_sampling_helper.rb +1 -1
  149. data/lib/datadog/profiling/profiler.rb +4 -0
  150. data/lib/datadog/profiling/tag_builder.rb +36 -3
  151. data/lib/datadog/profiling.rb +1 -2
  152. data/lib/datadog/single_step_instrument.rb +1 -1
  153. data/lib/datadog/tracing/component.rb +6 -17
  154. data/lib/datadog/tracing/configuration/dynamic.rb +2 -2
  155. data/lib/datadog/tracing/configuration/ext.rb +9 -0
  156. data/lib/datadog/tracing/configuration/settings.rb +77 -3
  157. data/lib/datadog/tracing/contrib/action_pack/action_controller/instrumentation.rb +4 -4
  158. data/lib/datadog/tracing/contrib/action_pack/utils.rb +1 -2
  159. data/lib/datadog/tracing/contrib/active_job/log_injection.rb +21 -7
  160. data/lib/datadog/tracing/contrib/active_job/patcher.rb +5 -1
  161. data/lib/datadog/tracing/contrib/aws/instrumentation.rb +4 -2
  162. data/lib/datadog/tracing/contrib/component.rb +2 -2
  163. data/lib/datadog/tracing/contrib/ethon/easy_patch.rb +4 -1
  164. data/lib/datadog/tracing/contrib/excon/configuration/settings.rb +11 -3
  165. data/lib/datadog/tracing/contrib/faraday/configuration/settings.rb +11 -7
  166. data/lib/datadog/tracing/contrib/grape/configuration/settings.rb +7 -3
  167. data/lib/datadog/tracing/contrib/graphql/configuration/settings.rb +7 -0
  168. data/lib/datadog/tracing/contrib/graphql/ext.rb +1 -0
  169. data/lib/datadog/tracing/contrib/graphql/unified_trace.rb +74 -44
  170. data/lib/datadog/tracing/contrib/http/configuration/settings.rb +11 -3
  171. data/lib/datadog/tracing/contrib/httpclient/configuration/settings.rb +11 -3
  172. data/lib/datadog/tracing/contrib/httprb/configuration/settings.rb +11 -3
  173. data/lib/datadog/tracing/contrib/kafka/instrumentation/consumer.rb +66 -0
  174. data/lib/datadog/tracing/contrib/kafka/instrumentation/producer.rb +66 -0
  175. data/lib/datadog/tracing/contrib/kafka/patcher.rb +14 -0
  176. data/lib/datadog/tracing/contrib/karafka/framework.rb +30 -0
  177. data/lib/datadog/tracing/contrib/karafka/monitor.rb +11 -0
  178. data/lib/datadog/tracing/contrib/karafka/patcher.rb +32 -0
  179. data/lib/datadog/tracing/contrib/rack/middlewares.rb +59 -27
  180. data/lib/datadog/tracing/contrib/rack/route_inference.rb +53 -0
  181. data/lib/datadog/tracing/contrib/rails/middlewares.rb +2 -2
  182. data/lib/datadog/tracing/contrib/rest_client/request_patch.rb +4 -1
  183. data/lib/datadog/tracing/contrib/roda/instrumentation.rb +3 -1
  184. data/lib/datadog/tracing/contrib/sinatra/tracer_middleware.rb +3 -1
  185. data/lib/datadog/tracing/contrib/status_range_matcher.rb +7 -0
  186. data/lib/datadog/tracing/contrib/waterdrop/configuration/settings.rb +27 -0
  187. data/lib/datadog/tracing/contrib/waterdrop/distributed/propagation.rb +48 -0
  188. data/lib/datadog/tracing/contrib/waterdrop/ext.rb +17 -0
  189. data/lib/datadog/tracing/contrib/waterdrop/integration.rb +43 -0
  190. data/lib/datadog/tracing/contrib/waterdrop/middleware.rb +46 -0
  191. data/lib/datadog/tracing/contrib/waterdrop/patcher.rb +46 -0
  192. data/lib/datadog/tracing/contrib/waterdrop/producer.rb +50 -0
  193. data/lib/datadog/tracing/contrib/waterdrop.rb +37 -0
  194. data/lib/datadog/tracing/contrib.rb +1 -0
  195. data/lib/datadog/tracing/metadata/ext.rb +9 -1
  196. data/lib/datadog/tracing/transport/http/client.rb +12 -26
  197. data/lib/datadog/tracing/transport/trace_formatter.rb +11 -0
  198. data/lib/datadog/tracing/transport/traces.rb +3 -5
  199. data/lib/datadog/version.rb +2 -2
  200. data/lib/datadog.rb +2 -0
  201. metadata +92 -16
  202. data/ext/libdatadog_api/macos_development.md +0 -26
  203. data/lib/datadog/core/remote/transport/http/client.rb +0 -49
  204. data/lib/datadog/core/telemetry/transport/http/client.rb +0 -49
  205. data/lib/datadog/di/transport/http/client.rb +0 -47
@@ -19,6 +19,8 @@ module Datadog
19
19
  #
20
20
  # @api private
21
21
  class Component
22
+ ENDPOINT_COLLECTION_MESSAGE_LIMIT = 300
23
+
22
24
  attr_reader :enabled, :logger, :transport, :worker
23
25
 
24
26
  include Core::Utils::Forking
@@ -107,13 +109,17 @@ module Datadog
107
109
  @worker&.enabled = false
108
110
  end
109
111
 
110
- def start(initial_event_is_change = false)
112
+ def start(initial_event_is_change = false, components:)
111
113
  return if !@enabled
112
114
 
113
115
  initial_event = if initial_event_is_change
114
- Event::SynthAppClientConfigurationChange.new(agent_settings: @agent_settings)
116
+ Event::SynthAppClientConfigurationChange.new(
117
+ components: components,
118
+ )
115
119
  else
116
- Event::AppStarted.new(agent_settings: @agent_settings)
120
+ Event::AppStarted.new(
121
+ components: components,
122
+ )
117
123
  end
118
124
 
119
125
  @worker.start(initial_event)
@@ -165,6 +171,15 @@ module Datadog
165
171
  @worker.enqueue(Event::AppClientConfigurationChange.new(changes, 'remote_config'))
166
172
  end
167
173
 
174
+ # Report application endpoints
175
+ def app_endpoints_loaded(endpoints, page_size: ENDPOINT_COLLECTION_MESSAGE_LIMIT)
176
+ return if !@enabled || forked?
177
+
178
+ endpoints.each_slice(page_size).with_index do |endpoints_slice, i|
179
+ @worker.enqueue(Event::AppEndpointsLoaded.new(endpoints_slice, is_first: i.zero?))
180
+ end
181
+ end
182
+
168
183
  # Increments a count metric.
169
184
  def inc(namespace, metric_name, value, tags: {}, common: true)
170
185
  @metrics_manager.inc(namespace, metric_name, value, tags: tags, common: common)
@@ -31,15 +31,15 @@ module Datadog
31
31
  seq_id = self.class.sequence.next
32
32
  payload = Request.build_payload(event, seq_id, debug: debug?)
33
33
  res = @transport.send_telemetry(request_type: event.type, payload: payload)
34
- logger.debug { "Telemetry sent for event `#{event.type}` (response code: #{res.code})" }
34
+ if res.ok?
35
+ logger.debug { "Telemetry sent for event `#{event.type}`" }
36
+ else
37
+ logger.debug { "Failed to send telemetry for event `#{event.type}`: #{res.inspect}" }
38
+ end
35
39
  res
36
40
  rescue => e
37
41
  logger.debug {
38
- "Unable to send telemetry request for event `#{begin
39
- event.type
40
- rescue
41
- "unknown"
42
- end}`: #{e}"
42
+ "Unable to send telemetry request for event `#{event.respond_to?(:type) ? event.type : event.to_s}`: #{e.class}: #{e}"
43
43
  }
44
44
  Core::Transport::InternalErrorResponse.new(e)
45
45
  end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'base'
4
+
5
+ module Datadog
6
+ module Core
7
+ module Telemetry
8
+ module Event
9
+ # Telemetry event class for sending 'app-endpoints' payload
10
+ class AppEndpointsLoaded < Base
11
+ def initialize(endpoints, is_first:)
12
+ @endpoints = endpoints
13
+ @is_first = !!is_first
14
+ end
15
+
16
+ def type
17
+ 'app-endpoints'
18
+ end
19
+
20
+ def payload
21
+ {
22
+ is_first: @is_first,
23
+ endpoints: @endpoints
24
+ }
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -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
@@ -26,6 +26,7 @@ require_relative 'event/base'
26
26
  require_relative 'event/app_client_configuration_change'
27
27
  require_relative 'event/app_closing'
28
28
  require_relative 'event/app_dependencies_loaded'
29
+ require_relative 'event/app_endpoints_loaded'
29
30
  require_relative 'event/app_heartbeat'
30
31
  require_relative 'event/app_integrations_change'
31
32
  require_relative 'event/app_started'
@@ -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
@@ -34,7 +34,10 @@ module Datadog
34
34
  end
35
35
 
36
36
  def inspect
37
- "#{self.class} ok?:#{ok?} unsupported?:#{unsupported?}, " \
37
+ maybe_code = if respond_to?(:code)
38
+ " code:#{code}," # steep:ignore
39
+ end
40
+ "#{self.class} ok?:#{ok?},#{maybe_code} unsupported?:#{unsupported?}, " \
38
41
  "not_found?:#{not_found?}, client_error?:#{client_error?}, " \
39
42
  "server_error?:#{server_error?}, internal_error?:#{internal_error?}, " \
40
43
  "payload:#{payload}"
@@ -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
@@ -13,6 +13,7 @@ module Datadog
13
13
  true-client-ip
14
14
  x-client-ip
15
15
  x-forwarded
16
+ forwarded
16
17
  forwarded-for
17
18
  x-cluster-client-ip
18
19
  fastly-client-ip
@@ -20,6 +21,8 @@ module Datadog
20
21
  cf-connecting-ipv6
21
22
  ].freeze
22
23
 
24
+ CGNAT_IP_RANGE = IPAddr.new('100.64.0.0/10')
25
+
23
26
  class << self
24
27
  # Returns a client IP associated with the request if it was
25
28
  # retrieved successfully.
@@ -73,6 +76,8 @@ module Datadog
73
76
  next unless value
74
77
 
75
78
  ips = value.split(',')
79
+ ips = process_forwarded_header_values(ips) if name == 'forwarded'
80
+
76
81
  ips.each do |ip|
77
82
  parsed_ip = ip_to_ipaddr(ip.strip)
78
83
 
@@ -83,6 +88,22 @@ module Datadog
83
88
  nil
84
89
  end
85
90
 
91
+ def process_forwarded_header_values(values)
92
+ values.each_with_object([]) do |value, acc|
93
+ value.downcase!
94
+
95
+ value.split(';').each do |tuple_str|
96
+ tuple_str.strip!
97
+ next unless tuple_str.start_with?('for=')
98
+
99
+ tuple_str.delete_prefix!('for=')
100
+ tuple_str.delete!('"')
101
+
102
+ acc << tuple_str
103
+ end
104
+ end
105
+ end
106
+
86
107
  # Returns whether the given value is more likely to be an IPv4 than an IPv6 address.
87
108
  #
88
109
  # This is done by checking if a dot (`'.'`) character appears before a colon (`':'`) in the value.
@@ -112,7 +133,7 @@ module Datadog
112
133
  end
113
134
 
114
135
  def global_ip?(parsed_ip)
115
- 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)
116
137
  end
117
138
  end
118
139
  end