datadog 2.30.0 → 2.32.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 (219) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +44 -1
  3. data/ext/datadog_profiling_native_extension/collectors_cpu_and_wall_time_worker.c +17 -7
  4. data/ext/datadog_profiling_native_extension/collectors_thread_context.c +11 -4
  5. data/ext/datadog_profiling_native_extension/collectors_thread_context.h +6 -0
  6. data/ext/datadog_profiling_native_extension/datadog_ruby_common.c +18 -0
  7. data/ext/datadog_profiling_native_extension/datadog_ruby_common.h +10 -0
  8. data/ext/datadog_profiling_native_extension/extconf.rb +7 -4
  9. data/ext/datadog_profiling_native_extension/http_transport.c +10 -5
  10. data/ext/libdatadog_api/crashtracker.c +5 -8
  11. data/ext/libdatadog_api/datadog_ruby_common.c +18 -0
  12. data/ext/libdatadog_api/datadog_ruby_common.h +10 -0
  13. data/ext/libdatadog_api/di.c +127 -0
  14. data/ext/libdatadog_api/extconf.rb +9 -4
  15. data/ext/libdatadog_api/init.c +5 -2
  16. data/ext/libdatadog_extconf_helpers.rb +46 -1
  17. data/lib/datadog/ai_guard/component.rb +2 -0
  18. data/lib/datadog/ai_guard/configuration.rb +105 -2
  19. data/lib/datadog/ai_guard/contrib/ruby_llm/chat_instrumentation.rb +41 -3
  20. data/lib/datadog/ai_guard/evaluation/content_builder.rb +31 -0
  21. data/lib/datadog/ai_guard/evaluation/content_part.rb +36 -0
  22. data/lib/datadog/ai_guard/evaluation/no_op_result.rb +3 -1
  23. data/lib/datadog/ai_guard/evaluation/request.rb +14 -9
  24. data/lib/datadog/ai_guard/evaluation/result.rb +3 -1
  25. data/lib/datadog/ai_guard/evaluation.rb +37 -7
  26. data/lib/datadog/ai_guard/ext.rb +1 -0
  27. data/lib/datadog/ai_guard.rb +26 -8
  28. data/lib/datadog/appsec/autoload.rb +1 -1
  29. data/lib/datadog/appsec/component.rb +11 -7
  30. data/lib/datadog/appsec/configuration.rb +414 -1
  31. data/lib/datadog/appsec/contrib/devise/patches/signin_tracking_patch.rb +2 -1
  32. data/lib/datadog/appsec/contrib/rack/gateway/watcher.rb +6 -7
  33. data/lib/datadog/appsec/instrumentation/gateway.rb +0 -13
  34. data/lib/datadog/appsec/metrics/telemetry.rb +13 -1
  35. data/lib/datadog/appsec/monitor/gateway/watcher.rb +2 -0
  36. data/lib/datadog/appsec/security_engine/runner.rb +1 -1
  37. data/lib/datadog/appsec/trace_keeper.rb +18 -6
  38. data/lib/datadog/appsec/utils/http/media_type.rb +1 -2
  39. data/lib/datadog/appsec/utils/http/url_encoded.rb +3 -3
  40. data/lib/datadog/appsec.rb +5 -9
  41. data/lib/datadog/core/configuration/base.rb +17 -5
  42. data/lib/datadog/core/configuration/components.rb +22 -9
  43. data/lib/datadog/core/configuration/config_helper.rb +9 -0
  44. data/lib/datadog/core/configuration/option.rb +30 -5
  45. data/lib/datadog/core/configuration/option_definition.rb +38 -12
  46. data/lib/datadog/core/configuration/options.rb +40 -6
  47. data/lib/datadog/core/configuration/settings.rb +18 -0
  48. data/lib/datadog/core/configuration/supported_configurations.rb +3 -0
  49. data/lib/datadog/core/configuration.rb +1 -1
  50. data/lib/datadog/core/contrib/rails/railtie.rb +32 -0
  51. data/lib/datadog/core/contrib/rails/utils.rb +7 -3
  52. data/lib/datadog/core/crashtracking/component.rb +3 -3
  53. data/lib/datadog/core/diagnostics/environment_logger.rb +3 -1
  54. data/lib/datadog/core/environment/container.rb +2 -2
  55. data/lib/datadog/core/environment/ext.rb +1 -0
  56. data/lib/datadog/core/environment/identity.rb +25 -3
  57. data/lib/datadog/core/environment/process.rb +12 -0
  58. data/lib/datadog/core/feature_flags.rb +1 -1
  59. data/lib/datadog/core/metrics/client.rb +5 -5
  60. data/lib/datadog/core/remote/client.rb +1 -1
  61. data/lib/datadog/core/remote/component.rb +38 -21
  62. data/lib/datadog/core/runtime/metrics.rb +1 -1
  63. data/lib/datadog/core/telemetry/component.rb +3 -0
  64. data/lib/datadog/core/telemetry/emitter.rb +1 -1
  65. data/lib/datadog/core/telemetry/event/app_client_configuration_change.rb +2 -3
  66. data/lib/datadog/core/telemetry/event/app_extended_heartbeat.rb +32 -0
  67. data/lib/datadog/core/telemetry/event/app_started.rb +151 -169
  68. data/lib/datadog/core/telemetry/event.rb +1 -7
  69. data/lib/datadog/core/telemetry/ext.rb +1 -0
  70. data/lib/datadog/core/telemetry/transport/http/telemetry.rb +5 -0
  71. data/lib/datadog/core/telemetry/worker.rb +20 -0
  72. data/lib/datadog/core/transport/http.rb +2 -0
  73. data/lib/datadog/core/utils/only_once.rb +1 -1
  74. data/lib/datadog/core/utils/spawn_monkey_patch.rb +36 -0
  75. data/lib/datadog/core/utils.rb +1 -1
  76. data/lib/datadog/core/workers/async.rb +1 -1
  77. data/lib/datadog/core.rb +1 -2
  78. data/lib/datadog/data_streams/configuration.rb +40 -1
  79. data/lib/datadog/data_streams/pathway_context.rb +1 -1
  80. data/lib/datadog/data_streams/processor.rb +1 -1
  81. data/lib/datadog/data_streams.rb +1 -1
  82. data/lib/datadog/di/base.rb +8 -5
  83. data/lib/datadog/di/boot.rb +2 -4
  84. data/lib/datadog/di/code_tracker.rb +179 -1
  85. data/lib/datadog/di/component.rb +5 -1
  86. data/lib/datadog/di/configuration.rb +235 -2
  87. data/lib/datadog/di/instrumenter.rb +55 -29
  88. data/lib/datadog/di/probe_builder.rb +1 -1
  89. data/lib/datadog/di/probe_file_loader.rb +2 -2
  90. data/lib/datadog/di/probe_manager.rb +6 -6
  91. data/lib/datadog/di/probe_notification_builder.rb +110 -2
  92. data/lib/datadog/di/probe_notifier_worker.rb +2 -2
  93. data/lib/datadog/di/remote.rb +6 -6
  94. data/lib/datadog/di/transport/input.rb +3 -3
  95. data/lib/datadog/di.rb +81 -0
  96. data/lib/datadog/error_tracking/configuration.rb +55 -2
  97. data/lib/datadog/kit/enable_core_dumps.rb +1 -1
  98. data/lib/datadog/open_feature/component.rb +18 -1
  99. data/lib/datadog/open_feature/evaluation_engine.rb +2 -2
  100. data/lib/datadog/open_feature/hooks/flag_eval_hook.rb +49 -0
  101. data/lib/datadog/open_feature/metrics/flag_eval_metrics.rb +149 -0
  102. data/lib/datadog/open_feature/provider.rb +19 -1
  103. data/lib/datadog/open_feature/remote.rb +1 -1
  104. data/lib/datadog/open_feature/transport.rb +1 -1
  105. data/lib/datadog/opentelemetry/configuration/settings.rb +2 -0
  106. data/lib/datadog/opentelemetry/metrics.rb +3 -3
  107. data/lib/datadog/opentelemetry/sdk/configurator.rb +1 -1
  108. data/lib/datadog/opentelemetry/sdk/metrics_exporter.rb +1 -1
  109. data/lib/datadog/profiling/collectors/code_provenance.rb +36 -11
  110. data/lib/datadog/profiling/collectors/cpu_and_wall_time_worker.rb +31 -2
  111. data/lib/datadog/profiling/collectors/idle_sampling_helper.rb +8 -2
  112. data/lib/datadog/profiling/collectors/info.rb +16 -3
  113. data/lib/datadog/profiling/component.rb +12 -4
  114. data/lib/datadog/profiling/exporter.rb +37 -12
  115. data/lib/datadog/profiling/ext.rb +0 -2
  116. data/lib/datadog/profiling/flush.rb +21 -12
  117. data/lib/datadog/profiling/http_transport.rb +12 -1
  118. data/lib/datadog/profiling/load_native_extension.rb +2 -2
  119. data/lib/datadog/profiling/profiler.rb +13 -5
  120. data/lib/datadog/profiling/scheduler.rb +2 -2
  121. data/lib/datadog/profiling/tasks/exec.rb +8 -3
  122. data/lib/datadog/profiling/tasks/help.rb +1 -0
  123. data/lib/datadog/profiling/tasks/setup.rb +2 -2
  124. data/lib/datadog/profiling.rb +1 -2
  125. data/lib/datadog/single_step_instrument.rb +1 -1
  126. data/lib/datadog/symbol_database/configuration.rb +65 -0
  127. data/lib/datadog/symbol_database/extractor.rb +915 -0
  128. data/lib/datadog/symbol_database/file_hash.rb +46 -0
  129. data/lib/datadog/symbol_database/logger.rb +43 -0
  130. data/lib/datadog/symbol_database/scope.rb +98 -0
  131. data/lib/datadog/symbol_database/service_version.rb +57 -0
  132. data/lib/datadog/symbol_database/symbol.rb +66 -0
  133. data/lib/datadog/symbol_database/transport/http/endpoint.rb +28 -0
  134. data/lib/datadog/symbol_database/transport/http.rb +45 -0
  135. data/lib/datadog/symbol_database/transport.rb +54 -0
  136. data/lib/datadog/symbol_database/uploader.rb +166 -0
  137. data/lib/datadog/symbol_database.rb +49 -0
  138. data/lib/datadog/tracing/buffer.rb +3 -3
  139. data/lib/datadog/tracing/component.rb +11 -0
  140. data/lib/datadog/tracing/configuration/settings.rb +2 -1
  141. data/lib/datadog/tracing/contrib/action_pack/action_controller/instrumentation.rb +5 -3
  142. data/lib/datadog/tracing/contrib/action_pack/action_dispatch/instrumentation.rb +20 -0
  143. data/lib/datadog/tracing/contrib/action_pack/action_dispatch/patcher.rb +3 -1
  144. data/lib/datadog/tracing/contrib/action_view/events/render_template.rb +1 -1
  145. data/lib/datadog/tracing/contrib/active_job/events/discard.rb +1 -1
  146. data/lib/datadog/tracing/contrib/active_job/events/enqueue.rb +1 -1
  147. data/lib/datadog/tracing/contrib/active_job/events/enqueue_at.rb +1 -1
  148. data/lib/datadog/tracing/contrib/active_job/events/enqueue_retry.rb +1 -1
  149. data/lib/datadog/tracing/contrib/active_job/events/perform.rb +1 -1
  150. data/lib/datadog/tracing/contrib/active_job/events/retry_stopped.rb +1 -1
  151. data/lib/datadog/tracing/contrib/active_model_serializers/events/render.rb +1 -1
  152. data/lib/datadog/tracing/contrib/active_model_serializers/events/serialize.rb +1 -1
  153. data/lib/datadog/tracing/contrib/active_record/configuration/resolver.rb +2 -2
  154. data/lib/datadog/tracing/contrib/active_record/events/instantiation.rb +1 -1
  155. data/lib/datadog/tracing/contrib/active_record/events/sql.rb +1 -1
  156. data/lib/datadog/tracing/contrib/active_record/utils.rb +1 -1
  157. data/lib/datadog/tracing/contrib/active_support/cache/events/cache.rb +1 -1
  158. data/lib/datadog/tracing/contrib/active_support/notifications/subscription.rb +2 -2
  159. data/lib/datadog/tracing/contrib/aws/instrumentation.rb +1 -1
  160. data/lib/datadog/tracing/contrib/component.rb +1 -1
  161. data/lib/datadog/tracing/contrib/configurable.rb +18 -3
  162. data/lib/datadog/tracing/contrib/configuration/resolver.rb +7 -4
  163. data/lib/datadog/tracing/contrib/dalli/quantize.rb +1 -1
  164. data/lib/datadog/tracing/contrib/elasticsearch/patcher.rb +1 -1
  165. data/lib/datadog/tracing/contrib/excon/middleware.rb +2 -2
  166. data/lib/datadog/tracing/contrib/extensions.rb +9 -0
  167. data/lib/datadog/tracing/contrib/faraday/middleware.rb +2 -2
  168. data/lib/datadog/tracing/contrib/grape/endpoint.rb +5 -5
  169. data/lib/datadog/tracing/contrib/grpc/datadog_interceptor/client.rb +2 -2
  170. data/lib/datadog/tracing/contrib/grpc/datadog_interceptor/server.rb +2 -2
  171. data/lib/datadog/tracing/contrib/http/instrumentation.rb +3 -3
  172. data/lib/datadog/tracing/contrib/httpclient/instrumentation.rb +6 -2
  173. data/lib/datadog/tracing/contrib/httprb/instrumentation.rb +3 -3
  174. data/lib/datadog/tracing/contrib/kafka/instrumentation/consumer.rb +2 -2
  175. data/lib/datadog/tracing/contrib/kafka/instrumentation/producer.rb +2 -2
  176. data/lib/datadog/tracing/contrib/karafka/patcher.rb +1 -1
  177. data/lib/datadog/tracing/contrib/mongodb/subscribers.rb +3 -3
  178. data/lib/datadog/tracing/contrib/opensearch/patcher.rb +1 -1
  179. data/lib/datadog/tracing/contrib/presto/instrumentation.rb +3 -3
  180. data/lib/datadog/tracing/contrib/rack/patcher.rb +1 -1
  181. data/lib/datadog/tracing/contrib/rack/request_queue.rb +1 -1
  182. data/lib/datadog/tracing/contrib/rails/log_injection.rb +1 -1
  183. data/lib/datadog/tracing/contrib/rails/patcher.rb +0 -1
  184. data/lib/datadog/tracing/contrib/rails/runner.rb +1 -1
  185. data/lib/datadog/tracing/contrib/rake/instrumentation.rb +2 -2
  186. data/lib/datadog/tracing/contrib/redis/quantize.rb +1 -1
  187. data/lib/datadog/tracing/contrib/redis/tags.rb +1 -1
  188. data/lib/datadog/tracing/contrib/sidekiq/utils.rb +1 -1
  189. data/lib/datadog/tracing/contrib/status_range_matcher.rb +4 -0
  190. data/lib/datadog/tracing/contrib/stripe/request.rb +1 -1
  191. data/lib/datadog/tracing/contrib.rb +8 -0
  192. data/lib/datadog/tracing/diagnostics/environment_logger.rb +3 -1
  193. data/lib/datadog/tracing/distributed/baggage.rb +59 -5
  194. data/lib/datadog/tracing/distributed/datadog.rb +13 -11
  195. data/lib/datadog/tracing/distributed/datadog_tags_codec.rb +1 -1
  196. data/lib/datadog/tracing/distributed/propagation.rb +2 -2
  197. data/lib/datadog/tracing/distributed/trace_context.rb +74 -32
  198. data/lib/datadog/tracing/event.rb +1 -1
  199. data/lib/datadog/tracing/metadata/tagging.rb +2 -2
  200. data/lib/datadog/tracing/pipeline.rb +1 -1
  201. data/lib/datadog/tracing/remote.rb +1 -1
  202. data/lib/datadog/tracing/sampling/ext.rb +2 -0
  203. data/lib/datadog/tracing/sampling/priority_sampler.rb +13 -0
  204. data/lib/datadog/tracing/sampling/rule.rb +1 -1
  205. data/lib/datadog/tracing/sampling/rule_sampler.rb +54 -25
  206. data/lib/datadog/tracing/sampling/span/rule_parser.rb +2 -2
  207. data/lib/datadog/tracing/span_operation.rb +4 -4
  208. data/lib/datadog/tracing/trace_operation.rb +53 -9
  209. data/lib/datadog/tracing/tracer.rb +29 -4
  210. data/lib/datadog/tracing/transport/io/client.rb +1 -1
  211. data/lib/datadog/tracing/transport/trace_formatter.rb +1 -1
  212. data/lib/datadog/tracing/workers.rb +2 -1
  213. data/lib/datadog/version.rb +1 -1
  214. metadata +27 -12
  215. data/lib/datadog/ai_guard/configuration/settings.rb +0 -113
  216. data/lib/datadog/appsec/configuration/settings.rb +0 -423
  217. data/lib/datadog/data_streams/configuration/settings.rb +0 -49
  218. data/lib/datadog/di/configuration/settings.rb +0 -243
  219. data/lib/datadog/error_tracking/configuration/settings.rb +0 -63
@@ -12,6 +12,7 @@ require_relative '../telemetry/component'
12
12
  require_relative '../workers/runtime_metrics'
13
13
  require_relative '../remote/component'
14
14
  require_relative '../utils/at_fork_monkey_patch'
15
+ require_relative '../utils/spawn_monkey_patch'
15
16
  require_relative '../utils/only_once'
16
17
  require_relative '../../tracing/component'
17
18
  require_relative '../../profiling/component'
@@ -22,6 +23,7 @@ require_relative '../../open_feature/component'
22
23
  require_relative '../../error_tracking/component'
23
24
  require_relative '../crashtracking/component'
24
25
  require_relative '../environment/agent_info'
26
+ require_relative '../environment/identity'
25
27
  require_relative '../process_discovery'
26
28
  require_relative '../../data_streams/processor'
27
29
 
@@ -31,7 +33,7 @@ module Datadog
31
33
  # Global components for the trace library.
32
34
  class Components
33
35
  # Class-level constant to ensure fork patch is applied only once
34
- AT_FORK_ONLY_ONCE = Utils::OnlyOnce.new
36
+ PATCH_ONLY_ONCE = Utils::OnlyOnce.new
35
37
 
36
38
  class << self
37
39
  def build_health_metrics(settings, logger, telemetry)
@@ -96,7 +98,7 @@ module Datadog
96
98
  agent_info: agent_info
97
99
  )
98
100
  rescue => e
99
- logger.warn("Failed to initialize Data Streams Monitoring: #{e.class}: #{e}")
101
+ logger.warn("Failed to initialize Data Streams Monitoring: #{e.class}: #{e.message}")
100
102
  nil
101
103
  end
102
104
  end
@@ -128,8 +130,11 @@ module Datadog
128
130
  Deprecations.log_deprecations_from_all_sources(@logger)
129
131
 
130
132
  # Register fork handling once globally
131
- self.class::AT_FORK_ONLY_ONCE.run do
133
+ self.class::PATCH_ONLY_ONCE.run do
132
134
  Utils::AtForkMonkeyPatch.apply!
135
+ Utils::SpawnMonkeyPatch.apply!(
136
+ lineage_envs_provider: Core::Environment::Identity.method(:runtime_propagation_envs),
137
+ )
133
138
 
134
139
  # Register callback that calls Components.after_fork
135
140
  Utils::AtForkMonkeyPatch.at_fork(:child) do
@@ -172,6 +177,11 @@ module Datadog
172
177
 
173
178
  # Configure non-privileged components.
174
179
  Datadog::Tracing::Contrib::Component.configure(settings)
180
+
181
+ # Load the core Rails Railtie when Rails is present so all products benefit from Rails-specific setup.
182
+ if defined?(::Rails::Railtie)
183
+ require_relative '../contrib/rails/railtie'
184
+ end
175
185
  end
176
186
 
177
187
  # Called when a fork is detected
@@ -204,14 +214,13 @@ module Datadog
204
214
  end
205
215
  end
206
216
 
207
- if settings.remote.enabled && old_state&.remote_started?
217
+ if remote && old_state&.remote_started?
208
218
  # The library was reconfigured and previously it already started
209
219
  # the remote component (i.e., it received at least one request
210
220
  # through the installed Rack middleware which started the remote).
211
221
  # If the new configuration also has remote enabled, start the
212
222
  # new remote right away.
213
- # remote should always be not nil here but steep doesn't know this.
214
- remote&.start
223
+ remote.start
215
224
  end
216
225
 
217
226
  # This should stay here, not in initialize. During reconfiguration, the order of the calls is:
@@ -279,11 +288,15 @@ module Datadog
279
288
  unused_statsd = (old_statsd - (old_statsd & new_statsd))
280
289
  unused_statsd.each(&:close)
281
290
 
282
- # enqueue closing event before stopping telemetry so it will be sent out on shutdown
291
+ Core::ProcessDiscovery.shutdown!
292
+
293
+ # Shut down telemetry last so that all other components may
294
+ # report shutdown errors.
295
+ #
296
+ # Enqueue closing event before stopping telemetry so it will be
297
+ # sent out on shutdown.
283
298
  telemetry.emit_closing! unless replacement&.telemetry&.enabled
284
299
  telemetry.shutdown!
285
-
286
- Core::ProcessDiscovery.shutdown!
287
300
  end
288
301
 
289
302
  # Returns the current state of various components.
@@ -40,6 +40,12 @@ module Datadog
40
40
  !get_environment_variable(name).nil?
41
41
  end
42
42
 
43
+ # Returns the source environment as a Hash. Used when the full environment
44
+ # must be passed through (e.g. Process.spawn child env).
45
+ def to_h
46
+ @source_env.to_h
47
+ end
48
+
43
49
  alias_method :has_key?, :key?
44
50
  alias_method :include?, :key?
45
51
  alias_method :member?, :key?
@@ -97,4 +103,7 @@ module Datadog
97
103
  end
98
104
  end
99
105
  end
106
+ unless const_defined?(:DATADOG_ENV, false)
107
+ DATADOG_ENV = Core::Configuration::ConfigHelper.new
108
+ end
100
109
  end
@@ -77,6 +77,16 @@ module Datadog
77
77
  @precedence_set = Precedence::DEFAULT
78
78
  end
79
79
 
80
+ # Computes the name of the option with the settings path.
81
+ # E.g. "tracing.rails.middleware_names" for the "middleware_names" option in the "tracing.rails" settings.
82
+ # @return [String] the name of the option with the settings path
83
+ def name_with_settings_path
84
+ @name_with_settings_path ||= begin
85
+ settings_path = @context.class.settings_path
86
+ settings_path.nil? ? definition.name.to_s : "#{settings_path}.#{definition.name}"
87
+ end
88
+ end
89
+
80
90
  # Overrides the current value for this option if the `precedence` is equal or higher than
81
91
  # the previously set value.
82
92
  # The first call to `#set` will always store the value regardless of precedence.
@@ -89,7 +99,7 @@ module Datadog
89
99
  # This should be uncommon, as higher precedence values tend to
90
100
  # happen later in the application lifecycle.
91
101
  Datadog.logger.info do
92
- "Option '#{definition.name}' not changed to '#{value}' (precedence: #{precedence.name}) because the higher " \
102
+ "Option '#{name_with_settings_path}' not changed to '#{value}' (precedence: #{precedence.name}) because the higher " \
93
103
  "precedence value '#{@value}' (precedence: #{@precedence_set.name}) was already set."
94
104
  end
95
105
 
@@ -178,6 +188,21 @@ module Datadog
178
188
  precedence_set == Precedence::DEFAULT
179
189
  end
180
190
 
191
+ def settings?
192
+ @definition.is_settings
193
+ end
194
+
195
+ def values_per_precedence
196
+ # value_per_precedence is only filled after we call `get` once.
197
+ get unless @is_set
198
+
199
+ @value_per_precedence.each_with_object({}) do |(precedence, value), result|
200
+ next if value.equal?(UNSET)
201
+
202
+ result[precedence] = value
203
+ end
204
+ end
205
+
181
206
  private
182
207
 
183
208
  def coerce_env_variable(value)
@@ -216,7 +241,7 @@ module Datadog
216
241
  value
217
242
  else
218
243
  raise InvalidDefinitionError,
219
- "The option #{@definition.name} is using an unsupported type option for env coercion `#{@definition.type}`"
244
+ "The option #{name_with_settings_path} is using an unsupported type option for env coercion `#{@definition.type}`"
220
245
  end
221
246
  end
222
247
 
@@ -239,10 +264,10 @@ module Datadog
239
264
 
240
265
  if raise_error
241
266
  error_msg = if @definition.type_options[:nilable]
242
- "The setting `#{@definition.name}` inside your app's `Datadog.configure` block expects a " \
267
+ "The setting `#{name_with_settings_path}` inside your app's `Datadog.configure` block expects a " \
243
268
  "#{@definition.type} or `nil`, but a `#{value.class}` was provided (#{value.inspect})." \
244
269
  else
245
- "The setting `#{@definition.name}` inside your app's `Datadog.configure` block expects a " \
270
+ "The setting `#{name_with_settings_path}` inside your app's `Datadog.configure` block expects a " \
246
271
  "#{@definition.type}, but a `#{value.class}` was provided (#{value.inspect})." \
247
272
  end
248
273
 
@@ -276,7 +301,7 @@ module Datadog
276
301
  true # No validation is performed when option is typeless
277
302
  else
278
303
  raise InvalidDefinitionError,
279
- "The option #{@definition.name} is using an unsupported type option `#{@definition.type}`"
304
+ "The option #{name_with_settings_path} is using an unsupported type option `#{@definition.type}`"
280
305
  end
281
306
  end
282
307
 
@@ -10,28 +10,36 @@ module Datadog
10
10
  IDENTITY = ->(new_value, _old_value) { new_value }
11
11
 
12
12
  attr_reader \
13
+ :is_settings,
13
14
  :default,
14
15
  :default_proc,
15
16
  :env,
16
17
  :env_parser,
17
18
  :name,
18
19
  :after_set,
20
+ :skip_telemetry,
19
21
  :resetter,
20
22
  :setter,
21
23
  :type,
22
24
  :type_options
23
25
 
24
- def initialize(name, meta, &block)
25
- @default = meta[:default]
26
- @default_proc = meta[:default_proc]
27
- @env = meta[:env]
28
- @env_parser = meta[:env_parser]
26
+ def initialize(name, attributes, &block)
27
+ # When a settings is defined using the config DSL, an option is also created.
28
+ # See Datadog::Core::Configuration::Base::ClassMethods#settings for more details.
29
+ # This flag is used to indicate that the option is a settings option.
30
+ @is_settings = attributes[:is_settings]
31
+
32
+ @default = attributes[:default]
33
+ @default_proc = attributes[:default_proc]
34
+ @env = attributes[:env]
35
+ @env_parser = attributes[:env_parser]
29
36
  @name = name.to_sym
30
- @after_set = meta[:after_set]
31
- @resetter = meta[:resetter]
32
- @setter = meta[:setter] || block || IDENTITY
33
- @type = meta[:type]
34
- @type_options = meta[:type_options]
37
+ @after_set = attributes[:after_set]
38
+ @skip_telemetry = attributes[:skip_telemetry]
39
+ @resetter = attributes[:resetter]
40
+ @setter = attributes[:setter] || block || IDENTITY
41
+ @type = attributes[:type]
42
+ @type_options = attributes[:type_options]
35
43
  end
36
44
 
37
45
  # Creates a new Option, bound to the context provided.
@@ -49,6 +57,8 @@ module Datadog
49
57
  :helpers
50
58
 
51
59
  def initialize(name, options = {})
60
+ @is_settings = options.fetch(:is_settings, false)
61
+
52
62
  @env = nil
53
63
  @env_parser = nil
54
64
  @default = nil
@@ -56,6 +66,7 @@ module Datadog
56
66
  @helpers = {}
57
67
  @name = name.to_sym
58
68
  @after_set = nil
69
+ @skip_telemetry = false
59
70
  @resetter = nil
60
71
  @setter = OptionDefinition::IDENTITY
61
72
  @type = nil
@@ -95,6 +106,16 @@ module Datadog
95
106
  @after_set = block
96
107
  end
97
108
 
109
+ # This should only be set to true for options that are manually modified
110
+ # before being added to the telemetry payload in app_started.rb.
111
+ # E.g. telemetry is skipped for `tracing.writer_options`, but in app_started.rb,
112
+ # we send two separate entries for the buffer_size and flush_interval values.
113
+ # Standard: We want to keep this method as skip_telemetry(value),
114
+ # not skip_telemetry = value, so attr_writer is not used.
115
+ def skip_telemetry(value) # standard:disable Style/TrivialAccessors
116
+ @skip_telemetry = value
117
+ end
118
+
98
119
  def resetter(&block)
99
120
  @resetter = block
100
121
  end
@@ -119,6 +140,8 @@ module Datadog
119
140
  env(options[:env]) if options.key?(:env)
120
141
  env_parser(&options[:env_parser]) if options.key?(:env_parser)
121
142
  after_set(&options[:after_set]) if options.key?(:after_set)
143
+ # Steep: https://github.com/soutaro/steep/issues/1979
144
+ skip_telemetry(options[:skip_telemetry]) if options.key?(:skip_telemetry) # steep:ignore ArgumentTypeMismatch
122
145
  resetter(&options[:resetter]) if options.key?(:resetter)
123
146
  # Steep: https://github.com/soutaro/steep/issues/1979
124
147
  setter(&options[:setter]) if options.key?(:setter) # steep:ignore BlockTypeMismatch
@@ -126,16 +149,19 @@ module Datadog
126
149
  end
127
150
 
128
151
  def to_definition
129
- OptionDefinition.new(@name, meta)
152
+ OptionDefinition.new(@name, attributes)
130
153
  end
131
154
 
132
- def meta
155
+ def attributes
133
156
  {
157
+ is_settings: @is_settings,
158
+
134
159
  default: @default,
135
160
  default_proc: @default_proc,
136
161
  env: @env,
137
162
  env_parser: @env_parser,
138
163
  after_set: @after_set,
164
+ skip_telemetry: @skip_telemetry,
139
165
  resetter: @resetter,
140
166
  setter: @setter,
141
167
  type: @type,
@@ -16,17 +16,47 @@ module Datadog
16
16
  # Class behavior for a configuration object with options
17
17
  # @public_api
18
18
  module ClassMethods
19
+ def settings_path
20
+ defined?(@settings_path) ? @settings_path : nil
21
+ end
22
+
23
+ # Registry of nested settings classes keyed by the option name declared
24
+ # via `Base.settings`. This lets us propagate a new settings path down the
25
+ # tree without storing parent references on the nested class or on the
26
+ # option definition itself.
27
+ def settings_children
28
+ @settings_children ||= if superclass <= Options
29
+ superclass.settings_children.dup
30
+ else
31
+ {}
32
+ end
33
+ end
34
+
35
+ def settings_path=(path)
36
+ @settings_path = path
37
+
38
+ # Keep nested settings paths in sync when a parent settings path is
39
+ # assigned later, which is how contrib integrations inject
40
+ # "tracing.<integration>" into their configuration classes.
41
+ settings_children.each do |name, settings_class|
42
+ nested_settings_path = path ? "#{path}.#{name}" : name.to_s
43
+ settings_class.settings_path = nested_settings_path
44
+ end
45
+ end
46
+
19
47
  def options
20
48
  # Allows for class inheritance of option definitions
21
- @options ||= (superclass <= Options) ? superclass.options.dup : {}
49
+ @options ||= if superclass <= Options
50
+ superclass.options.dup
51
+ else
52
+ {}
53
+ end
22
54
  end
23
55
 
24
56
  protected
25
57
 
26
- def option(name, meta = {}, &block)
27
- settings_name = defined?(@settings_name) && @settings_name
28
- option_name = settings_name ? "#{settings_name}.#{name}" : name
29
- builder = OptionDefinition::Builder.new(option_name, meta, &block)
58
+ def option(name, attributes = {}, &block)
59
+ builder = OptionDefinition::Builder.new(name, attributes, &block)
30
60
  options[name] = builder.to_definition.tap do
31
61
  # Resolve and define helper functions
32
62
  helpers = default_helpers(name)
@@ -75,7 +105,11 @@ module Datadog
75
105
  end
76
106
 
77
107
  def set_option(name, value, precedence: Configuration::Option::Precedence::PROGRAMMATIC)
78
- resolve_option(name).set(value, precedence: precedence)
108
+ option = resolve_option(name)
109
+ # Populate lower-precedence values so telemetry and `unset` can
110
+ # still observe the fallback chain after a first programmatic set.
111
+ option.get
112
+ option.set(value, precedence: precedence)
79
113
  end
80
114
 
81
115
  def unset_option(name, precedence: Configuration::Option::Precedence::PROGRAMMATIC)
@@ -13,6 +13,7 @@ require_relative '../../profiling/ext'
13
13
 
14
14
  require_relative '../../tracing/configuration/settings'
15
15
  require_relative '../../opentelemetry/configuration/settings'
16
+ require_relative '../../symbol_database/configuration'
16
17
 
17
18
  module Datadog
18
19
  module Core
@@ -221,6 +222,8 @@ module Datadog
221
222
  #
222
223
  # @return Logger::Severity
223
224
  option :instance do |o|
225
+ # Telemetry for this option is manually modified and added in the AppStarted event.
226
+ o.skip_telemetry true
224
227
  o.after_set { |value| set_option(:level, value.level) unless value.nil? }
225
228
  end
226
229
 
@@ -912,6 +915,19 @@ module Datadog
912
915
  o.default 60.0
913
916
  end
914
917
 
918
+ # The interval in seconds when extended heartbeat must be sent.
919
+ #
920
+ # This method is used internally, for testing purposes only.
921
+ #
922
+ # @default `DD_TELEMETRY_EXTENDED_HEARTBEAT_INTERVAL` environment variable, otherwise `86400`.
923
+ # @return [Integer]
924
+ # @!visibility private
925
+ option :extended_heartbeat_interval_seconds do |o|
926
+ o.type :int
927
+ o.env Core::Telemetry::Ext::ENV_EXTENDED_HEARTBEAT_INTERVAL
928
+ o.default 86400
929
+ end
930
+
915
931
  # The interval in seconds when telemetry metrics are aggregated.
916
932
  # Should be a denominator of `heartbeat_interval_seconds`.
917
933
  #
@@ -1096,6 +1112,8 @@ module Datadog
1096
1112
  extend Datadog::Tracing::Configuration::Settings
1097
1113
 
1098
1114
  extend Datadog::OpenTelemetry::Configuration::Settings
1115
+
1116
+ extend Datadog::SymbolDatabase::Configuration::Settings
1099
1117
  end
1100
1118
  # standard:enable Metrics/BlockLength
1101
1119
  end
@@ -67,6 +67,7 @@ module Datadog
67
67
  "DD_INSTRUMENTATION_INSTALL_TIME",
68
68
  "DD_INSTRUMENTATION_INSTALL_TYPE",
69
69
  "DD_INSTRUMENTATION_TELEMETRY_ENABLED",
70
+ "DD_INTERNAL_FORCE_SYMBOL_DATABASE_UPLOAD",
70
71
  "DD_LOGS_INJECTION",
71
72
  "DD_METRICS_OTEL_ENABLED",
72
73
  "DD_METRIC_AGENT_PORT",
@@ -104,9 +105,11 @@ module Datadog
104
105
  "DD_SITE",
105
106
  "DD_SPAN_SAMPLING_RULES",
106
107
  "DD_SPAN_SAMPLING_RULES_FILE",
108
+ "DD_SYMBOL_DATABASE_UPLOAD_ENABLED",
107
109
  "DD_TAGS",
108
110
  "DD_TELEMETRY_AGENTLESS_URL",
109
111
  "DD_TELEMETRY_DEPENDENCY_COLLECTION_ENABLED",
112
+ "DD_TELEMETRY_EXTENDED_HEARTBEAT_INTERVAL",
110
113
  "DD_TELEMETRY_HEARTBEAT_INTERVAL",
111
114
  "DD_TELEMETRY_LOG_COLLECTION_ENABLED",
112
115
  "DD_TELEMETRY_METRICS_AGGREGATION_INTERVAL",
@@ -238,7 +238,7 @@ module Datadog
238
238
  yield write_components
239
239
  rescue ThreadError => e
240
240
  logger_without_components.error(
241
- "Detected deadlock during datadog initialization: #{e.class}: #{e}. " \
241
+ "Detected deadlock during datadog initialization: #{e.class}: #{e.message}. " \
242
242
  'Please report this at https://github.com/datadog/dd-trace-rb/blob/master/CONTRIBUTING.md#found-a-bug' \
243
243
  "\n\tSource:\n\t#{Array(e.backtrace).join("\n\t")}"
244
244
  )
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'utils'
4
+ require_relative '../../environment/process'
5
+ require_relative '../../process_discovery'
6
+
7
+ module Datadog
8
+ module Core
9
+ module Contrib
10
+ module Rails
11
+ # Railtie for core Rails setup that benefits all Datadog products.
12
+ class Railtie < ::Rails::Railtie
13
+ def self.after_initialize
14
+ if Datadog.configuration.experimental_propagate_process_tags_enabled
15
+ Datadog::Core::Environment::Process.rails_application_name =
16
+ Datadog::Core::Contrib::Rails::Utils.app_name
17
+ end
18
+
19
+ # Process Discovery should always publish after_initialize since it has access to more information
20
+ Datadog::Core::ProcessDiscovery.publish(Datadog.configuration)
21
+ end
22
+
23
+ # Registered after the method definition so the method exists if on_load fires immediately
24
+ # (which happens when the Railtie is loaded into an already-initialized Rails app).
25
+ ::ActiveSupport.on_load(:after_initialize) do
26
+ Datadog::Core::Contrib::Rails::Railtie.after_initialize
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -7,11 +7,15 @@ module Datadog
7
7
  # common utilities for Rails
8
8
  module Utils
9
9
  def self.app_name
10
- if ::Rails::VERSION::MAJOR >= 6
11
- ::Rails.application.class.module_parent_name.underscore
10
+ application_name = if ::Rails::VERSION::MAJOR >= 6
11
+ ::Rails.application.class.module_parent_name
12
12
  else
13
- ::Rails.application.class.parent_name.underscore
13
+ ::Rails.application.class.parent_name
14
14
  end
15
+ application_name&.underscore
16
+ rescue => e
17
+ Datadog.logger.debug("Failed to extract Rails application name: #{e.class}: #{e.message}")
18
+ nil
15
19
  end
16
20
 
17
21
  def self.railtie_supported?
@@ -55,7 +55,7 @@ module Datadog
55
55
  # Unhandled exception report triggering means that the application is already in a bad state
56
56
  # We don't want to swallow non-StandardError exceptions here; we would rather just let the
57
57
  # application crash
58
- Datadog.logger.debug("Crashtracker failed to report unhandled exception: #{e.message}")
58
+ Datadog.logger.debug { "Crashtracker failed to report unhandled exception: #{e.class}: #{e.message}" }
59
59
  end
60
60
  end
61
61
 
@@ -130,7 +130,7 @@ module Datadog
130
130
  self.class._native_stop
131
131
  logger.debug('Crash tracking stopped successfully')
132
132
  rescue => e
133
- logger.error("Failed to stop crash tracking: #{e.message}")
133
+ logger.error("Failed to stop crash tracking: #{e.class}: #{e.message}")
134
134
  end
135
135
 
136
136
  private
@@ -149,7 +149,7 @@ module Datadog
149
149
  )
150
150
  logger.debug("Crash tracking action: #{action} successful")
151
151
  rescue => e
152
- logger.error("Failed to #{action} crash tracking: #{e.message}")
152
+ logger.error("Failed to #{action} crash tracking: #{e.class}: #{e.message}")
153
153
  end
154
154
  end
155
155
  end
@@ -52,7 +52,9 @@ module Datadog
52
52
  log_configuration!('CORE', data.to_json)
53
53
  end
54
54
  rescue => e
55
- logger.warn("Failed to collect core environment information: #{e} Location: #{Array(e.backtrace).first}")
55
+ logger.warn(
56
+ "Failed to collect core environment information: #{e.class}: #{e.message} Location: #{Array(e.backtrace).first}"
57
+ )
56
58
  end
57
59
  end
58
60
 
@@ -108,7 +108,7 @@ module Datadog
108
108
  end
109
109
  rescue => e
110
110
  Datadog.logger.debug(
111
- "Error while checking cgroup namespace. Cause: #{e.class.name} #{e.message} Location: #{Array(e.backtrace).first}"
111
+ "Error while checking cgroup namespace. Cause: #{e.class}: #{e.message} Location: #{Array(e.backtrace).first}"
112
112
  )
113
113
  false
114
114
  end
@@ -172,7 +172,7 @@ module Datadog
172
172
  @entry = Entry.new # Empty entry if no valid cgroup entry is found
173
173
  rescue => e
174
174
  Datadog.logger.debug(
175
- "Error while reading container entry. Cause: #{e.class.name} #{e.message} Location: #{Array(e.backtrace).first}"
175
+ "Error while reading container entry. Cause: #{e.class}: #{e.message} Location: #{Array(e.backtrace).first}"
176
176
  )
177
177
  @entry = Entry.new unless defined?(@entry)
178
178
  @entry
@@ -41,6 +41,7 @@ module Datadog
41
41
  TAG_ENTRYPOINT_NAME = "entrypoint.name"
42
42
  TAG_ENTRYPOINT_WORKDIR = "entrypoint.workdir"
43
43
  TAG_ENTRYPOINT_TYPE = "entrypoint.type"
44
+ TAG_RAILS_APPLICATION = "rails.application"
44
45
  TAG_PROCESS_TAGS = "_dd.tags.process"
45
46
  TAG_SERVICE = 'service'
46
47
  TAG_VERSION = 'version'
@@ -2,6 +2,7 @@
2
2
 
3
3
  require 'securerandom'
4
4
 
5
+ require_relative '../configuration/config_helper'
5
6
  require_relative 'ext'
6
7
  require_relative '../utils/forking'
7
8
 
@@ -13,18 +14,39 @@ module Datadog
13
14
  module Identity
14
15
  extend Core::Utils::Forking
15
16
 
17
+ ENV_ROOT_SESSION_ID = '_DD_ROOT_RB_SESSION_ID'
18
+ ENV_PARENT_SESSION_ID = '_DD_PARENT_RB_SESSION_ID'
19
+
16
20
  module_function
17
21
 
18
- # Retrieves number of classes from runtime
22
+ @root_runtime_id = DATADOG_ENV[ENV_ROOT_SESSION_ID]&.freeze
23
+ @parent_runtime_id = DATADOG_ENV[ENV_PARENT_SESSION_ID]&.freeze
24
+
19
25
  def id
20
26
  @id ||= ::SecureRandom.uuid.freeze
21
27
 
22
- # Check if runtime has changed, e.g. forked.
23
- after_fork! { @id = ::SecureRandom.uuid.freeze }
28
+ after_fork! do
29
+ # Order matters: capture @id before overwriting
30
+ @parent_runtime_id = @id
31
+ @root_runtime_id ||= @id
32
+ @id = ::SecureRandom.uuid.freeze
33
+ end
24
34
 
25
35
  @id
26
36
  end
27
37
 
38
+ def root_runtime_id
39
+ @root_runtime_id
40
+ end
41
+
42
+ def parent_runtime_id
43
+ @parent_runtime_id
44
+ end
45
+
46
+ def runtime_propagation_envs
47
+ {ENV_ROOT_SESSION_ID => root_runtime_id || id, ENV_PARENT_SESSION_ID => id}.freeze
48
+ end
49
+
28
50
  def pid
29
51
  ::Process.pid
30
52
  end
@@ -35,6 +35,9 @@ module Datadog
35
35
 
36
36
  tags << "#{Environment::Ext::TAG_ENTRYPOINT_TYPE}:#{TagNormalizer.normalize(entrypoint_type, remove_digit_start_char: false)}"
37
37
 
38
+ rails_application_name = TagNormalizer.normalize_process_value(@rails_application_name.to_s)
39
+ tags << "#{Environment::Ext::TAG_RAILS_APPLICATION}:#{rails_application_name}" unless rails_application_name.empty?
40
+
38
41
  @tags = tags.freeze
39
42
  end
40
43
 
@@ -80,6 +83,15 @@ module Datadog
80
83
  File.basename(File.expand_path(File.dirname($0)))
81
84
  end
82
85
 
86
+ # Sets the rails application name from other places in code
87
+ # @param name [String] the rails application name
88
+ # @return [void]
89
+ def self.rails_application_name=(name)
90
+ @rails_application_name = name
91
+ remove_instance_variable(:@tags) if instance_variable_defined?(:@tags)
92
+ remove_instance_variable(:@serialized) if instance_variable_defined?(:@serialized)
93
+ end
94
+
83
95
  private_class_method :entrypoint_workdir, :entrypoint_type, :entrypoint_name, :entrypoint_basedir
84
96
  end
85
97
  end
@@ -37,7 +37,7 @@ module Datadog
37
37
  # moved into C extension
38
38
  @value = json?(value) ? JSON.parse(value) : value
39
39
  rescue JSON::ParserError => e
40
- raise Error, "Failed to parse JSON value: #{e.class}: #{e}"
40
+ raise Error, "Failed to parse JSON value: #{e.class}: #{e.message}"
41
41
  end
42
42
 
43
43
  # Check if the resolution resulted in an error