datadog 2.15.0 → 2.16.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 (121) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +46 -2
  3. data/ext/datadog_profiling_native_extension/datadog_ruby_common.c +1 -4
  4. data/ext/datadog_profiling_native_extension/datadog_ruby_common.h +7 -0
  5. data/ext/datadog_profiling_native_extension/extconf.rb +3 -0
  6. data/ext/datadog_profiling_native_extension/heap_recorder.c +8 -1
  7. data/ext/libdatadog_api/crashtracker.c +1 -9
  8. data/ext/libdatadog_api/crashtracker.h +5 -0
  9. data/ext/libdatadog_api/datadog_ruby_common.c +1 -4
  10. data/ext/libdatadog_api/datadog_ruby_common.h +7 -0
  11. data/ext/libdatadog_api/init.c +15 -0
  12. data/ext/libdatadog_api/library_config.c +122 -0
  13. data/ext/libdatadog_api/library_config.h +19 -0
  14. data/ext/libdatadog_api/process_discovery.c +117 -0
  15. data/ext/libdatadog_api/process_discovery.h +5 -0
  16. data/lib/datadog/appsec/actions_handler.rb +3 -2
  17. data/lib/datadog/appsec/assets/waf_rules/recommended.json +1344 -0
  18. data/lib/datadog/appsec/assets/waf_rules/strict.json +1344 -0
  19. data/lib/datadog/appsec/autoload.rb +1 -1
  20. data/lib/datadog/appsec/component.rb +11 -4
  21. data/lib/datadog/appsec/configuration/settings.rb +31 -18
  22. data/lib/datadog/appsec/context.rb +1 -1
  23. data/lib/datadog/appsec/contrib/active_record/instrumentation.rb +10 -12
  24. data/lib/datadog/appsec/contrib/active_record/integration.rb +1 -1
  25. data/lib/datadog/appsec/contrib/active_record/patcher.rb +22 -22
  26. data/lib/datadog/appsec/contrib/devise/data_extractor.rb +2 -3
  27. data/lib/datadog/appsec/contrib/devise/ext.rb +1 -0
  28. data/lib/datadog/appsec/contrib/devise/integration.rb +1 -1
  29. data/lib/datadog/appsec/contrib/devise/patcher.rb +3 -5
  30. data/lib/datadog/appsec/contrib/devise/tracking_middleware.rb +17 -4
  31. data/lib/datadog/appsec/contrib/excon/integration.rb +1 -1
  32. data/lib/datadog/appsec/contrib/excon/ssrf_detection_middleware.rb +9 -10
  33. data/lib/datadog/appsec/contrib/faraday/integration.rb +1 -1
  34. data/lib/datadog/appsec/contrib/faraday/ssrf_detection_middleware.rb +8 -9
  35. data/lib/datadog/appsec/contrib/graphql/gateway/watcher.rb +8 -9
  36. data/lib/datadog/appsec/contrib/graphql/integration.rb +1 -1
  37. data/lib/datadog/appsec/contrib/rack/gateway/watcher.rb +22 -32
  38. data/lib/datadog/appsec/contrib/rack/integration.rb +1 -1
  39. data/lib/datadog/appsec/contrib/rack/request_middleware.rb +16 -16
  40. data/lib/datadog/appsec/contrib/rails/gateway/watcher.rb +11 -13
  41. data/lib/datadog/appsec/contrib/rails/integration.rb +1 -1
  42. data/lib/datadog/appsec/contrib/rails/patcher.rb +21 -21
  43. data/lib/datadog/appsec/contrib/rest_client/integration.rb +1 -1
  44. data/lib/datadog/appsec/contrib/rest_client/request_ssrf_detection_patch.rb +10 -11
  45. data/lib/datadog/appsec/contrib/sinatra/gateway/watcher.rb +17 -23
  46. data/lib/datadog/appsec/contrib/sinatra/integration.rb +1 -1
  47. data/lib/datadog/appsec/event.rb +85 -95
  48. data/lib/datadog/appsec/instrumentation/gateway/argument.rb +5 -2
  49. data/lib/datadog/appsec/metrics/telemetry.rb +1 -1
  50. data/lib/datadog/appsec/monitor/gateway/watcher.rb +42 -12
  51. data/lib/datadog/appsec/processor/rule_loader.rb +26 -28
  52. data/lib/datadog/appsec/processor/rule_merger.rb +5 -5
  53. data/lib/datadog/appsec/processor.rb +1 -1
  54. data/lib/datadog/appsec/remote.rb +14 -13
  55. data/lib/datadog/appsec/response.rb +6 -6
  56. data/lib/datadog/appsec/security_engine/runner.rb +1 -1
  57. data/lib/datadog/appsec/security_event.rb +39 -0
  58. data/lib/datadog/appsec.rb +1 -1
  59. data/lib/datadog/core/configuration/agentless_settings_resolver.rb +176 -0
  60. data/lib/datadog/core/configuration/components.rb +19 -10
  61. data/lib/datadog/core/configuration/option.rb +61 -25
  62. data/lib/datadog/core/configuration/settings.rb +10 -0
  63. data/lib/datadog/core/configuration/stable_config.rb +23 -0
  64. data/lib/datadog/core/configuration.rb +24 -0
  65. data/lib/datadog/core/crashtracking/component.rb +1 -9
  66. data/lib/datadog/core/environment/git.rb +1 -0
  67. data/lib/datadog/core/environment/variable_helpers.rb +1 -1
  68. data/lib/datadog/core/metrics/client.rb +8 -7
  69. data/lib/datadog/core/process_discovery.rb +32 -0
  70. data/lib/datadog/core/remote/client.rb +7 -0
  71. data/lib/datadog/core/runtime/metrics.rb +1 -1
  72. data/lib/datadog/core/telemetry/component.rb +60 -50
  73. data/lib/datadog/core/telemetry/emitter.rb +17 -11
  74. data/lib/datadog/core/telemetry/event.rb +7 -4
  75. data/lib/datadog/core/telemetry/http/adapters/net.rb +12 -97
  76. data/lib/datadog/core/telemetry/request.rb +3 -3
  77. data/lib/datadog/core/telemetry/transport/http/api.rb +43 -0
  78. data/lib/datadog/core/telemetry/transport/http/client.rb +49 -0
  79. data/lib/datadog/core/telemetry/transport/http/telemetry.rb +92 -0
  80. data/lib/datadog/core/telemetry/transport/http.rb +63 -0
  81. data/lib/datadog/core/telemetry/transport/telemetry.rb +52 -0
  82. data/lib/datadog/core/telemetry/worker.rb +45 -0
  83. data/lib/datadog/core/utils/time.rb +12 -0
  84. data/lib/datadog/core/workers/async.rb +20 -2
  85. data/lib/datadog/core/workers/interval_loop.rb +12 -1
  86. data/lib/datadog/core/workers/runtime_metrics.rb +2 -2
  87. data/lib/datadog/core.rb +8 -0
  88. data/lib/datadog/di/boot.rb +34 -0
  89. data/lib/datadog/di/remote.rb +2 -0
  90. data/lib/datadog/di.rb +5 -32
  91. data/lib/datadog/error_tracking/collector.rb +87 -0
  92. data/lib/datadog/error_tracking/component.rb +167 -0
  93. data/lib/datadog/error_tracking/configuration/settings.rb +63 -0
  94. data/lib/datadog/error_tracking/configuration.rb +11 -0
  95. data/lib/datadog/error_tracking/ext.rb +18 -0
  96. data/lib/datadog/error_tracking/extensions.rb +16 -0
  97. data/lib/datadog/error_tracking/filters.rb +77 -0
  98. data/lib/datadog/error_tracking.rb +18 -0
  99. data/lib/datadog/kit/identity.rb +1 -1
  100. data/lib/datadog/profiling/exporter.rb +1 -1
  101. data/lib/datadog/tracing/analytics.rb +1 -1
  102. data/lib/datadog/tracing/contrib/karafka/distributed/propagation.rb +2 -0
  103. data/lib/datadog/tracing/contrib/karafka/monitor.rb +1 -1
  104. data/lib/datadog/tracing/contrib/mongodb/configuration/settings.rb +8 -0
  105. data/lib/datadog/tracing/contrib/mongodb/ext.rb +1 -0
  106. data/lib/datadog/tracing/contrib/mongodb/subscribers.rb +18 -1
  107. data/lib/datadog/tracing/distributed/b3_multi.rb +1 -1
  108. data/lib/datadog/tracing/distributed/b3_single.rb +1 -1
  109. data/lib/datadog/tracing/distributed/datadog.rb +2 -2
  110. data/lib/datadog/tracing/sampling/rate_sampler.rb +2 -1
  111. data/lib/datadog/tracing/span_operation.rb +38 -14
  112. data/lib/datadog/tracing/trace_operation.rb +15 -7
  113. data/lib/datadog/tracing/tracer.rb +7 -3
  114. data/lib/datadog/tracing/utils.rb +1 -1
  115. data/lib/datadog/version.rb +1 -1
  116. data/lib/datadog.rb +2 -3
  117. metadata +34 -8
  118. data/lib/datadog/core/telemetry/http/env.rb +0 -20
  119. data/lib/datadog/core/telemetry/http/ext.rb +0 -28
  120. data/lib/datadog/core/telemetry/http/response.rb +0 -70
  121. data/lib/datadog/core/telemetry/http/transport.rb +0 -90
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative 'stable_config'
3
4
  require_relative '../utils/safe_dup'
4
5
 
5
6
  module Datadog
@@ -32,17 +33,25 @@ module Datadog
32
33
  end
33
34
 
34
35
  # Remote configuration provided through the Datadog app.
35
- REMOTE_CONFIGURATION = Value.new(2, :remote_configuration).freeze
36
+ REMOTE_CONFIGURATION = Value.new(5, :remote_configuration).freeze
36
37
 
37
38
  # Configuration provided in Ruby code, in this same process
38
- # or via Environment variable
39
- PROGRAMMATIC = Value.new(1, :programmatic).freeze
39
+ PROGRAMMATIC = Value.new(4, :programmatic).freeze
40
+
41
+ # Configuration provided by fleet managed stable config
42
+ FLEET_STABLE = Value.new(3, :fleet_stable).freeze
43
+
44
+ # Configuration provided via environment variable
45
+ ENVIRONMENT = Value.new(2, :environment).freeze
46
+
47
+ # Configuration provided by local stable config file
48
+ LOCAL_STABLE = Value.new(1, :local_stable).freeze
40
49
 
41
50
  # Configuration that comes from default values
42
51
  DEFAULT = Value.new(0, :default).freeze
43
52
 
44
53
  # All precedences, sorted from highest to lowest
45
- LIST = [REMOTE_CONFIGURATION, PROGRAMMATIC, DEFAULT].sort.reverse.freeze
54
+ LIST = [REMOTE_CONFIGURATION, PROGRAMMATIC, FLEET_STABLE, ENVIRONMENT, LOCAL_STABLE, DEFAULT].sort.reverse.freeze
46
55
  end
47
56
 
48
57
  def initialize(definition, context)
@@ -118,11 +127,17 @@ module Datadog
118
127
  end
119
128
 
120
129
  def get
121
- if @is_set
122
- @value
123
- else
124
- set_value_from_env_or_default
130
+ unless @is_set
131
+ # Ensures that both the default value and the environment value are set.
132
+ # This approach handles scenarios where an environment value is unset
133
+ # by falling back to the default value consistently.
134
+ set_default_value
135
+ set_customer_stable_config_value
136
+ set_env_value
137
+ set_fleet_stable_config_value
125
138
  end
139
+
140
+ @value
126
141
  end
127
142
 
128
143
  def reset
@@ -192,7 +207,7 @@ module Datadog
192
207
  when :bool
193
208
  string_value = value.strip
194
209
  string_value = string_value.downcase
195
- string_value == 'true' || string_value == '1' # rubocop:disable Style/MultipleComparison
210
+ string_value == 'true' || string_value == '1'
196
211
  when :string, NilClass
197
212
  value
198
213
  else
@@ -256,7 +271,8 @@ module Datadog
256
271
  when NilClass
257
272
  true # No validation is performed when option is typeless
258
273
  else
259
- raise ArgumentError, "The option #{@definition.name} is using an unsupported type option `#{@definition.type}`"
274
+ raise InvalidDefinitionError,
275
+ "The option #{@definition.name} is using an unsupported type option `#{@definition.type}`"
260
276
  end
261
277
  end
262
278
 
@@ -269,7 +285,7 @@ module Datadog
269
285
  @resolved_env = resolved_env
270
286
  # Store original value to ensure we can always safely call `#internal_set`
271
287
  # when restoring a value from `@value_per_precedence`, and we are only running `definition.setter`
272
- # on the original value, not on a valud that has already been processed by `definition.setter`.
288
+ # on the original value, not on a value that has already been processed by `definition.setter`.
273
289
  @value_per_precedence[precedence] = value
274
290
  context_exec(v, old_value, precedence, &definition.after_set) if definition.after_set
275
291
  end
@@ -283,39 +299,59 @@ module Datadog
283
299
  @context.instance_eval(&block)
284
300
  end
285
301
 
286
- def set_value_from_env_or_default
302
+ def set_default_value
303
+ set(default_value, precedence: Precedence::DEFAULT)
304
+ end
305
+
306
+ def set_env_value
307
+ value, resolved_env = get_value_and_resolved_env_from(ENV)
308
+ set(value, precedence: Precedence::ENVIRONMENT, resolved_env: resolved_env) unless value.nil?
309
+ end
310
+
311
+ def set_customer_stable_config_value
312
+ customer_config = StableConfig.configuration[:local]
313
+ return if customer_config.nil?
314
+
315
+ value, resolved_env = get_value_and_resolved_env_from(customer_config, source: 'local stable config')
316
+ set(value, precedence: Precedence::LOCAL_STABLE, resolved_env: resolved_env) unless value.nil?
317
+ end
318
+
319
+ def set_fleet_stable_config_value
320
+ fleet_config = StableConfig.configuration[:fleet]
321
+ return if fleet_config.nil?
322
+
323
+ value, resolved_env = get_value_and_resolved_env_from(fleet_config, source: 'fleet stable config')
324
+ set(value, precedence: Precedence::FLEET_STABLE, resolved_env: resolved_env) unless value.nil?
325
+ end
326
+
327
+ def get_value_and_resolved_env_from(env_vars, source: 'environment variable')
287
328
  value = nil
288
- precedence = nil
289
329
  resolved_env = nil
290
330
 
291
331
  if definition.env
292
332
  Array(definition.env).each do |env|
293
- next if ENV[env].nil?
333
+ next if env_vars[env].nil?
294
334
 
295
335
  resolved_env = env
296
- value = coerce_env_variable(ENV[env])
297
- precedence = Precedence::PROGRAMMATIC
336
+ value = coerce_env_variable(env_vars[env])
298
337
  break
299
338
  end
300
339
  end
301
340
 
302
- if value.nil? && definition.deprecated_env && ENV[definition.deprecated_env]
341
+ if value.nil? && definition.deprecated_env && env_vars[definition.deprecated_env]
303
342
  resolved_env = definition.deprecated_env
304
- value = coerce_env_variable(ENV[definition.deprecated_env])
305
- precedence = Precedence::PROGRAMMATIC
343
+ value = coerce_env_variable(env_vars[definition.deprecated_env])
306
344
 
307
345
  Datadog::Core.log_deprecation do
308
- "#{definition.deprecated_env} environment variable is deprecated, use #{definition.env} instead."
346
+ "#{definition.deprecated_env} #{source} is deprecated, use #{definition.env} instead."
309
347
  end
310
348
  end
311
349
 
312
- option_value = value.nil? ? default_value : value
313
-
314
- set(option_value, precedence: precedence || Precedence::DEFAULT, resolved_env: resolved_env)
350
+ [value, resolved_env]
315
351
  rescue ArgumentError
316
352
  raise ArgumentError,
317
- "Expected environment variable #{resolved_env} to be a #{@definition.type}, " \
318
- "but '#{ENV[resolved_env]}' was provided"
353
+ "Expected #{source} #{resolved_env} to be a #{@definition.type}, " \
354
+ "but '#{env_vars[resolved_env]}' was provided"
319
355
  end
320
356
 
321
357
  # Anchor object that represents a value that is not set.
@@ -888,6 +888,16 @@ module Datadog
888
888
  o.env Core::Telemetry::Ext::ENV_LOG_COLLECTION
889
889
  o.default true
890
890
  end
891
+
892
+ # For internal use only.
893
+ # Enables telemetry debugging through the Datadog platform.
894
+ #
895
+ # @default `false`.
896
+ # @return [Boolean]
897
+ option :debug do |o|
898
+ o.type :bool
899
+ o.default false
900
+ end
891
901
  end
892
902
 
893
903
  # Remote configuration
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Datadog
4
+ module Core
5
+ module Configuration
6
+ # Import config from config files (fleet automation)
7
+ module StableConfig
8
+ def self.extract_configuration
9
+ if (libdatadog_api_failure = Datadog::Core::LIBDATADOG_API_FAILURE)
10
+ Datadog.config_init_logger.debug("Cannot enable stable config: #{libdatadog_api_failure}")
11
+ return {}
12
+ end
13
+ Configurator.new.get
14
+ end
15
+
16
+ def self.configuration
17
+ # @configuration ||= StableConfig.extract_configuration # TODO: After libdatadog 17.1 release, uncomment this line
18
+ @configuration ||= {} # TODO: After libdatadog 17.1 release, delete this line
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -172,6 +172,10 @@ module Datadog
172
172
  end
173
173
  end
174
174
 
175
+ def config_init_logger
176
+ configuration? ? logger : logger_without_configuration
177
+ end
178
+
175
179
  # Gracefully shuts down all components.
176
180
  #
177
181
  # Components will still respond to method calls as usual,
@@ -244,6 +248,10 @@ module Datadog
244
248
  end
245
249
  end
246
250
 
251
+ def configuration?
252
+ (defined?(@configuration) && @configuration) != nil
253
+ end
254
+
247
255
  def components?
248
256
  # This does not need to grab the COMPONENTS_READ_LOCK because it's not returning the components
249
257
  (defined?(@components) && @components) != nil
@@ -274,6 +282,7 @@ module Datadog
274
282
  def logger_without_components
275
283
  # Use default logger without initializing components.
276
284
  # This enables logging during initialization, otherwise we'd run into deadlocks.
285
+
277
286
  @temp_logger ||= begin
278
287
  logger = configuration.logger.instance || Core::Logger.new($stdout)
279
288
  logger.level = configuration.diagnostics.debug ? ::Logger::DEBUG : configuration.logger.level
@@ -281,6 +290,21 @@ module Datadog
281
290
  end
282
291
  end
283
292
 
293
+ def logger_without_configuration
294
+ # There's rare cases where we need to use logger during configuration initialization,
295
+ # such as reading stable config. In this case we cannot access configuration.
296
+
297
+ @temp_config_logger ||= begin
298
+ debug_env_value = ENV[Ext::Diagnostics::ENV_DEBUG_ENABLED]&.strip&.downcase
299
+ debug_value = debug_env_value == 'true' || debug_env_value == '1'
300
+
301
+ logger = Core::Logger.new($stdout)
302
+ # We cannot access config and the default level is INFO, so we need to set the level manually
303
+ logger.level = debug_value ? ::Logger::DEBUG : ::Logger::INFO
304
+ logger
305
+ end
306
+ end
307
+
284
308
  # Called from our at_exit hook whenever there was a pending Interrupt exception (e.g. typically due to ctrl+c)
285
309
  # to print a nice message whenever we're taking a bit longer than usual to finish the process.
286
310
  def handle_interrupt_shutdown!
@@ -18,14 +18,6 @@ module Datadog
18
18
  #
19
19
  # Methods prefixed with _native_ are implemented in `crashtracker.c`
20
20
  class Component
21
- LIBDATADOG_API_FAILURE =
22
- begin
23
- require "libdatadog_api.#{RUBY_VERSION[/\d+.\d+/]}_#{RUBY_PLATFORM}"
24
- nil
25
- rescue LoadError => e
26
- e.message
27
- end
28
-
29
21
  ONLY_ONCE = Core::Utils::OnlyOnce.new
30
22
 
31
23
  def self.build(settings, agent_settings, logger:)
@@ -71,7 +63,7 @@ module Datadog
71
63
  # Must NOT reference `self` here, as only the first instance will
72
64
  # be captured by the ONLY_ONCE and we want to pick the latest active one
73
65
  # (which may have different tags or agent config)
74
- Datadog.send(:components).crashtracker&.update_on_fork
66
+ Datadog.send(:components, allow_initialization: false)&.crashtracker&.update_on_fork
75
67
  end
76
68
  end
77
69
  end
@@ -5,6 +5,7 @@ require_relative '../utils/url'
5
5
 
6
6
  module Datadog
7
7
  module Core
8
+ # Environment
8
9
  module Environment
9
10
  # Retrieves git repository information from environment variables
10
11
  module Git
@@ -23,7 +23,7 @@ module Datadog
23
23
  if var && ENV.key?(var)
24
24
  value = ENV[var].to_s.strip
25
25
  value.downcase!
26
- value == 'true' || value == '1' # rubocop:disable Style/MultipleComparison
26
+ value == 'true' || value == '1'
27
27
  else
28
28
  default
29
29
  end
@@ -21,9 +21,10 @@ module Datadog
21
21
  extend Options
22
22
  extend Helpers
23
23
 
24
- attr_reader :statsd, :logger
24
+ attr_reader :statsd, :logger, :telemetry
25
25
 
26
- def initialize(logger: Datadog.logger, statsd: nil, enabled: true, **_)
26
+ def initialize(telemetry:, logger: Datadog.logger, statsd: nil, enabled: true, **_)
27
+ @telemetry = telemetry
27
28
  @logger = logger
28
29
  @statsd =
29
30
  if supported?
@@ -102,7 +103,7 @@ module Datadog
102
103
  logger.error(
103
104
  "Failed to send count stat. Cause: #{e.class.name} #{e.message} Source: #{Array(e.backtrace).first}"
104
105
  )
105
- Telemetry::Logger.report(e, description: 'Failed to send count stat')
106
+ telemetry.report(e, description: 'Failed to send count stat')
106
107
  end
107
108
 
108
109
  def distribution(stat, value = nil, options = nil, &block)
@@ -116,7 +117,7 @@ module Datadog
116
117
  logger.error(
117
118
  "Failed to send distribution stat. Cause: #{e.class.name} #{e.message} Source: #{Array(e.backtrace).first}"
118
119
  )
119
- Telemetry::Logger.report(e, description: 'Failed to send distribution stat')
120
+ telemetry.report(e, description: 'Failed to send distribution stat')
120
121
  end
121
122
 
122
123
  def increment(stat, options = nil)
@@ -129,7 +130,7 @@ module Datadog
129
130
  logger.error(
130
131
  "Failed to send increment stat. Cause: #{e.class.name} #{e.message} Source: #{Array(e.backtrace).first}"
131
132
  )
132
- Telemetry::Logger.report(e, description: 'Failed to send increment stat')
133
+ telemetry.report(e, description: 'Failed to send increment stat')
133
134
  end
134
135
 
135
136
  def gauge(stat, value = nil, options = nil, &block)
@@ -143,7 +144,7 @@ module Datadog
143
144
  logger.error(
144
145
  "Failed to send gauge stat. Cause: #{e.class.name} #{e.message} Source: #{Array(e.backtrace).first}"
145
146
  )
146
- Telemetry::Logger.report(e, description: 'Failed to send gauge stat')
147
+ telemetry.report(e, description: 'Failed to send gauge stat')
147
148
  end
148
149
 
149
150
  def time(stat, options = nil)
@@ -163,7 +164,7 @@ module Datadog
163
164
  logger.error(
164
165
  "Failed to send time stat. Cause: #{e.class.name} #{e.message} Source: #{Array(e.backtrace).first}"
165
166
  )
166
- Telemetry::Logger.report(e, description: 'Failed to send time stat')
167
+ telemetry.report(e, description: 'Failed to send time stat')
167
168
  end
168
169
  end
169
170
 
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Datadog
4
+ module Core
5
+ # Class used to store tracer metadata in a native file descriptor.
6
+ class ProcessDiscovery
7
+ def self.get_and_store_metadata(settings, logger)
8
+ if (libdatadog_api_failure = Datadog::Core::LIBDATADOG_API_FAILURE)
9
+ logger.debug("Cannot enable process discovery: #{libdatadog_api_failure}")
10
+ return
11
+ end
12
+ metadata = get_metadata(settings)
13
+ _native_store_tracer_metadata(logger, **metadata)
14
+ end
15
+
16
+ # According to the RFC, runtime_id, service_name, service_env, service_version are optional.
17
+ # In the C method exposed by ddcommon, memfd_create replaces empty strings by None for these fields.
18
+ private_class_method def self.get_metadata(settings)
19
+ {
20
+ schema_version: 1,
21
+ runtime_id: Core::Environment::Identity.id,
22
+ tracer_language: Core::Environment::Identity.lang,
23
+ tracer_version: Core::Environment::Identity.gem_datadog_version_semver2,
24
+ hostname: Core::Environment::Socket.hostname,
25
+ service_name: settings.service || '',
26
+ service_env: settings.env || '',
27
+ service_version: settings.version || ''
28
+ }
29
+ end
30
+ end
31
+ end
32
+ end
@@ -140,6 +140,13 @@ module Datadog
140
140
  "ruby.gem.libdatadog.platform:#{gem_spec('libdatadog').platform}",
141
141
  ]
142
142
 
143
+ if (git_repository_url = Core::Environment::Git.git_repository_url)
144
+ client_tracer_tags << "git.repository_url:#{git_repository_url}"
145
+ end
146
+ if (git_commit_sha = Core::Environment::Git.git_commit_sha)
147
+ client_tracer_tags << "git.commit.sha:#{git_commit_sha}"
148
+ end
149
+
143
150
  client_tracer = {
144
151
  runtime_id: Core::Environment::Identity.id,
145
152
  language: Core::Environment::Identity.lang,
@@ -14,7 +14,7 @@ module Datadog
14
14
  module Runtime
15
15
  # For generating runtime metrics
16
16
  class Metrics < Core::Metrics::Client
17
- def initialize(**options)
17
+ def initialize(telemetry:, **options)
18
18
  super
19
19
 
20
20
  # Initialize service list
@@ -2,12 +2,13 @@
2
2
 
3
3
  require_relative 'emitter'
4
4
  require_relative 'event'
5
- require_relative 'http/transport'
6
5
  require_relative 'metrics_manager'
7
6
  require_relative 'worker'
8
7
  require_relative 'logging'
8
+ require_relative 'transport/http'
9
9
 
10
10
  require_relative '../configuration/ext'
11
+ require_relative '../configuration/agentless_settings_resolver'
11
12
  require_relative '../utils/forking'
12
13
 
13
14
  module Datadog
@@ -16,7 +17,7 @@ module Datadog
16
17
  # Telemetry entrypoint, coordinates sending telemetry events at various points in app lifecycle.
17
18
  # Note: Telemetry does not spawn its worker thread in fork processes, thus no telemetry is sent in forked processes.
18
19
  class Component
19
- attr_reader :enabled, :logger
20
+ attr_reader :enabled, :logger, :transport, :worker
20
21
 
21
22
  include Core::Utils::Forking
22
23
  include Telemetry::Logging
@@ -25,89 +26,87 @@ module Datadog
25
26
  enabled = settings.telemetry.enabled
26
27
  agentless_enabled = settings.telemetry.agentless_enabled
27
28
 
28
- if !agentless_enabled && agent_settings.adapter != Datadog::Core::Configuration::Ext::Agent::HTTP::ADAPTER
29
- enabled = false
30
- logger.debug { "Telemetry disabled. Agent network adapter not supported: #{agent_settings.adapter}" }
31
- end
32
-
33
29
  if agentless_enabled && settings.api_key.nil?
34
30
  enabled = false
35
- logger.debug { 'Telemetry disabled. Agentless telemetry requires an DD_API_KEY variable to be set.' }
31
+ logger.debug { 'Telemetry disabled. Agentless telemetry requires a DD_API_KEY variable to be set.' }
36
32
  end
37
33
 
38
- transport = if agentless_enabled
39
- Datadog::Core::Telemetry::Http::Transport.build_agentless_transport(
40
- api_key: settings.api_key,
41
- dd_site: settings.site,
42
- url_override: settings.telemetry.agentless_url_override
43
- )
44
- else
45
- Datadog::Core::Telemetry::Http::Transport.build_agent_transport(agent_settings)
46
- end
47
-
48
34
  Telemetry::Component.new(
49
- http_transport: transport,
35
+ settings: settings,
36
+ agent_settings: agent_settings,
50
37
  enabled: enabled,
51
- metrics_enabled: enabled && settings.telemetry.metrics_enabled,
52
- heartbeat_interval_seconds: settings.telemetry.heartbeat_interval_seconds,
53
- metrics_aggregation_interval_seconds: settings.telemetry.metrics_aggregation_interval_seconds,
54
- dependency_collection: settings.telemetry.dependency_collection,
55
38
  logger: logger,
56
- shutdown_timeout_seconds: settings.telemetry.shutdown_timeout_seconds,
57
- log_collection_enabled: settings.telemetry.log_collection_enabled
58
39
  )
59
40
  end
60
41
 
61
42
  # @param enabled [Boolean] Determines whether telemetry events should be sent to the API
62
- # @param metrics_enabled [Boolean] Determines whether telemetry metrics should be sent to the API
63
- # @param heartbeat_interval_seconds [Float] How frequently heartbeats will be reported, in seconds.
64
- # @param metrics_aggregation_interval_seconds [Float] How frequently metrics will be aggregated, in seconds.
65
- # @param [Boolean] dependency_collection Whether to send the `app-dependencies-loaded` event
66
- def initialize(
67
- heartbeat_interval_seconds:,
68
- metrics_aggregation_interval_seconds:,
69
- dependency_collection:,
43
+ def initialize( # rubocop: disable Metrics/MethodLength
44
+ settings:,
45
+ agent_settings:,
70
46
  logger:,
71
- http_transport:,
72
- shutdown_timeout_seconds:,
73
- enabled: true,
74
- metrics_enabled: true,
75
- log_collection_enabled: true
47
+ enabled:
76
48
  )
77
49
  @enabled = enabled
78
- @log_collection_enabled = log_collection_enabled
50
+ @log_collection_enabled = settings.telemetry.log_collection_enabled
79
51
  @logger = logger
80
52
 
81
53
  @metrics_manager = MetricsManager.new(
82
- enabled: enabled && metrics_enabled,
83
- aggregation_interval: metrics_aggregation_interval_seconds
54
+ enabled: @enabled && settings.telemetry.metrics_enabled,
55
+ aggregation_interval: settings.telemetry.metrics_aggregation_interval_seconds,
84
56
  )
85
57
 
58
+ @stopped = false
59
+
60
+ return unless @enabled
61
+
62
+ @transport = if settings.telemetry.agentless_enabled
63
+ agent_settings = Core::Configuration::AgentlessSettingsResolver.call(
64
+ settings,
65
+ host_prefix: 'instrumentation-telemetry-intake',
66
+ url_override: settings.telemetry.agentless_url_override,
67
+ url_override_source: 'c.telemetry.agentless_url_override',
68
+ logger: logger,
69
+ )
70
+ Telemetry::Transport::HTTP.agentless_telemetry(
71
+ agent_settings: agent_settings,
72
+ logger: logger,
73
+ # api_key should have already validated to be
74
+ # not nil by +build+ method above.
75
+ api_key: settings.api_key,
76
+ )
77
+ else
78
+ Telemetry::Transport::HTTP.agent_telemetry(
79
+ agent_settings: agent_settings, logger: logger,
80
+ )
81
+ end
82
+
86
83
  @worker = Telemetry::Worker.new(
87
84
  enabled: @enabled,
88
- heartbeat_interval_seconds: heartbeat_interval_seconds,
89
- metrics_aggregation_interval_seconds: metrics_aggregation_interval_seconds,
90
- emitter: Emitter.new(http_transport: http_transport),
85
+ heartbeat_interval_seconds: settings.telemetry.heartbeat_interval_seconds,
86
+ metrics_aggregation_interval_seconds: settings.telemetry.metrics_aggregation_interval_seconds,
87
+ emitter: Emitter.new(
88
+ @transport,
89
+ logger: @logger,
90
+ debug: settings.telemetry.debug,
91
+ ),
91
92
  metrics_manager: @metrics_manager,
92
- dependency_collection: dependency_collection,
93
+ dependency_collection: settings.telemetry.dependency_collection,
93
94
  logger: logger,
94
- shutdown_timeout: shutdown_timeout_seconds
95
+ shutdown_timeout: settings.telemetry.shutdown_timeout_seconds,
95
96
  )
96
97
 
97
- @stopped = false
98
-
99
98
  @worker.start
100
99
  end
101
100
 
102
101
  def disable!
103
102
  @enabled = false
104
- @worker.enabled = false
103
+ @worker&.enabled = false
105
104
  end
106
105
 
107
106
  def stop!
108
107
  return if @stopped
109
108
 
110
- @worker.stop(true)
109
+ @worker&.stop(true)
111
110
  @stopped = true
112
111
  end
113
112
 
@@ -129,6 +128,17 @@ module Datadog
129
128
  @worker.enqueue(event)
130
129
  end
131
130
 
131
+ # Wait for the worker to send out all events that have already
132
+ # been queued, up to 15 seconds. Returns whether all events have
133
+ # been flushed.
134
+ #
135
+ # @api private
136
+ def flush
137
+ return if !@enabled || forked?
138
+
139
+ @worker.flush
140
+ end
141
+
132
142
  # Report configuration changes caused by Remote Configuration.
133
143
  def client_configuration_change!(changes)
134
144
  return if !@enabled || forked?
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative 'request'
4
- require_relative 'http/transport'
4
+ require_relative '../transport/response'
5
5
  require_relative '../utils/sequence'
6
6
  require_relative '../utils/forking'
7
7
 
@@ -10,26 +10,32 @@ module Datadog
10
10
  module Telemetry
11
11
  # Class that emits telemetry events
12
12
  class Emitter
13
- attr_reader :http_transport
13
+ attr_reader :transport, :logger
14
14
 
15
15
  extend Core::Utils::Forking
16
16
 
17
- # @param http_transport [Datadog::Core::Telemetry::Http::Transport] Transport object that can be used to send
18
- # telemetry requests via the agent
19
- def initialize(http_transport:)
20
- @http_transport = http_transport
17
+ # @param transport [Datadog::Core::Telemetry::Transport::Telemetry::Transport]
18
+ # Transport object that can be used to send telemetry requests
19
+ def initialize(transport, logger: Datadog.logger, debug: false)
20
+ @transport = transport
21
+ @logger = logger
22
+ @debug = !!debug
23
+ end
24
+
25
+ def debug?
26
+ @debug
21
27
  end
22
28
 
23
29
  # Retrieves and emits a TelemetryRequest object based on the request type specified
24
30
  def request(event)
25
31
  seq_id = self.class.sequence.next
26
- payload = Request.build_payload(event, seq_id)
27
- res = @http_transport.request(request_type: event.type, payload: payload.to_json)
28
- Datadog.logger.debug { "Telemetry sent for event `#{event.type}` (code: #{res.code.inspect})" }
32
+ payload = Request.build_payload(event, seq_id, debug: debug?)
33
+ res = @transport.send_telemetry(request_type: event.type, payload: payload)
34
+ logger.debug { "Telemetry sent for event `#{event.type}` (response code: #{res.code})" }
29
35
  res
30
36
  rescue => e
31
- Datadog.logger.debug("Unable to send telemetry request for event `#{event.type rescue 'unknown'}`: #{e}")
32
- Telemetry::Http::InternalErrorResponse.new(e)
37
+ logger.debug { "Unable to send telemetry request for event `#{event.type rescue 'unknown'}`: #{e}" }
38
+ Core::Transport::InternalErrorResponse.new(e)
33
39
  end
34
40
 
35
41
  # Initializes a Sequence object to track seq_id if not already initialized; else returns stored