datadog 2.14.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 (149) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +67 -1
  3. data/ext/datadog_profiling_native_extension/collectors_thread_context.c +7 -6
  4. data/ext/datadog_profiling_native_extension/datadog_ruby_common.c +1 -4
  5. data/ext/datadog_profiling_native_extension/datadog_ruby_common.h +10 -0
  6. data/ext/datadog_profiling_native_extension/encoded_profile.c +69 -0
  7. data/ext/datadog_profiling_native_extension/encoded_profile.h +7 -0
  8. data/ext/datadog_profiling_native_extension/extconf.rb +3 -0
  9. data/ext/datadog_profiling_native_extension/heap_recorder.c +8 -1
  10. data/ext/datadog_profiling_native_extension/http_transport.c +25 -32
  11. data/ext/datadog_profiling_native_extension/profiling.c +2 -0
  12. data/ext/datadog_profiling_native_extension/stack_recorder.c +22 -21
  13. data/ext/libdatadog_api/crashtracker.c +1 -9
  14. data/ext/libdatadog_api/crashtracker.h +5 -0
  15. data/ext/libdatadog_api/datadog_ruby_common.c +1 -4
  16. data/ext/libdatadog_api/datadog_ruby_common.h +10 -0
  17. data/ext/libdatadog_api/init.c +15 -0
  18. data/ext/libdatadog_api/library_config.c +122 -0
  19. data/ext/libdatadog_api/library_config.h +19 -0
  20. data/ext/libdatadog_api/process_discovery.c +117 -0
  21. data/ext/libdatadog_api/process_discovery.h +5 -0
  22. data/lib/datadog/appsec/actions_handler.rb +3 -2
  23. data/lib/datadog/appsec/assets/waf_rules/README.md +50 -5
  24. data/lib/datadog/appsec/assets/waf_rules/processors.json +239 -10
  25. data/lib/datadog/appsec/assets/waf_rules/scanners.json +926 -17
  26. data/lib/datadog/appsec/autoload.rb +1 -1
  27. data/lib/datadog/appsec/component.rb +29 -20
  28. data/lib/datadog/appsec/compressed_json.rb +40 -0
  29. data/lib/datadog/appsec/configuration/settings.rb +31 -18
  30. data/lib/datadog/appsec/context.rb +1 -1
  31. data/lib/datadog/appsec/contrib/active_record/instrumentation.rb +10 -12
  32. data/lib/datadog/appsec/contrib/active_record/integration.rb +2 -2
  33. data/lib/datadog/appsec/contrib/active_record/patcher.rb +22 -22
  34. data/lib/datadog/appsec/contrib/devise/data_extractor.rb +2 -3
  35. data/lib/datadog/appsec/contrib/devise/ext.rb +1 -0
  36. data/lib/datadog/appsec/contrib/devise/integration.rb +1 -1
  37. data/lib/datadog/appsec/contrib/devise/patcher.rb +3 -5
  38. data/lib/datadog/appsec/contrib/devise/tracking_middleware.rb +17 -4
  39. data/lib/datadog/appsec/contrib/excon/integration.rb +1 -1
  40. data/lib/datadog/appsec/contrib/excon/ssrf_detection_middleware.rb +9 -10
  41. data/lib/datadog/appsec/contrib/faraday/integration.rb +1 -1
  42. data/lib/datadog/appsec/contrib/faraday/ssrf_detection_middleware.rb +8 -9
  43. data/lib/datadog/appsec/contrib/graphql/gateway/watcher.rb +8 -9
  44. data/lib/datadog/appsec/contrib/graphql/integration.rb +1 -1
  45. data/lib/datadog/appsec/contrib/rack/gateway/watcher.rb +22 -32
  46. data/lib/datadog/appsec/contrib/rack/integration.rb +1 -1
  47. data/lib/datadog/appsec/contrib/rack/request_middleware.rb +16 -16
  48. data/lib/datadog/appsec/contrib/rails/gateway/watcher.rb +11 -13
  49. data/lib/datadog/appsec/contrib/rails/integration.rb +1 -1
  50. data/lib/datadog/appsec/contrib/rails/patcher.rb +21 -21
  51. data/lib/datadog/appsec/contrib/rest_client/integration.rb +1 -1
  52. data/lib/datadog/appsec/contrib/rest_client/request_ssrf_detection_patch.rb +10 -11
  53. data/lib/datadog/appsec/contrib/sinatra/gateway/watcher.rb +17 -23
  54. data/lib/datadog/appsec/contrib/sinatra/integration.rb +1 -1
  55. data/lib/datadog/appsec/event.rb +95 -134
  56. data/lib/datadog/appsec/instrumentation/gateway/argument.rb +5 -2
  57. data/lib/datadog/appsec/metrics/telemetry.rb +1 -1
  58. data/lib/datadog/appsec/monitor/gateway/watcher.rb +42 -12
  59. data/lib/datadog/appsec/processor/rule_loader.rb +26 -28
  60. data/lib/datadog/appsec/processor/rule_merger.rb +5 -5
  61. data/lib/datadog/appsec/processor.rb +1 -1
  62. data/lib/datadog/appsec/remote.rb +16 -11
  63. data/lib/datadog/appsec/response.rb +6 -6
  64. data/lib/datadog/appsec/security_engine/runner.rb +1 -1
  65. data/lib/datadog/appsec/security_event.rb +39 -0
  66. data/lib/datadog/appsec.rb +1 -1
  67. data/lib/datadog/core/configuration/agentless_settings_resolver.rb +176 -0
  68. data/lib/datadog/core/configuration/components.rb +19 -10
  69. data/lib/datadog/core/configuration/option.rb +61 -25
  70. data/lib/datadog/core/configuration/settings.rb +10 -0
  71. data/lib/datadog/core/configuration/stable_config.rb +23 -0
  72. data/lib/datadog/core/configuration.rb +24 -0
  73. data/lib/datadog/core/crashtracking/component.rb +1 -9
  74. data/lib/datadog/core/diagnostics/environment_logger.rb +1 -1
  75. data/lib/datadog/core/environment/git.rb +1 -0
  76. data/lib/datadog/core/environment/variable_helpers.rb +1 -1
  77. data/lib/datadog/core/metrics/client.rb +8 -7
  78. data/lib/datadog/core/process_discovery.rb +32 -0
  79. data/lib/datadog/core/remote/client.rb +7 -0
  80. data/lib/datadog/core/runtime/metrics.rb +1 -1
  81. data/lib/datadog/core/telemetry/component.rb +60 -50
  82. data/lib/datadog/core/telemetry/emitter.rb +17 -11
  83. data/lib/datadog/core/telemetry/event.rb +7 -4
  84. data/lib/datadog/core/telemetry/http/adapters/net.rb +12 -97
  85. data/lib/datadog/core/telemetry/metric.rb +5 -5
  86. data/lib/datadog/core/telemetry/request.rb +4 -4
  87. data/lib/datadog/core/telemetry/transport/http/api.rb +43 -0
  88. data/lib/datadog/core/telemetry/transport/http/client.rb +49 -0
  89. data/lib/datadog/core/telemetry/transport/http/telemetry.rb +92 -0
  90. data/lib/datadog/core/telemetry/transport/http.rb +63 -0
  91. data/lib/datadog/core/telemetry/transport/telemetry.rb +52 -0
  92. data/lib/datadog/core/telemetry/worker.rb +45 -0
  93. data/lib/datadog/core/utils/time.rb +12 -0
  94. data/lib/datadog/core/workers/async.rb +20 -2
  95. data/lib/datadog/core/workers/interval_loop.rb +12 -1
  96. data/lib/datadog/core/workers/runtime_metrics.rb +2 -2
  97. data/lib/datadog/core.rb +8 -0
  98. data/lib/datadog/di/boot.rb +34 -0
  99. data/lib/datadog/di/probe_notification_builder.rb +1 -1
  100. data/lib/datadog/di/remote.rb +2 -0
  101. data/lib/datadog/di/transport/http/diagnostics.rb +0 -1
  102. data/lib/datadog/di/transport/http/input.rb +0 -1
  103. data/lib/datadog/di/transport/http.rb +0 -6
  104. data/lib/datadog/di.rb +5 -32
  105. data/lib/datadog/error_tracking/collector.rb +87 -0
  106. data/lib/datadog/error_tracking/component.rb +167 -0
  107. data/lib/datadog/error_tracking/configuration/settings.rb +63 -0
  108. data/lib/datadog/error_tracking/configuration.rb +11 -0
  109. data/lib/datadog/error_tracking/ext.rb +18 -0
  110. data/lib/datadog/error_tracking/extensions.rb +16 -0
  111. data/lib/datadog/error_tracking/filters.rb +77 -0
  112. data/lib/datadog/error_tracking.rb +18 -0
  113. data/lib/datadog/kit/identity.rb +1 -1
  114. data/lib/datadog/profiling/collectors/info.rb +3 -0
  115. data/lib/datadog/profiling/encoded_profile.rb +11 -0
  116. data/lib/datadog/profiling/exporter.rb +3 -4
  117. data/lib/datadog/profiling/ext.rb +0 -1
  118. data/lib/datadog/profiling/flush.rb +4 -7
  119. data/lib/datadog/profiling/http_transport.rb +10 -59
  120. data/lib/datadog/profiling/stack_recorder.rb +4 -4
  121. data/lib/datadog/profiling.rb +1 -0
  122. data/lib/datadog/tracing/analytics.rb +1 -1
  123. data/lib/datadog/tracing/contrib/active_record/integration.rb +1 -1
  124. data/lib/datadog/tracing/contrib/karafka/distributed/propagation.rb +2 -0
  125. data/lib/datadog/tracing/contrib/karafka/monitor.rb +1 -1
  126. data/lib/datadog/tracing/contrib/mongodb/configuration/settings.rb +8 -0
  127. data/lib/datadog/tracing/contrib/mongodb/ext.rb +1 -0
  128. data/lib/datadog/tracing/contrib/mongodb/subscribers.rb +18 -1
  129. data/lib/datadog/tracing/contrib/opensearch/configuration/settings.rb +17 -0
  130. data/lib/datadog/tracing/contrib/opensearch/ext.rb +9 -0
  131. data/lib/datadog/tracing/contrib/opensearch/patcher.rb +5 -1
  132. data/lib/datadog/tracing/contrib/rack/request_queue.rb +1 -1
  133. data/lib/datadog/tracing/contrib/sidekiq/server_tracer.rb +1 -1
  134. data/lib/datadog/tracing/distributed/b3_multi.rb +1 -1
  135. data/lib/datadog/tracing/distributed/b3_single.rb +1 -1
  136. data/lib/datadog/tracing/distributed/datadog.rb +2 -2
  137. data/lib/datadog/tracing/sampling/rate_sampler.rb +2 -1
  138. data/lib/datadog/tracing/span_event.rb +1 -1
  139. data/lib/datadog/tracing/span_operation.rb +38 -14
  140. data/lib/datadog/tracing/trace_operation.rb +15 -7
  141. data/lib/datadog/tracing/tracer.rb +7 -3
  142. data/lib/datadog/tracing/utils.rb +1 -1
  143. data/lib/datadog/version.rb +1 -1
  144. data/lib/datadog.rb +2 -3
  145. metadata +40 -10
  146. data/lib/datadog/core/telemetry/http/env.rb +0 -20
  147. data/lib/datadog/core/telemetry/http/ext.rb +0 -28
  148. data/lib/datadog/core/telemetry/http/response.rb +0 -70
  149. data/lib/datadog/core/telemetry/http/transport.rb +0 -90
@@ -0,0 +1,176 @@
1
+ # frozen_string_literal: true
2
+
3
+ # rubocop:disable Style/*
4
+
5
+ require 'uri'
6
+
7
+ require_relative 'agent_settings_resolver'
8
+
9
+ module Datadog
10
+ module Core
11
+ module Configuration
12
+ # Agent settings resolver for agentless operations (currently, telemetry
13
+ # in agentless mode).
14
+ #
15
+ # The terminology gets a little confusing here, but transports communicate
16
+ # with servers which are - for most components in the tracer - the
17
+ # (local) agent. Hence, "agent settings" to refer to where the server
18
+ # is located. Telemetry supports sending to the local agent but also
19
+ # implements agentless mode where it sends directly to Datadog intake
20
+ # endpoints. The agentless mode is configured using different settings,
21
+ # and this class produces AgentSettings instances when in agentless mode.
22
+ #
23
+ # Agentless settings resolver uses the following configuration sources:
24
+ #
25
+ # 1. url_override constructor parameter, if provided
26
+ # 2. Built-in default host/port/TLS settings for the backend
27
+ # intake endpoint
28
+ #
29
+ # The agentless resolver does NOT use agent settings (since it is
30
+ # for agentless operation), specifically it ignores:
31
+ #
32
+ # - c.agent.host
33
+ # - DD_AGENT_HOST
34
+ # - c.agent.port
35
+ # - DD_AGENT_PORT
36
+ #
37
+ # However, agentless resolver does respect the timeout specified via
38
+ # c.agent.timeout_seconds or DD_TRACE_AGENT_TIMEOUT_SECONDS.
39
+ class AgentlessSettingsResolver < AgentSettingsResolver
40
+ # To avoid coupling this class to telemetry, the URL override is
41
+ # taken here as a parameter instead of being read out of
42
+ # c.telemetry.agentless_url_override. For the same reason, the
43
+ # +url_override_source+ parameter should be set to the string
44
+ # "c.telemetry.agentless_url_override".
45
+ def self.call(settings, host_prefix:, url_override: nil, url_override_source: nil, logger: Datadog.logger)
46
+ new(
47
+ settings,
48
+ host_prefix: host_prefix,
49
+ url_override: url_override,
50
+ url_override_source: url_override_source,
51
+ logger: logger
52
+ ).send(:call)
53
+ end
54
+
55
+ private
56
+
57
+ attr_reader \
58
+ :host_prefix,
59
+ :url_override,
60
+ :url_override_source
61
+
62
+ def initialize(settings, host_prefix:, url_override: nil, url_override_source: nil, logger: Datadog.logger)
63
+ if url_override && url_override_source.nil?
64
+ raise ArgumentError, 'url_override_source must be provided when url_override is provided'
65
+ end
66
+
67
+ super(settings, logger: logger)
68
+
69
+ @host_prefix = host_prefix
70
+ @url_override = url_override
71
+ @url_override_source = url_override_source
72
+ end
73
+
74
+ def hostname
75
+ if should_use_uds?
76
+ nil
77
+ else
78
+ configured_hostname || "#{host_prefix}.#{settings.site}"
79
+ end
80
+ end
81
+
82
+ def configured_hostname
83
+ return @configured_hostname if defined?(@configured_hostname)
84
+
85
+ if should_use_uds?
86
+ nil
87
+ else
88
+ @configured_hostname = (parsed_url.hostname if parsed_url)
89
+ end
90
+ end
91
+
92
+ def configured_port
93
+ return @configured_port if defined?(@configured_port)
94
+
95
+ @configured_port = (parsed_url.port if parsed_url)
96
+ end
97
+
98
+ # Note that this method should always return true or false
99
+ def ssl?
100
+ if configured_hostname
101
+ configured_ssl || false
102
+ else
103
+ if should_use_uds?
104
+ false
105
+ else
106
+ # If no hostname is specified, we are communicating with the
107
+ # default Datadog intake, which uses TLS.
108
+ true
109
+ end
110
+ end
111
+ end
112
+
113
+ # Note that this method can return nil
114
+ def configured_ssl
115
+ return @configured_ssl if defined?(@configured_ssl)
116
+
117
+ @configured_ssl = (parsed_url_ssl? if parsed_url)
118
+ end
119
+
120
+ def port
121
+ if configured_port
122
+ configured_port
123
+ else
124
+ if should_use_uds?
125
+ nil
126
+ else
127
+ # If no hostname is specified, we are communicating with the
128
+ # default Datadog intake, which exists on port 443.
129
+ 443
130
+ end
131
+ end
132
+ end
133
+
134
+ def mixed_http_and_uds
135
+ false
136
+ end
137
+
138
+ def configured_uds_path
139
+ return @configured_uds_path if defined?(@configured_uds_path)
140
+
141
+ parsed_url_uds_path
142
+ end
143
+
144
+ def can_use_uds?
145
+ # While in theory agentless transport could communicate via UDS,
146
+ # in practice "agentless" means we are communicating with Datadog
147
+ # infrastructure which is always remote.
148
+ # Permit UDS for proxy usage?
149
+ !configured_uds_path.nil?
150
+ end
151
+
152
+ def parsed_url
153
+ return @parsed_url if defined?(@parsed_url)
154
+
155
+ @parsed_url =
156
+ if @url_override
157
+ parsed = URI.parse(@url_override)
158
+
159
+ # Agentless URL should never refer to a UDS?
160
+ if http_scheme?(parsed) || unix_scheme?(parsed)
161
+ parsed
162
+ else
163
+ log_warning(
164
+ "Invalid URI scheme '#{parsed.scheme}' for #{url_override_source}. " \
165
+ "Ignoring the contents of #{url_override_source}."
166
+ )
167
+ nil
168
+ end
169
+ end
170
+ end
171
+ end
172
+ end
173
+ end
174
+ end
175
+
176
+ # rubocop:enable Style/*
@@ -14,9 +14,11 @@ require_relative '../../tracing/component'
14
14
  require_relative '../../profiling/component'
15
15
  require_relative '../../appsec/component'
16
16
  require_relative '../../di/component'
17
+ require_relative '../../error_tracking/component'
17
18
  require_relative '../crashtracking/component'
18
19
 
19
20
  require_relative '../environment/agent_info'
21
+ require_relative '../process_discovery'
20
22
 
21
23
  module Datadog
22
24
  module Core
@@ -26,12 +28,12 @@ module Datadog
26
28
  class << self
27
29
  include Datadog::Tracing::Component
28
30
 
29
- def build_health_metrics(settings, logger)
31
+ def build_health_metrics(settings, logger, telemetry)
30
32
  settings = settings.health_metrics
31
33
  options = { enabled: settings.enabled }
32
34
  options[:statsd] = settings.statsd unless settings.statsd.nil?
33
35
 
34
- Core::Diagnostics::Health::Metrics.new(logger: logger, **options)
36
+ Core::Diagnostics::Health::Metrics.new(telemetry: telemetry, logger: logger, **options)
35
37
  end
36
38
 
37
39
  def build_logger(settings)
@@ -41,24 +43,24 @@ module Datadog
41
43
  logger
42
44
  end
43
45
 
44
- def build_runtime_metrics(settings, logger)
46
+ def build_runtime_metrics(settings, logger, telemetry)
45
47
  options = { enabled: settings.runtime_metrics.enabled }
46
48
  options[:statsd] = settings.runtime_metrics.statsd unless settings.runtime_metrics.statsd.nil?
47
49
  options[:services] = [settings.service] unless settings.service.nil?
48
50
  options[:experimental_runtime_id_enabled] = settings.runtime_metrics.experimental_runtime_id_enabled
49
51
 
50
- Core::Runtime::Metrics.new(logger: logger, **options)
52
+ Core::Runtime::Metrics.new(logger: logger, telemetry: telemetry, **options)
51
53
  end
52
54
 
53
- def build_runtime_metrics_worker(settings, logger)
55
+ def build_runtime_metrics_worker(settings, logger, telemetry)
54
56
  # NOTE: Should we just ignore building the worker if its not enabled?
55
57
  options = settings.runtime_metrics.opts.merge(
56
58
  enabled: settings.runtime_metrics.enabled,
57
- metrics: build_runtime_metrics(settings, logger),
59
+ metrics: build_runtime_metrics(settings, logger, telemetry),
58
60
  logger: logger,
59
61
  )
60
62
 
61
- Core::Workers::RuntimeMetrics.new(options)
63
+ Core::Workers::RuntimeMetrics.new(telemetry: telemetry, **options)
62
64
  end
63
65
 
64
66
  def build_telemetry(settings, agent_settings, logger)
@@ -68,7 +70,7 @@ module Datadog
68
70
  def build_crashtracker(settings, agent_settings, logger:)
69
71
  return unless settings.crashtracking.enabled
70
72
 
71
- if (libdatadog_api_failure = Datadog::Core::Crashtracking::Component::LIBDATADOG_API_FAILURE)
73
+ if (libdatadog_api_failure = Datadog::Core::LIBDATADOG_API_FAILURE)
72
74
  logger.debug("Cannot enable crashtracking: #{libdatadog_api_failure}")
73
75
  return
74
76
  end
@@ -88,6 +90,7 @@ module Datadog
88
90
  :telemetry,
89
91
  :tracer,
90
92
  :crashtracker,
93
+ :error_tracking,
91
94
  :dynamic_instrumentation,
92
95
  :appsec,
93
96
  :agent_info
@@ -118,11 +121,14 @@ module Datadog
118
121
  )
119
122
  @environment_logger_extra.merge!(profiler_logger_extra) if profiler_logger_extra
120
123
 
121
- @runtime_metrics = self.class.build_runtime_metrics_worker(settings, @logger)
122
- @health_metrics = self.class.build_health_metrics(settings, @logger)
124
+ @runtime_metrics = self.class.build_runtime_metrics_worker(settings, @logger, telemetry)
125
+ @health_metrics = self.class.build_health_metrics(settings, @logger, telemetry)
123
126
  @appsec = Datadog::AppSec::Component.build_appsec_component(settings, telemetry: telemetry)
124
127
  @dynamic_instrumentation = Datadog::DI::Component.build(settings, agent_settings, @logger, telemetry: telemetry)
128
+ @error_tracking = Datadog::ErrorTracking::Component.build(settings, @tracer, @logger)
125
129
  @environment_logger_extra[:dynamic_instrumentation_enabled] = !!@dynamic_instrumentation
130
+ # TODO: Re-enable this once we have updated libdatadog to 17.1
131
+ # @process_discovery_fd = Core::ProcessDiscovery.get_and_store_metadata(settings, @logger)
126
132
 
127
133
  self.class.configure_tracing(settings)
128
134
  end
@@ -203,6 +209,9 @@ module Datadog
203
209
  # enqueue closing event before stopping telemetry so it will be send out on shutdown
204
210
  telemetry.emit_closing! unless replacement
205
211
  telemetry.stop!
212
+
213
+ # TODO: Re-enable this once we have updated libdatadog to 17.1
214
+ # Core::ProcessDiscovery._native_close_tracer_memfd(@process_discovery_fd, @logger) if @process_discovery_fd
206
215
  end
207
216
  end
208
217
  end
@@ -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
@@ -79,7 +79,7 @@ module Datadog
79
79
 
80
80
  # @return [String] current time in ISO8601 format
81
81
  def date
82
- Time.now.utc.iso8601
82
+ Core::Utils::Time.now.utc.iso8601
83
83
  end
84
84
 
85
85
  # Best portable guess of OS information.
@@ -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