datadog 2.39.0 → 2.41.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 (158) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +97 -44
  3. data/ext/datadog_profiling_native_extension/collectors_stack.c +219 -148
  4. data/ext/datadog_profiling_native_extension/collectors_stack.h +16 -2
  5. data/ext/datadog_profiling_native_extension/collectors_thread_context.c +12 -7
  6. data/ext/datadog_profiling_native_extension/crashtracking_runtime_stacks.c +5 -4
  7. data/ext/datadog_profiling_native_extension/datadog_ruby_common.c +19 -11
  8. data/ext/datadog_profiling_native_extension/datadog_ruby_common.h +7 -0
  9. data/ext/datadog_profiling_native_extension/extconf.rb +12 -7
  10. data/ext/datadog_profiling_native_extension/native_extension_helpers.rb +3 -3
  11. data/ext/datadog_profiling_native_extension/private_vm_api_access.c +284 -76
  12. data/ext/datadog_profiling_native_extension/private_vm_api_access.h +16 -10
  13. data/ext/libdatadog_api/datadog_ruby_common.c +19 -11
  14. data/ext/libdatadog_api/datadog_ruby_common.h +7 -0
  15. data/ext/libdatadog_api/init.c +4 -0
  16. data/ext/libdatadog_api/trace_exporter.c +1312 -0
  17. data/ext/libdatadog_api/trace_exporter.h +5 -0
  18. data/ext/libdatadog_extconf_helpers.rb +1 -1
  19. data/lib/datadog/ai_guard/api_client.rb +1 -1
  20. data/lib/datadog/ai_guard/evaluation/request.rb +8 -8
  21. data/lib/datadog/ai_guard/evaluation.rb +11 -3
  22. data/lib/datadog/ai_guard/ext.rb +3 -1
  23. data/lib/datadog/appsec/actions_handler/serializable_backtrace.rb +21 -42
  24. data/lib/datadog/appsec/api_security/endpoint_collection/grape_route_serializer.rb +1 -1
  25. data/lib/datadog/appsec/api_security/endpoint_collection/rails_route_serializer.rb +1 -1
  26. data/lib/datadog/appsec/api_security/endpoint_collection/sinatra_route_serializer.rb +1 -1
  27. data/lib/datadog/appsec/configuration.rb +11 -2
  28. data/lib/datadog/appsec/context.rb +1 -1
  29. data/lib/datadog/appsec/contrib/active_record/instrumentation.rb +1 -1
  30. data/lib/datadog/appsec/contrib/aws_lambda/waf_addresses.rb +2 -2
  31. data/lib/datadog/appsec/contrib/devise/configuration.rb +1 -1
  32. data/lib/datadog/appsec/contrib/devise/patcher.rb +1 -1
  33. data/lib/datadog/appsec/contrib/excon/ssrf_detection_middleware.rb +2 -2
  34. data/lib/datadog/appsec/contrib/faraday/ssrf_detection_middleware.rb +2 -2
  35. data/lib/datadog/appsec/contrib/graphql/gateway/watcher.rb +1 -1
  36. data/lib/datadog/appsec/contrib/rack/ext.rb +2 -2
  37. data/lib/datadog/appsec/contrib/rack/gateway/watcher.rb +2 -2
  38. data/lib/datadog/appsec/contrib/rack/patcher.rb +1 -1
  39. data/lib/datadog/appsec/contrib/rack/request_body_middleware.rb +6 -3
  40. data/lib/datadog/appsec/contrib/rails/gateway/watcher.rb +2 -2
  41. data/lib/datadog/appsec/contrib/rails/request_middleware.rb +2 -1
  42. data/lib/datadog/appsec/contrib/rest_client/request_ssrf_detection_patch.rb +2 -2
  43. data/lib/datadog/appsec/contrib/sinatra/gateway/watcher.rb +2 -2
  44. data/lib/datadog/appsec/contrib/sinatra/request_middleware.rb +2 -1
  45. data/lib/datadog/appsec/processor/rule_loader.rb +12 -12
  46. data/lib/datadog/appsec/response.rb +1 -1
  47. data/lib/datadog/appsec/route_normalizer/route_pattern.rb +3 -3
  48. data/lib/datadog/appsec/security_engine/engine.rb +3 -3
  49. data/lib/datadog/core/configuration/components.rb +2 -2
  50. data/lib/datadog/core/configuration/option_definition.rb +1 -1
  51. data/lib/datadog/core/configuration/options.rb +1 -1
  52. data/lib/datadog/core/configuration/settings.rb +33 -41
  53. data/lib/datadog/core/configuration/supported_configurations.rb +3 -0
  54. data/lib/datadog/core/diagnostics/environment_logger.rb +36 -1
  55. data/lib/datadog/core/environment/gc.rb +1 -1
  56. data/lib/datadog/core/environment/vm_cache.rb +1 -1
  57. data/lib/datadog/core/environment/yjit.rb +2 -2
  58. data/lib/datadog/core/metrics/helpers.rb +1 -1
  59. data/lib/datadog/core/metrics/options.rb +2 -2
  60. data/lib/datadog/core/process_discovery.rb +1 -1
  61. data/lib/datadog/core/remote/client.rb +1 -1
  62. data/lib/datadog/core/remote/configuration/repository.rb +2 -2
  63. data/lib/datadog/core/telemetry/configuration_value.rb +38 -0
  64. data/lib/datadog/core/telemetry/event/app_client_configuration_change.rb +3 -1
  65. data/lib/datadog/core/telemetry/event/app_endpoints_loaded.rb +1 -1
  66. data/lib/datadog/core/telemetry/event/app_started.rb +5 -24
  67. data/lib/datadog/core/telemetry/event/generate_metrics.rb +1 -1
  68. data/lib/datadog/core/telemetry/event/log.rb +2 -2
  69. data/lib/datadog/core/telemetry/event/synth_app_client_configuration_change.rb +1 -1
  70. data/lib/datadog/core/telemetry/metric.rb +2 -2
  71. data/lib/datadog/core/telemetry/request.rb +2 -2
  72. data/lib/datadog/core/transport/http.rb +1 -1
  73. data/lib/datadog/core/transport/transport.rb +1 -1
  74. data/lib/datadog/core/utils/at_fork_monkey_patch.rb +170 -18
  75. data/lib/datadog/core/utils/sequence.rb +3 -6
  76. data/lib/datadog/core/utils/time.rb +16 -54
  77. data/lib/datadog/data_streams/processor.rb +14 -14
  78. data/lib/datadog/di/el/compiler.rb +88 -12
  79. data/lib/datadog/di/el/evaluator.rb +82 -2
  80. data/lib/datadog/di/el/expression.rb +13 -2
  81. data/lib/datadog/di/instrumenter.rb +5 -4
  82. data/lib/datadog/di/probe_builder.rb +7 -6
  83. data/lib/datadog/di/probe_notification_builder.rb +2 -2
  84. data/lib/datadog/di/serializer.rb +29 -4
  85. data/lib/datadog/error_tracking/component.rb +1 -1
  86. data/lib/datadog/kit/appsec/events/v2.rb +2 -2
  87. data/lib/datadog/open_feature/exposures/batch_builder.rb +1 -1
  88. data/lib/datadog/open_feature/exposures/event.rb +5 -5
  89. data/lib/datadog/profiling/collectors/info.rb +1 -1
  90. data/lib/datadog/profiling/collectors/thread_context.rb +6 -13
  91. data/lib/datadog/profiling/component.rb +1 -0
  92. data/lib/datadog/profiling/tasks/exec.rb +1 -1
  93. data/lib/datadog/profiling.rb +4 -0
  94. data/lib/datadog/symbol_database/extractor.rb +6 -6
  95. data/lib/datadog/tracing/component.rb +21 -0
  96. data/lib/datadog/tracing/configuration/dynamic/option.rb +4 -0
  97. data/lib/datadog/tracing/configuration/dynamic.rb +5 -3
  98. data/lib/datadog/tracing/configuration/ext.rb +1 -0
  99. data/lib/datadog/tracing/configuration/settings.rb +16 -0
  100. data/lib/datadog/tracing/contrib/action_cable/events.rb +1 -1
  101. data/lib/datadog/tracing/contrib/action_mailer/events.rb +1 -1
  102. data/lib/datadog/tracing/contrib/action_pack/action_controller/instrumentation.rb +2 -2
  103. data/lib/datadog/tracing/contrib/action_view/events.rb +1 -1
  104. data/lib/datadog/tracing/contrib/active_model_serializers/events.rb +1 -1
  105. data/lib/datadog/tracing/contrib/active_record/configuration/resolver.rb +1 -1
  106. data/lib/datadog/tracing/contrib/active_record/events.rb +1 -1
  107. data/lib/datadog/tracing/contrib/active_support/cache/events/cache.rb +2 -2
  108. data/lib/datadog/tracing/contrib/aws/ext.rb +1 -1
  109. data/lib/datadog/tracing/contrib/aws/services.rb +1 -1
  110. data/lib/datadog/tracing/contrib/elasticsearch/quantize.rb +1 -1
  111. data/lib/datadog/tracing/contrib/ext.rb +3 -3
  112. data/lib/datadog/tracing/contrib/grpc/datadog_interceptor/client.rb +1 -1
  113. data/lib/datadog/tracing/contrib/grpc/datadog_interceptor/server.rb +1 -1
  114. data/lib/datadog/tracing/contrib/grpc/distributed/propagation.rb +1 -1
  115. data/lib/datadog/tracing/contrib/hanami/router_tracing.rb +2 -1
  116. data/lib/datadog/tracing/contrib/kafka/events/connection/request.rb +4 -0
  117. data/lib/datadog/tracing/contrib/kafka/events/produce_operation/send_messages.rb +7 -2
  118. data/lib/datadog/tracing/contrib/kafka/events/producer/deliver_messages.rb +7 -2
  119. data/lib/datadog/tracing/contrib/kafka/events.rb +1 -1
  120. data/lib/datadog/tracing/contrib/karafka/distributed/propagation.rb +1 -1
  121. data/lib/datadog/tracing/contrib/mongodb/parsers.rb +1 -1
  122. data/lib/datadog/tracing/contrib/opensearch/ext.rb +1 -1
  123. data/lib/datadog/tracing/contrib/opensearch/quantize.rb +1 -1
  124. data/lib/datadog/tracing/contrib/patchable.rb +1 -1
  125. data/lib/datadog/tracing/contrib/patcher.rb +1 -1
  126. data/lib/datadog/tracing/contrib/que/tracer.rb +1 -1
  127. data/lib/datadog/tracing/contrib/racecar/events.rb +1 -1
  128. data/lib/datadog/tracing/contrib/rack/configuration/settings.rb +1 -1
  129. data/lib/datadog/tracing/contrib/rack/header_tagging.rb +1 -1
  130. data/lib/datadog/tracing/contrib/rack/patcher.rb +1 -1
  131. data/lib/datadog/tracing/contrib/rack/trace_proxy_middleware.rb +1 -1
  132. data/lib/datadog/tracing/contrib/redis/configuration/resolver.rb +1 -1
  133. data/lib/datadog/tracing/contrib/redis/quantize.rb +36 -2
  134. data/lib/datadog/tracing/contrib/redis/trace_middleware.rb +9 -3
  135. data/lib/datadog/tracing/contrib/sequel/database.rb +1 -5
  136. data/lib/datadog/tracing/contrib/sequel/utils.rb +1 -1
  137. data/lib/datadog/tracing/contrib/sidekiq/distributed/propagation.rb +1 -1
  138. data/lib/datadog/tracing/contrib/sinatra/configuration/settings.rb +1 -1
  139. data/lib/datadog/tracing/contrib/sneakers/tracer.rb +1 -1
  140. data/lib/datadog/tracing/contrib/utils/quantization/hash_formatter.rb +1 -1
  141. data/lib/datadog/tracing/contrib/waterdrop/distributed/propagation.rb +1 -1
  142. data/lib/datadog/tracing/correlation.rb +2 -2
  143. data/lib/datadog/tracing/diagnostics/environment_logger.rb +2 -2
  144. data/lib/datadog/tracing/distributed/baggage.rb +1 -2
  145. data/lib/datadog/tracing/distributed/propagation_policy.rb +5 -0
  146. data/lib/datadog/tracing/metadata/tagging.rb +1 -1
  147. data/lib/datadog/tracing/remote.rb +2 -2
  148. data/lib/datadog/tracing/span.rb +1 -1
  149. data/lib/datadog/tracing/span_operation.rb +1 -1
  150. data/lib/datadog/tracing/sync_writer.rb +8 -3
  151. data/lib/datadog/tracing/tracer.rb +8 -0
  152. data/lib/datadog/tracing/transport/io/traces.rb +1 -1
  153. data/lib/datadog/tracing/transport/native/response.rb +71 -0
  154. data/lib/datadog/tracing/transport/native.rb +387 -0
  155. data/lib/datadog/tracing/transport/trace_formatter.rb +1 -1
  156. data/lib/datadog/tracing/writer.rb +17 -4
  157. data/lib/datadog/version.rb +1 -1
  158. metadata +12 -7
@@ -1,5 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative "../../ruby_version"
4
+
5
+ require "timeout" if Datadog::RubyVersion.is?("< 3.2")
6
+
3
7
  module Datadog
4
8
  module DI
5
9
  module EL
@@ -7,6 +11,20 @@ module Datadog
7
11
  #
8
12
  # @api private
9
13
  class Evaluator
14
+ # Maximum wall-clock time allowed for evaluating a single `matches`
15
+ # operator.
16
+ MATCHES_TIMEOUT_SECONDS = 0.5
17
+
18
+ # @param regexps [Array<Regexp>] Regexps precompiled from literal
19
+ # `matches` patterns, looked up by index by #matches_compiled.
20
+ # Empty when the expression has no `matches` pattern with
21
+ # a direct regular expression argument.
22
+ def initialize(regexps = [])
23
+ @regexps = regexps
24
+ end
25
+
26
+ attr_reader :regexps
27
+
10
28
  def ref(var)
11
29
  @context.fetch(var)
12
30
  end
@@ -48,10 +66,72 @@ module Datadog
48
66
  end
49
67
  end
50
68
 
69
+ # Build a Regexp from a pattern string. On Ruby 3.2+ the per-match
70
+ # timeout (MATCHES_TIMEOUT_SECONDS) is baked into the compiled
71
+ # Regexp via the in-engine `timeout:` keyword, which interrupts the
72
+ # matcher at every backtrack step and reliably bounds matcher
73
+ # runtime regardless of pattern shape. On older Rubies the Regexp
74
+ # carries no timeout; the bound is applied at match time by
75
+ # #bounded_match? instead.
76
+ #
77
+ # @param needle [String] regexp source.
78
+ # @return [Regexp] compiled regexp, with baked-in timeout on Ruby 3.2+.
79
+ if Datadog::RubyVersion.is?(">= 3.2")
80
+ def self.compile_regexp(needle)
81
+ Regexp.new(needle, timeout: MATCHES_TIMEOUT_SECONDS)
82
+ end
83
+ else
84
+ def self.compile_regexp(needle)
85
+ Regexp.compile(needle)
86
+ end
87
+ end
88
+
89
+ # Match +haystack+ against a regexp whose needle is computed at
90
+ # evaluation time, so the Regexp cannot be precompiled. Literal needles are
91
+ # precompiled by the Compiler and dispatched to #matches_compiled.
92
+ #
93
+ # @param haystack [String] string to match against.
94
+ # @param needle [String] regexp source.
95
+ # @return [Boolean] whether the haystack matches the regexp.
96
+ # @raise [Regexp::TimeoutError] (Ruby 3.2+) regexp engine exceeded MATCHES_TIMEOUT_SECONDS.
97
+ # @raise [Timeout::Error] (Ruby < 3.2) Timeout.timeout fired.
51
98
  def matches(haystack, needle)
52
- re = Regexp.compile(needle)
53
- !!(haystack =~ re)
99
+ bounded_match?(Evaluator.compile_regexp(needle), haystack)
100
+ end
101
+
102
+ # Match +haystack+ against a Regexp precompiled at expression-compile
103
+ # time, looked up by index in +regexps+.
104
+ #
105
+ # @param haystack [String] string to match against.
106
+ # @param index [Integer] position of the precompiled Regexp in +regexps+.
107
+ # @return [Boolean] whether the haystack matches the regexp.
108
+ # @raise [Regexp::TimeoutError] (Ruby 3.2+) regexp engine exceeded MATCHES_TIMEOUT_SECONDS.
109
+ # @raise [Timeout::Error] (Ruby < 3.2) Timeout.timeout fired.
110
+ def matches_compiled(haystack, index)
111
+ bounded_match?(regexps.fetch(index), haystack)
112
+ end
113
+
114
+ # Match +haystack+ against +re+, bounded at MATCHES_TIMEOUT_SECONDS
115
+ # wall-clock.
116
+ #
117
+ # @param re [Regexp] regexp to match against.
118
+ # @param haystack [String] string to match against.
119
+ # @return [Boolean] whether the haystack matches the regexp.
120
+ if Datadog::RubyVersion.is?(">= 3.2")
121
+ def bounded_match?(re, haystack)
122
+ # Uses Regexp#match? rather than =~ so that the
123
+ # thread-local match data ($~, $1, ...) is not mutated as a side
124
+ # effect of DI expression evaluation.
125
+ re.match?(haystack)
126
+ end
127
+ else
128
+ def bounded_match?(re, haystack)
129
+ Timeout.timeout(MATCHES_TIMEOUT_SECONDS) do
130
+ re.match?(haystack)
131
+ end
132
+ end
54
133
  end
134
+ private :bounded_match?
55
135
 
56
136
  def getmember(object, field)
57
137
  object.instance_variable_get("@#{field}")
@@ -7,12 +7,22 @@ module Datadog
7
7
  #
8
8
  # @api private
9
9
  class Expression
10
- def initialize(dsl_expr, compiled_expr)
10
+ # @param dsl_expr [String] human-readable DSL form, kept for debugging.
11
+ # @param compiled_expr [String] Ruby source produced by Compiler#compile.
12
+ # @param regexps [Array<Regexp>] precompiled `matches` regexps (see
13
+ # Compiler#precompile_regexp), the second element returned by
14
+ # Compiler#compile.
15
+ # @param redaction_identifier [String, nil] the identifier this
16
+ # expression directly references at its top level (see
17
+ # Compiler#redaction_identifier); nil when it is not a direct
18
+ # reference.
19
+ def initialize(dsl_expr, compiled_expr, regexps: [], redaction_identifier: nil)
11
20
  unless String === compiled_expr
12
21
  raise ArgumentError, "compiled_expr must be a string"
13
22
  end
14
23
 
15
24
  @dsl_expr = dsl_expr
25
+ @redaction_identifier = redaction_identifier
16
26
 
17
27
  cls = Class.new(Evaluator)
18
28
  cls.class_exec do
@@ -23,11 +33,12 @@ module Datadog
23
33
  end
24
34
  RUBY
25
35
  end
26
- @evaluator = cls.new
36
+ @evaluator = cls.new(regexps)
27
37
  end
28
38
 
29
39
  attr_reader :dsl_expr
30
40
  attr_reader :evaluator
41
+ attr_reader :redaction_identifier
31
42
 
32
43
  def evaluate(context)
33
44
  @evaluator.evaluate(context)
@@ -160,6 +160,7 @@ module Datadog
160
160
  end
161
161
 
162
162
  loc = target_method&.source_location
163
+ # @type var instrumenter: Instrumenter
163
164
  instrumenter = self
164
165
 
165
166
  mod = Module.new do
@@ -193,7 +194,7 @@ module Datadog
193
194
  # user probe on Proc#call cannot intercept the trampoline, and no
194
195
  # Proc is allocated for the block.
195
196
  if RubyVersion.is?(">= 3")
196
- define_method(method_name) do |*args, **kwargs, &target_block| # steep:ignore NoMethod
197
+ define_method(method_name) do |*args, **kwargs, &target_block|
197
198
  # steep:ignore FallbackAny below: Steep cannot narrow the
198
199
  # **kwargs parameter inside this define_method block, so it
199
200
  # falls back to untyped at the super and run_method_probe sites.
@@ -211,7 +212,7 @@ module Datadog
211
212
  end
212
213
  end
213
214
  else
214
- define_method(method_name) do |*args, &target_block| # steep:ignore NoMethod
215
+ define_method(method_name) do |*args, &target_block|
215
216
  if DI.in_probe?
216
217
  return super(*args, &target_block)
217
218
  end
@@ -230,7 +231,7 @@ module Datadog
230
231
  super(*args, &target_block)
231
232
  end
232
233
  end
233
- ruby2_keywords(method_name) if respond_to?(:ruby2_keywords, true) # steep:ignore NoMethod
234
+ ruby2_keywords(method_name) if respond_to?(:ruby2_keywords, true)
234
235
  end
235
236
  end
236
237
 
@@ -461,7 +462,7 @@ module Datadog
461
462
  # @param args [Array] positional arguments passed to the probed method
462
463
  # @param kwargs [Hash{Symbol => Object}] keyword arguments passed to the probed method
463
464
  # @param target_block [Proc, nil] block argument passed to the probed method
464
- # @param target_self [Object] the receiver of the probed method invocation
465
+ # @param target_self [any] the receiver of the probed method invocation
465
466
  # @param probe [Datadog::DI::Probe] the probe whose callback this invocation runs
466
467
  # @param responder [#probe_executed_callback, #probe_condition_evaluation_failed_callback] callback target invoked with the built Context
467
468
  # @param loc [Array(String, Integer), nil] source location of the probed method, or nil for virtual/lazily-defined methods
@@ -45,8 +45,8 @@ module Datadog
45
45
  unless cond_spec["dsl"] && cond_spec["json"]
46
46
  raise ArgumentError, "Malformed condition specification for probe: #{config}"
47
47
  end
48
- compiled = EL::Compiler.new.compile(cond_spec["json"])
49
- EL::Expression.new(cond_spec["dsl"], compiled)
48
+ compiled, regexps = EL::Compiler.new.compile(cond_spec["json"])
49
+ EL::Expression.new(cond_spec["dsl"], compiled, regexps: regexps)
50
50
  end
51
51
  capture_expressions = build_capture_expressions(config["captureExpressions"])
52
52
  capture_expressions = dedup_capture_expressions(capture_expressions, config["id"], logger)
@@ -100,8 +100,8 @@ module Datadog
100
100
  unless Hash === expr_spec && expr_spec["dsl"] && expr_spec["json"]
101
101
  raise ArgumentError, "captureExpressions entry #{name}: missing or malformed expr"
102
102
  end
103
- compiled = EL::Compiler.new.compile(expr_spec["json"])
104
- expr = EL::Expression.new(expr_spec["dsl"], compiled)
103
+ compiled, regexps = EL::Compiler.new.compile(expr_spec["json"])
104
+ expr = EL::Expression.new(expr_spec["dsl"], compiled, regexps: regexps)
105
105
  limits = build_capture_limits(entry["capture"])
106
106
  CaptureExpression.new(name: name, expr: expr, limits: limits)
107
107
  end
@@ -152,8 +152,9 @@ module Datadog
152
152
  unless dsl = segment["dsl"]
153
153
  raise ArgumentError, "Missing dsl for json in segment: #{segment}"
154
154
  end
155
- compiled = EL::Compiler.new.compile(ast)
156
- EL::Expression.new(dsl, compiled)
155
+ compiler = EL::Compiler.new
156
+ compiled, regexps = compiler.compile(ast)
157
+ EL::Expression.new(dsl, compiled, regexps: regexps, redaction_identifier: compiler.redaction_identifier(ast))
157
158
  else
158
159
  # TODO report to telemetry?
159
160
  end
@@ -179,7 +179,7 @@ module Datadog
179
179
  if status == "ERROR"
180
180
  diagnostics[:exception] = { # steep:ignore
181
181
  type: exception ? exception.class.name : "Error",
182
- message: exception ? exception.message : message
182
+ message: exception ? exception.message : message,
183
183
  }
184
184
  end
185
185
 
@@ -405,7 +405,7 @@ module Datadog
405
405
  when String
406
406
  segment
407
407
  when EL::Expression
408
- serializer.serialize_value_for_message(segment.evaluate(context))
408
+ serializer.serialize_value_for_message(segment.evaluate(context), name: segment.redaction_identifier)
409
409
  else
410
410
  raise ArgumentError, "Invalid template segment type: #{segment}"
411
411
  end
@@ -50,6 +50,13 @@ module Datadog
50
50
  # return a safe stub rather than tear the process down.
51
51
  SERIALIZABLE_FATAL_EXCEPTION_CLASSES = [SystemExit, SignalException].freeze
52
52
 
53
+ # Placeholder emitted by #serialize_value_for_message in place of a value
54
+ # whose identifier or type matches the redaction configuration. This
55
+ # mirrors, for the human-readable log-probe message path, the
56
+ # notCapturedReason: "redactedIdent"/"redactedType" gating that
57
+ # #serialize_value applies on the snapshot path.
58
+ REDACTED_VALUE_FOR_MESSAGE = "[redacted]"
59
+
53
60
  # Third-party library integration / custom serializers.
54
61
  #
55
62
  # Dynamic instrumentation has limited payload sizes, and for efficiency
@@ -375,9 +382,17 @@ module Datadog
375
382
  #
376
383
  # We also use the Ruby-like syntax for symbols, which don't exist
377
384
  # in other languages.
378
- def serialize_value_for_message(value, depth = 1)
385
+ #
386
+ # +name+, when given, is the identifier the template expression
387
+ # references at its top level; a redacted identifier yields the
388
+ # redaction placeholder, mirroring #serialize_value on the snapshot path.
389
+ def serialize_value_for_message(value, depth: 1, name: nil)
379
390
  # This method is more verbose than "normal" Ruby code to avoid
380
391
  # array allocations.
392
+
393
+ return REDACTED_VALUE_FOR_MESSAGE if redactor.redact_type?(value)
394
+ return REDACTED_VALUE_FOR_MESSAGE if name && redactor.redact_identifier?(name)
395
+
381
396
  case value
382
397
  when NilClass
383
398
  "nil"
@@ -398,7 +413,7 @@ module Datadog
398
413
  value = value_
399
414
  end
400
415
  "[" + value.map do |item|
401
- serialize_value_for_message(item, depth - 1)
416
+ serialize_value_for_message(item, depth: depth - 1)
402
417
  end.join(", ") + "]"
403
418
  when Hash
404
419
  return "..." if depth <= 0
@@ -413,7 +428,12 @@ module Datadog
413
428
  truncated = true
414
429
  end
415
430
  serialized = keys.map do |key|
416
- "#{serialize_value_for_message(key, depth - 1)} => #{serialize_value_for_message(value[key], depth - 1)}"
431
+ serialized_value = if (String === key || Symbol === key) && redactor.redact_identifier?(key)
432
+ REDACTED_VALUE_FOR_MESSAGE
433
+ else
434
+ serialize_value_for_message(value[key], depth: depth - 1)
435
+ end
436
+ "#{serialize_value_for_message(key, depth: depth - 1)} => #{serialized_value}"
417
437
  end
418
438
  if truncated
419
439
  serialized[serialized.length] = serialized[serialized.length - 1]
@@ -435,7 +455,12 @@ module Datadog
435
455
  serialized = vars.map do |var|
436
456
  # +var+ here is always the instance variable name which is a
437
457
  # symbol, we do not need to run it through our serializer.
438
- "#{var}=#{serialize_value_for_message(value.send(:instance_variable_get, var), depth - 1)}"
458
+ serialized_value = if redactor.redact_identifier?(var)
459
+ REDACTED_VALUE_FOR_MESSAGE
460
+ else
461
+ serialize_value_for_message(value.send(:instance_variable_get, var), depth: depth - 1)
462
+ end
463
+ "#{var}=#{serialized_value}"
439
464
  end
440
465
  if truncated
441
466
  serialized << serialized.last
@@ -154,7 +154,7 @@ module Datadog
154
154
  attributes = {
155
155
  "exception.type" => formatted_exception.type,
156
156
  "exception.message" => formatted_exception.message,
157
- "exception.stacktrace" => formatted_exception.backtrace
157
+ "exception.stacktrace" => formatted_exception.backtrace,
158
158
  }
159
159
  Datadog::Tracing::SpanEvent.new("exception", attributes: attributes)
160
160
  end
@@ -19,7 +19,7 @@ module Datadog
19
19
  TELEMETRY_METRICS_EVENTS_INTO_TYPES = {
20
20
  LOGIN_SUCCESS_EVENT => "login_success",
21
21
  LOGIN_FAILURE_EVENT => "login_failure",
22
- SIGNUP_EVENT => "signup"
22
+ SIGNUP_EVENT => "signup",
23
23
  }.freeze
24
24
 
25
25
  class << self
@@ -241,7 +241,7 @@ module Datadog
241
241
 
242
242
  tags = {
243
243
  event_type: TELEMETRY_METRICS_EVENTS_INTO_TYPES[event],
244
- sdk_version: TELEMETRY_METRICS_SDK_VERSION
244
+ sdk_version: TELEMETRY_METRICS_SDK_VERSION,
245
245
  }
246
246
  telemetry.inc(TELEMETRY_METRICS_NAMESPACE, TELEMETRY_METRICS_SDK_EVENT, 1, tags: tags)
247
247
  end
@@ -12,7 +12,7 @@ module Datadog
12
12
  def payload_for(events)
13
13
  {
14
14
  context: @context,
15
- exposures: events
15
+ exposures: events,
16
16
  }
17
17
  end
18
18
 
@@ -23,18 +23,18 @@ module Datadog
23
23
  {
24
24
  timestamp: current_timestamp_ms,
25
25
  allocation: {
26
- key: result.allocation_key
26
+ key: result.allocation_key,
27
27
  },
28
28
  flag: {
29
- key: flag_key
29
+ key: flag_key,
30
30
  },
31
31
  variant: {
32
- key: result.variant
32
+ key: result.variant,
33
33
  },
34
34
  subject: {
35
35
  id: context.targeting_key,
36
- attributes: extract_attributes(context)
37
- }
36
+ attributes: extract_attributes(context),
37
+ },
38
38
  }.freeze
39
39
  end
40
40
 
@@ -83,7 +83,7 @@ module Datadog
83
83
  hostname: Datadog::Core::Environment::Platform.hostname,
84
84
  kernel_name: Datadog::Core::Environment::Platform.kernel_name,
85
85
  kernel_release: Datadog::Core::Environment::Platform.kernel_release,
86
- kernel_version: Datadog::Core::Environment::Platform.kernel_version
86
+ kernel_version: Datadog::Core::Environment::Platform.kernel_version,
87
87
  }.freeze
88
88
  end
89
89
 
@@ -21,7 +21,8 @@ module Datadog
21
21
  endpoint_collection_enabled:,
22
22
  waiting_for_gvl_threshold_ns:,
23
23
  otel_context_enabled:,
24
- native_filenames_enabled:
24
+ native_filenames_enabled:,
25
+ show_classes:
25
26
  )
26
27
  tracer_context_key = safely_extract_context_key_from(tracer)
27
28
  self.class._native_initialize(
@@ -32,7 +33,8 @@ module Datadog
32
33
  endpoint_collection_enabled: endpoint_collection_enabled,
33
34
  waiting_for_gvl_threshold_ns: waiting_for_gvl_threshold_ns,
34
35
  otel_context_enabled: otel_context_enabled,
35
- native_filenames_enabled: validate_native_filenames(native_filenames_enabled),
36
+ native_filenames_enabled: native_filenames_enabled,
37
+ show_classes: show_classes,
36
38
  overhead_filename: __FILE__,
37
39
  )
38
40
  end
@@ -45,6 +47,7 @@ module Datadog
45
47
  waiting_for_gvl_threshold_ns: 10_000_000,
46
48
  otel_context_enabled: false,
47
49
  native_filenames_enabled: true,
50
+ show_classes: false,
48
51
  trigger_global_reset: true,
49
52
  **options
50
53
  )
@@ -56,6 +59,7 @@ module Datadog
56
59
  waiting_for_gvl_threshold_ns: waiting_for_gvl_threshold_ns,
57
60
  otel_context_enabled: otel_context_enabled,
58
61
  native_filenames_enabled: native_filenames_enabled,
62
+ show_classes: show_classes,
59
63
  **options,
60
64
  )
61
65
 
@@ -90,17 +94,6 @@ module Datadog
90
94
  context = provider.instance_variable_get(:@context)
91
95
  context&.instance_variable_get(:@key)
92
96
  end
93
-
94
- def validate_native_filenames(native_filenames_enabled)
95
- if native_filenames_enabled && !Datadog::Profiling::Collectors::Stack._native_filenames_available?
96
- Datadog.logger.debug(
97
- "Native filenames are enabled, but the required dladdr API was not available. Disabling native filenames."
98
- )
99
- false
100
- else
101
- native_filenames_enabled
102
- end
103
- end
104
97
  end
105
98
  end
106
99
  end
@@ -105,6 +105,7 @@ module Datadog
105
105
  waiting_for_gvl_threshold_ns: settings.profiling.advanced.waiting_for_gvl_threshold_ns,
106
106
  otel_context_enabled: settings.profiling.advanced.preview_otel_context_enabled,
107
107
  native_filenames_enabled: settings.profiling.advanced.native_filenames_enabled,
108
+ show_classes: settings.profiling.advanced.experimental_show_classes_enabled,
108
109
  )
109
110
  end
110
111
 
@@ -21,7 +21,7 @@ module Datadog
21
21
  #: () -> ::Array["-rdatadog/profiling/preload"]
22
22
  def rubyopts
23
23
  [
24
- "-rdatadog/profiling/preload"
24
+ "-rdatadog/profiling/preload",
25
25
  ]
26
26
  end
27
27
 
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "rbconfig"
3
4
  require_relative "core"
4
5
  require_relative "core/environment/variable_helpers"
5
6
  require_relative "core/utils/only_once"
@@ -7,6 +8,9 @@ require_relative "core/utils/only_once"
7
8
  module Datadog
8
9
  # Datadog Continuous Profiler implementation: https://docs.datadoghq.com/profiler/
9
10
  module Profiling
11
+ STATIC_RUBY_PATH = (RbConfig::CONFIG["ENABLE_SHARED"] == "no") ? RbConfig.ruby.freeze : nil
12
+ private_constant :STATIC_RUBY_PATH
13
+
10
14
  def self.supported?
11
15
  unsupported_reason.nil?
12
16
  end
@@ -616,7 +616,7 @@ module Datadog
616
616
  language_specifics: {
617
617
  visibility: method_visibility(klass, method_name),
618
618
  method_type: method_type.to_s,
619
- arity: method.arity
619
+ arity: method.arity,
620
620
  },
621
621
  symbols: extract_method_parameters(method)
622
622
  )
@@ -647,7 +647,7 @@ module Datadog
647
647
  # @param start_line [Integer] Fallback end_line if iseq unavailable
648
648
  # @return [Array(Array<Hash>, Integer), Array(nil, Integer)]
649
649
  def extract_targetable_lines(method, start_line)
650
- iseq = RubyVM::InstructionSequence.of(method) # steep:ignore
650
+ iseq = RubyVM::InstructionSequence.of(method)
651
651
  unless iseq
652
652
  @logger.debug { "symdb: no iseq for #{method.name} (C extension or native), skipping targetable lines" }
653
653
  return [nil, start_line]
@@ -801,7 +801,7 @@ module Datadog
801
801
  # objects allocated to read `source_location` are not retained between
802
802
  # passes, so they can be GC'd as soon as the inner loop ends.
803
803
  def collect_method_names_by_file(mod)
804
- result = Hash.new { |h, k| h[k] = [] } # steep:ignore
804
+ result = Hash.new { |h, k| h[k] = [] }
805
805
 
806
806
  # Module#instance_methods(false) already returns both public and protected
807
807
  # methods, so iterating it plus private_instance_methods covers all three
@@ -905,7 +905,7 @@ module Datadog
905
905
  current[:children][part] ||= {
906
906
  name: fqn, type: resolve_scope_type(fqn),
907
907
  children: {}, methods: [], mod: nil,
908
- source_file: file_path, fqn: fqn
908
+ source_file: file_path, fqn: fqn,
909
909
  }
910
910
  current = current[:children][part]
911
911
  end
@@ -924,7 +924,7 @@ module Datadog
924
924
  type: (Class === mod) ? "CLASS" : "MODULE",
925
925
  children: {}, methods: [],
926
926
  mod: mod, source_file: file_path,
927
- fqn: mod_name
927
+ fqn: mod_name,
928
928
  }
929
929
  current[:children][leaf_name] = leaf
930
930
  end
@@ -1043,7 +1043,7 @@ module Datadog
1043
1043
  language_specifics: {
1044
1044
  visibility: klass ? method_visibility(klass, method_name) : "public", # steep:ignore
1045
1045
  method_type: "instance",
1046
- arity: method.arity
1046
+ arity: method.arity,
1047
1047
  },
1048
1048
  symbols: extract_method_parameters(method)
1049
1049
  )
@@ -104,9 +104,30 @@ module Datadog
104
104
  return writer
105
105
  end
106
106
 
107
+ if settings.tracing.native_transport && (transport = build_native_transport(agent_settings))
108
+ options = options.merge(transport: transport)
109
+ end
110
+
107
111
  Tracing::Writer.new(agent_settings: agent_settings, **options)
108
112
  end
109
113
 
114
+ def build_native_transport(agent_settings)
115
+ require_relative "transport/native"
116
+
117
+ unless Transport::Native.supported?
118
+ Datadog.logger.warn(
119
+ "Native transport requested but not available: #{Transport::Native::UNSUPPORTED_REASON}. " \
120
+ "Falling back to default HTTP transport."
121
+ )
122
+ return nil
123
+ end
124
+
125
+ Transport::Native::Transport.new(
126
+ agent_settings: agent_settings,
127
+ logger: Datadog.logger
128
+ )
129
+ end
130
+
110
131
  def subscribe_to_writer_events!(writer, sampler_delegator, test_mode)
111
132
  return unless writer.respond_to?(:events) # Check if it's a custom, external writer
112
133
 
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative "../../../core/telemetry/configuration_value"
4
+
3
5
  module Datadog
4
6
  module Tracing
5
7
  module Configuration
@@ -56,6 +58,8 @@ module Datadog
56
58
  precedence: Core::Configuration::Option::Precedence::REMOTE_CONFIGURATION
57
59
  )
58
60
  end
61
+
62
+ Core::Telemetry::ConfigurationValue.convert(value)
59
63
  end
60
64
 
61
65
  protected
@@ -24,11 +24,11 @@ module Datadog
24
24
  def call(tracing_header_tags)
25
25
  # Modify the remote configuration value that it matches the
26
26
  # environment variable it configures.
27
- tracing_header_tags&.map! do |hash|
27
+ parsed_header_tags = tracing_header_tags&.map do |hash|
28
28
  "#{hash["header"]}:#{hash["tag_name"]}"
29
29
  end
30
30
 
31
- super
31
+ super(parsed_header_tags)
32
32
  end
33
33
  end
34
34
 
@@ -42,6 +42,7 @@ module Datadog
42
42
  def call(tracing_sampling_rate)
43
43
  super
44
44
  Datadog.send(:components).reconfigure_sampler
45
+ tracing_sampling_rate
45
46
  end
46
47
 
47
48
  protected
@@ -78,8 +79,9 @@ module Datadog
78
79
  tracing_sampling_rules = tracing_sampling_rules.to_json
79
80
  end
80
81
 
81
- super
82
+ telemetry_value = super
82
83
  Datadog.send(:components).reconfigure_sampler
84
+ telemetry_value
83
85
  end
84
86
 
85
87
  protected
@@ -16,6 +16,7 @@ module Datadog
16
16
  ENV_RESOURCE_RENAMING_ENABLED = "DD_TRACE_RESOURCE_RENAMING_ENABLED"
17
17
  ENV_RESOURCE_RENAMING_ALWAYS_SIMPLIFIED_ENDPOINT = "DD_TRACE_RESOURCE_RENAMING_ALWAYS_SIMPLIFIED_ENDPOINT"
18
18
  ENV_EXPERIMENTAL_PROPAGATE_PROCESS_TAGS_ENABLED = "DD_EXPERIMENTAL_PROPAGATE_PROCESS_TAGS_ENABLED"
19
+ ENV_EXPERIMENTAL_NATIVE_TRANSPORT_ENABLED = "DD_EXPERIMENTAL_NATIVE_TRANSPORT_ENABLED"
19
20
 
20
21
  # @public_api
21
22
  module SpanAttributeSchema
@@ -482,6 +482,22 @@ module Datadog
482
482
  end
483
483
  end
484
484
 
485
+ # Use the native trace transport (Rust via C FFI) instead of
486
+ # the default pure-Ruby HTTP transport.
487
+ #
488
+ # The native transport delegates serialization, stats
489
+ # computation, and HTTP sending to the Rust data pipeline.
490
+ #
491
+ # This option is recommended for internal use only.
492
+ #
493
+ # @default `false`
494
+ # @return [Boolean]
495
+ option :native_transport do |o|
496
+ o.env Configuration::Ext::ENV_EXPERIMENTAL_NATIVE_TRANSPORT_ENABLED
497
+ o.default false
498
+ o.type :bool
499
+ end
500
+
485
501
  # A custom writer instance.
486
502
  # The object must respect the {Datadog::Tracing::Writer} interface.
487
503
  #
@@ -14,7 +14,7 @@ module Datadog
14
14
  ALL = [
15
15
  Events::Broadcast,
16
16
  Events::PerformAction,
17
- Events::Transmit
17
+ Events::Transmit,
18
18
  ].freeze
19
19
 
20
20
  module_function
@@ -11,7 +11,7 @@ module Datadog
11
11
  module Events
12
12
  ALL = [
13
13
  Events::Process,
14
- Events::Deliver
14
+ Events::Deliver,
15
15
  ].freeze
16
16
 
17
17
  module_function