datadog 2.41.0 → 2.42.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 (68) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +36 -2
  3. data/ext/datadog_profiling_native_extension/NativeExtensionDesign.md +12 -24
  4. data/ext/datadog_profiling_native_extension/collectors_cpu_and_wall_time_worker.c +110 -61
  5. data/ext/datadog_profiling_native_extension/collectors_stack.c +11 -3
  6. data/ext/datadog_profiling_native_extension/collectors_thread_context.c +141 -103
  7. data/ext/datadog_profiling_native_extension/collectors_thread_context.h +7 -3
  8. data/ext/datadog_profiling_native_extension/datadog_ruby_common.h +0 -10
  9. data/ext/datadog_profiling_native_extension/extconf.rb +52 -93
  10. data/ext/datadog_profiling_native_extension/heap_recorder.c +338 -255
  11. data/ext/datadog_profiling_native_extension/heap_recorder.h +46 -31
  12. data/ext/datadog_profiling_native_extension/native_extension_helpers.rb +0 -24
  13. data/ext/datadog_profiling_native_extension/private_vm_api_access.c +509 -440
  14. data/ext/datadog_profiling_native_extension/private_vm_api_access.h +15 -3
  15. data/ext/datadog_profiling_native_extension/profiling.c +2 -0
  16. data/ext/datadog_profiling_native_extension/ruby_helpers.c +1 -79
  17. data/ext/datadog_profiling_native_extension/ruby_helpers.h +0 -7
  18. data/ext/datadog_profiling_native_extension/stack_recorder.c +93 -61
  19. data/ext/datadog_profiling_native_extension/stack_recorder.h +12 -4
  20. data/ext/libdatadog_api/datadog_ruby_common.h +0 -10
  21. data/ext/libdatadog_api/di.c +10 -0
  22. data/ext/libdatadog_api/extconf.rb +3 -0
  23. data/ext/libdatadog_api/init.c +2 -0
  24. data/ext/libdatadog_api/otel_thread_context.c +232 -0
  25. data/ext/libdatadog_api/otel_thread_context.h +5 -0
  26. data/ext/libdatadog_extconf_helpers.rb +1 -1
  27. data/lib/datadog/appsec/assets/blocked.html +1 -108
  28. data/lib/datadog/core/configuration/components.rb +1 -0
  29. data/lib/datadog/core/crashtracking/component.rb +5 -1
  30. data/lib/datadog/data_streams/pathway_context.rb +20 -22
  31. data/lib/datadog/data_streams/processor.rb +31 -0
  32. data/lib/datadog/di/instrumenter.rb +41 -1
  33. data/lib/datadog/di/logger.rb +2 -2
  34. data/lib/datadog/di/probe.rb +9 -1
  35. data/lib/datadog/di/probe_notification_builder.rb +1 -0
  36. data/lib/datadog/di/remote.rb +3 -3
  37. data/lib/datadog/open_feature/evaluation_engine.rb +29 -3
  38. data/lib/datadog/open_feature/exposures/event.rb +10 -3
  39. data/lib/datadog/open_feature/ext.rb +19 -0
  40. data/lib/datadog/open_feature/flag_evaluation/aggregator.rb +236 -80
  41. data/lib/datadog/open_feature/flag_evaluation/writer.rb +179 -68
  42. data/lib/datadog/open_feature/hooks/flag_eval_evp_hook.rb +24 -21
  43. data/lib/datadog/open_feature/native_evaluator.rb +33 -6
  44. data/lib/datadog/open_feature/noop_evaluator.rb +5 -0
  45. data/lib/datadog/open_feature/provider.rb +11 -2
  46. data/lib/datadog/opentelemetry/sdk/propagator.rb +1 -1
  47. data/lib/datadog/opentelemetry/trace.rb +3 -0
  48. data/lib/datadog/profiling/collectors/cpu_and_wall_time_worker.rb +3 -0
  49. data/lib/datadog/profiling/collectors/thread_context.rb +0 -4
  50. data/lib/datadog/profiling/component.rb +8 -16
  51. data/lib/datadog/tracing/contrib/active_record/events/sql.rb +1 -0
  52. data/lib/datadog/tracing/distributed/baggage.rb +0 -1
  53. data/lib/datadog/tracing/distributed/datadog.rb +3 -3
  54. data/lib/datadog/tracing/distributed/propagation.rb +3 -0
  55. data/lib/datadog/tracing/distributed/trace_context.rb +14 -271
  56. data/lib/datadog/tracing/distributed/trace_state/datadog.rb +233 -0
  57. data/lib/datadog/tracing/distributed/trace_state/ext.rb +44 -0
  58. data/lib/datadog/tracing/distributed/trace_state/open_telemetry.rb +156 -0
  59. data/lib/datadog/tracing/distributed/trace_state.rb +121 -0
  60. data/lib/datadog/tracing/otel_thread_context.rb +30 -0
  61. data/lib/datadog/tracing/remote.rb +195 -27
  62. data/lib/datadog/tracing/sampling/rule_sampler.rb +2 -0
  63. data/lib/datadog/tracing/trace_digest.rb +22 -4
  64. data/lib/datadog/tracing/trace_operation.rb +22 -10
  65. data/lib/datadog/tracing/tracer.rb +5 -5
  66. data/lib/datadog/version.rb +1 -1
  67. metadata +14 -8
  68. data/lib/datadog/tracing/distributed/datadog_tags_codec.rb +0 -69
@@ -15,22 +15,198 @@ module Datadog
15
15
  1 << 13, # APM_TRACING_LOGS_INJECTION: Dynamic trace logs injection configuration
16
16
  1 << 14, # APM_TRACING_HTTP_HEADER_TAGS: Dynamic trace HTTP header tags configuration
17
17
  1 << 29, # APM_TRACING_SAMPLE_RULES: Dynamic trace sampling rules configuration
18
+ 1 << 45, # APM_TRACING_MULTICONFIG: merge multiple org/env-level APM_TRACING configs
18
19
  # APM_TRACING_ENABLE_DYNAMIC_INSTRUMENTATION (bit 38) is declared in
19
20
  # DI::Remote.capabilities, not here, so it is registered only when DI
20
21
  # is not explicitly disabled and the runtime supports DI.
21
22
  ].freeze
22
23
 
24
+ # Diagnostic scope label per specificity priority.
25
+ SCOPE_LABELS = {
26
+ 5 => "service+env",
27
+ 4 => "service",
28
+ 3 => "env",
29
+ 2 => "cluster",
30
+ 1 => "org",
31
+ }.freeze
32
+
33
+ # @return [Array[String]] the remote config products this module handles
23
34
  def products
24
35
  [PRODUCT]
25
36
  end
26
37
 
38
+ # @return [Array[Integer]] the remote config capability bits advertised
27
39
  def capabilities
28
40
  CAPABILITIES
29
41
  end
30
42
 
31
- def process_config(config, content, repository = nil)
32
- lib_config = config["lib_config"]
43
+ # Merges every active APM_TRACING config in the repository and applies the
44
+ # result once. Org/env-level (multi-config) remote enablement delivers
45
+ # several APM_TRACING configs in parallel (a (service, env)-specific one,
46
+ # an env-wide one, and/or an org-wide "*" one); for each lib_config field
47
+ # the value from the most-specific matching config wins. The RC repository
48
+ # prunes deleted configs, so this recomputes the merge from the repository's
49
+ # current contents on each dispatch.
50
+ #
51
+ # @param repository [Core::Remote::Configuration::Repository] the current RC repository
52
+ # @return [nil]
53
+ def merge_and_apply_configs(repository)
54
+ # Resolve the service identity the same way the RC client registers
55
+ # it with the backend (Core::Remote::Client#service_name =
56
+ # remote.service || service). When a customer sets remote.service,
57
+ # the backend delivers service_target.service values targeting that
58
+ # override; matching against the local service instead would drop
59
+ # every service-scoped config and let a less-specific org config win.
60
+ service = Datadog.configuration.remote.service || Datadog.configuration.service
61
+ env = Datadog.configuration.env
62
+
63
+ # @type var parsed: Array[[::Datadog::Core::Remote::Configuration::Content, ::Hash[::String, untyped]]]
64
+ parsed = []
65
+ repository.contents.each do |content|
66
+ next unless content.path.product == PRODUCT
67
+
68
+ begin
69
+ config = parse_content(content)
70
+ unless config.is_a?(Hash)
71
+ # A syntactically valid but non-object payload (null, [], 42)
72
+ # would later make config_matches? raise outside this per-content
73
+ # rescue and abort the whole merge, erroring valid configs too.
74
+ raise TypeError, "APM_TRACING remote config must be a JSON object, got #{config.class}"
75
+ end
76
+ # A present but non-object lib_config (e.g. {"lib_config": []}) is a
77
+ # schema violation the customer can fix. Acknowledging it as applied
78
+ # would tell the backend the config was successfully applied when it
79
+ # was not, and an empty merge would revert active tracing overrides
80
+ # to their non-RC values. Reject it per content so the malformed
81
+ # payload is reported errored instead. A null or absent lib_config
82
+ # carries no overrides and is left as a no-op.
83
+ lib_config = config["lib_config"]
84
+ if !lib_config.nil? && !lib_config.is_a?(Hash)
85
+ raise TypeError, "APM_TRACING lib_config must be a JSON object, got #{lib_config.class}"
86
+ end
87
+ parsed << [content, config]
88
+ rescue => e
89
+ Datadog.logger.debug { "APM_TRACING RC: skipping unparseable config: #{e.class}: #{e.message}" }
90
+ Datadog.send(:components, allow_initialization: false)&.telemetry&.report(
91
+ e,
92
+ description: "Failed to parse APM_TRACING remote config",
93
+ )
94
+ content.errored("#{e.class}: #{e.message}: #{Array(e.backtrace).join("\n")}")
95
+ end
96
+ end
97
+
98
+ Datadog.logger.debug { "APM_TRACING RC: received #{parsed.length} config(s)" }
99
+
100
+ applicable = parsed.select do |content, config|
101
+ if config_matches?(config, service, env)
102
+ Datadog.logger.debug do
103
+ "APM_TRACING RC: config #{content.path.config_id} " \
104
+ "scope=#{SCOPE_LABELS[config_priority(config)]} priority=#{config_priority(config)}"
105
+ end
106
+ true
107
+ else
108
+ Datadog.logger.debug do
109
+ "APM_TRACING RC: dropped config #{content.path.config_id} " \
110
+ "(service_target=#{config["service_target"].inspect}, self=#{service}/#{env})"
111
+ end
112
+ false
113
+ end
114
+ end
115
+
116
+ # Most-specific first; ties broken by config id (ascending) for a
117
+ # deterministic merge.
118
+ ordered = applicable.sort_by { |content, config| [-config_priority(config), content.path.config_id] }
119
+ merged = merge_lib_configs(ordered.map { |_content, config| config })
120
+
121
+ # Applied even when the set is empty: an emptied repository (last config
122
+ # removed) reverts the tracing overrides to their non-RC values.
123
+ apply_lib_config(merged, repository)
124
+
125
+ parsed.each { |content, _config| content.applied }
126
+ nil
127
+ rescue => e
128
+ Datadog.logger.debug { "APM_TRACING RC: failed to apply configs: #{e.class}: #{e.message}" }
129
+ Datadog.send(:components, allow_initialization: false)&.telemetry&.report(
130
+ e,
131
+ description: "Failed to apply APM_TRACING remote configs",
132
+ )
133
+ parsed&.each do |content, _config|
134
+ content.errored("#{e.class}: #{e.message}: #{Array(e.backtrace).join("\n")}")
135
+ end
136
+ nil
137
+ end
33
138
 
139
+ # Whether a config targets this tracer. A concrete (non-"*") service or
140
+ # env that differs from ours excludes the config; "*" and an absent
141
+ # service_target match anything.
142
+ #
143
+ # @param config [Hash[String, untyped]] a parsed config
144
+ # @param service [String, nil] this tracer's service
145
+ # @param env [String, nil] this tracer's env
146
+ # @return [bool] true when the config applies to this tracer
147
+ def config_matches?(config, service, env)
148
+ target = config["service_target"]
149
+ return true unless target.is_a?(Hash)
150
+
151
+ target_service = target["service"]
152
+ target_env = target["env"]
153
+ return false if target_service && target_service != "*" && target_service != service
154
+ return false if target_env && target_env != "*" && target_env != env
155
+
156
+ true
157
+ end
158
+
159
+ # Specificity of a config, higher meaning more specific: service+env (5),
160
+ # service (4), env (3), cluster (2), org (1). A target counts as concrete
161
+ # only when present and not "*".
162
+ #
163
+ # @param config [Hash[String, untyped]] a parsed config
164
+ # @return [Integer] the specificity rank, 1 through 5
165
+ def config_priority(config)
166
+ target = config["service_target"]
167
+ service = target.is_a?(Hash) ? target["service"] : nil
168
+ env = target.is_a?(Hash) ? target["env"] : nil
169
+ single_service = !service.nil? && service != "*"
170
+ single_env = !env.nil? && env != "*"
171
+
172
+ return 5 if single_service && single_env
173
+ return 4 if single_service
174
+ return 3 if single_env
175
+ return 2 unless config["k8s_target_v2"].nil?
176
+
177
+ 1
178
+ end
179
+
180
+ # Merges lib_configs from configs ordered most-specific first: for each
181
+ # field, the first (most-specific) non-nil value wins. Fields are
182
+ # independent, so a lower-priority config can supply a field the
183
+ # higher-priority one omits.
184
+ #
185
+ # @param configs_most_specific_first [Array[Hash[String, untyped]]] configs, most-specific first
186
+ # @return [Hash[String, untyped]] the merged lib_config
187
+ def merge_lib_configs(configs_most_specific_first)
188
+ merged = {}
189
+ configs_most_specific_first.each do |config|
190
+ lib_config = config["lib_config"]
191
+ next unless lib_config.is_a?(Hash)
192
+
193
+ lib_config.each do |key, value|
194
+ next if value.nil?
195
+
196
+ merged[key] = value unless merged.key?(key)
197
+ end
198
+ end
199
+ merged
200
+ end
201
+
202
+ # Applies one lib_config: maps the dynamic OPTIONS to telemetry, drives DI
203
+ # enablement from "dynamic_instrumentation_enabled", and reports the
204
+ # configuration change to telemetry.
205
+ #
206
+ # @param lib_config [Hash[String, untyped]] the lib_config to apply
207
+ # @param repository [Core::Remote::Configuration::Repository, nil] forwarded to DI enablement
208
+ # @return [nil]
209
+ def apply_lib_config(lib_config, repository)
34
210
  env_vars = Datadog::Tracing::Configuration::Dynamic::OPTIONS.map do |name, env_var, option|
35
211
  value = lib_config[name]
36
212
 
@@ -55,11 +231,11 @@ module Datadog
55
231
  if di_enabled
56
232
  components&.symbol_database&.resume_pending_upload
57
233
  # Advertise the DI products only if the component actually started.
58
- # handle_rc_enablement above no-ops when DI cannot run the
59
- # component is nil on an unsupported runtime, or the enable signal
60
- # is blocked by DD_DYNAMIC_INSTRUMENTATION_ENABLED=false. Advertising
61
- # then would report DI as in use when it is not and invite probe
62
- # configs the tracer must refuse; withdraw the products otherwise.
234
+ # handle_rc_enablement above no-ops when DI cannot run: the component
235
+ # is nil on an unsupported runtime, or the enable signal is blocked
236
+ # by DD_DYNAMIC_INSTRUMENTATION_ENABLED=false. Advertising then would
237
+ # report DI as in use when it is not and invite probe configs the
238
+ # tracer must refuse; withdraw the products otherwise.
63
239
  if components&.dynamic_instrumentation&.started?
64
240
  components&.remote&.add_products(*di_products)
65
241
  else
@@ -69,33 +245,25 @@ module Datadog
69
245
  components&.symbol_database&.stop_for_di_disable
70
246
  components&.remote&.remove_products(*di_products)
71
247
  end
72
- end
73
248
 
74
- content.applied
249
+ Datadog.logger.debug { "APM_TRACING RC: merged dynamic_instrumentation_enabled=#{di_enabled}" }
250
+ end
75
251
 
76
- # allow_initialization: false because process_config runs on the
77
- # remote-config worker thread. If components haven't been built yet
78
- # (e.g. during a teardown/reset window), the default `true` would
79
- # synchronously build the entire component tree from this thread.
80
- # The &. chain matches the pattern used by DI::Remote.handle_rc_enablement
81
- # in the same dispatch path.
252
+ # allow_initialization: false because this runs on the remote-config
253
+ # worker thread. If components haven't been built yet (e.g. during a
254
+ # teardown/reset window), the default value would synchronously build
255
+ # the entire component tree from this thread. The &. chain matches the
256
+ # pattern used by DI::Remote.handle_rc_enablement in the same dispatch
257
+ # path.
82
258
  Datadog.send(:components, allow_initialization: false)&.telemetry&.client_configuration_change!(env_vars)
83
- rescue => e
84
- content.errored("#{e.class}: #{e.message}: #{Array(e.backtrace).join("\n")}")
259
+ nil
85
260
  end
86
261
 
262
+ # @param _telemetry [Core::Telemetry::Component] unused; kept for the receiver contract
263
+ # @return [Array[Core::Remote::Dispatcher::Receiver]] the APM_TRACING receiver
87
264
  def receivers(_telemetry)
88
265
  receiver do |repository, _changes|
89
- # DEV: Filter our by product. Given it will be very common
90
- # DEV: we can filter this out before we receive the data in this method.
91
- # DEV: Apply this refactor to AppSec as well if implemented.
92
- repository.contents.map do |content|
93
- case content.path.product
94
- when PRODUCT
95
- config = parse_content(content)
96
- process_config(config, content, repository)
97
- end
98
- end
266
+ merge_and_apply_configs(repository)
99
267
  end
100
268
  end
101
269
 
@@ -192,6 +192,8 @@ module Datadog
192
192
 
193
193
  def reconsider_matching_rule!(trace, rule)
194
194
  trace.agent_sample_rate = nil
195
+ # Avoid mistaking a reconsidered probabilistic drop for a limiter drop.
196
+ trace.rate_limiter_rate = nil
195
197
  trace.clear_tag(Tracing::Metadata::Ext::Distributed::TAG_DECISION_MAKER)
196
198
  apply_rule!(trace, rule)
197
199
  end
@@ -72,10 +72,7 @@ module Datadog
72
72
  # @return [Integer]
73
73
  # @see https://www.w3.org/TR/trace-context/#trace-flags
74
74
  # @!attribute [r] trace_state
75
- # The W3C "tracestate" extracted from a distributed context.
76
- # This field is a string representing vendor-specific distribution data.
77
- # The `dd=` entry is removed from `trace_state` as its value is dynamically calculated
78
- # on every propagation injection.
75
+ # W3C "tracestate" members other than `dd=` and `ot=`, which are stored in parsed fields.
79
76
  # @return [String]
80
77
  # @see https://www.w3.org/TR/trace-context/#tracestate-header
81
78
  # @!attribute [r] trace_state_unknown_fields
@@ -83,6 +80,15 @@ module Datadog
83
80
  # This allows later propagation to include those unknown fields, as they can represent future versions of the spec
84
81
  # sending data through this service. This value ends in a trailing `;` to facilitate serialization.
85
82
  # @return [String]
83
+ # @!attribute [r] trace_otel_random_value
84
+ # OpenTelemetry consistent probability sampling random value.
85
+ # @return [String]
86
+ # @!attribute [r] trace_otel_threshold
87
+ # OpenTelemetry consistent probability sampling threshold.
88
+ # @return [String]
89
+ # @!attribute [r] trace_otel_unknown_fields
90
+ # Unrecognized `ot=` fields, retained with a trailing `;` for propagation.
91
+ # @return [String]
86
92
  # @!attribute [r] baggage
87
93
  # The W3C "baggage" extracted from a distributed context. This field is a hash of key/value pairs.
88
94
  # @return [Hash<String,String>]
@@ -109,6 +115,9 @@ module Datadog
109
115
  :trace_flags,
110
116
  :trace_state,
111
117
  :trace_state_unknown_fields,
118
+ :trace_otel_random_value,
119
+ :trace_otel_threshold,
120
+ :trace_otel_unknown_fields,
112
121
  :span_remote,
113
122
  :baggage
114
123
 
@@ -133,6 +142,9 @@ module Datadog
133
142
  trace_flags: nil,
134
143
  trace_state: nil,
135
144
  trace_state_unknown_fields: nil,
145
+ trace_otel_random_value: nil,
146
+ trace_otel_threshold: nil,
147
+ trace_otel_unknown_fields: nil,
136
148
  span_remote: true,
137
149
  baggage: nil
138
150
  )
@@ -156,6 +168,9 @@ module Datadog
156
168
  @trace_flags = trace_flags
157
169
  @trace_state = trace_state && trace_state.dup.freeze
158
170
  @trace_state_unknown_fields = trace_state_unknown_fields && trace_state_unknown_fields.dup.freeze
171
+ @trace_otel_random_value = trace_otel_random_value && trace_otel_random_value.dup.freeze
172
+ @trace_otel_threshold = trace_otel_threshold && trace_otel_threshold.dup.freeze
173
+ @trace_otel_unknown_fields = trace_otel_unknown_fields && trace_otel_unknown_fields.dup.freeze
159
174
  @span_remote = span_remote
160
175
  @baggage = baggage && baggage.dup.freeze
161
176
  freeze
@@ -188,6 +203,9 @@ module Datadog
188
203
  trace_flags: trace_flags,
189
204
  trace_state: trace_state,
190
205
  trace_state_unknown_fields: trace_state_unknown_fields,
206
+ trace_otel_random_value: trace_otel_random_value,
207
+ trace_otel_threshold: trace_otel_threshold,
208
+ trace_otel_unknown_fields: trace_otel_unknown_fields,
191
209
  span_remote: span_remote,
192
210
  baggage: baggage, **field_value_pairs
193
211
  )
@@ -5,6 +5,7 @@ require_relative "../core/utils"
5
5
  require_relative "event"
6
6
  require_relative "metadata/tagging"
7
7
  require_relative "sampling/ext"
8
+ require_relative "distributed/trace_state"
8
9
  require_relative "span_operation"
9
10
  require_relative "trace_digest"
10
11
  require_relative "correlation"
@@ -48,8 +49,7 @@ module Datadog
48
49
  :id,
49
50
  :max_length,
50
51
  :parent_span_id,
51
- :trace_state,
52
- :trace_state_unknown_fields
52
+ :trace_state
53
53
 
54
54
  attr_writer \
55
55
  :name,
@@ -86,8 +86,8 @@ module Datadog
86
86
  tags: nil,
87
87
  metrics: nil,
88
88
  trace_state: nil,
89
- trace_state_unknown_fields: nil,
90
89
  remote_parent: false,
90
+ distributed_sampling_priority: false,
91
91
  tracer: nil, # DEV-3.0: deprecated, remove in 3.0
92
92
  baggage: nil,
93
93
  auto_finish: true
@@ -100,6 +100,7 @@ module Datadog
100
100
  @parent_span_id = parent_span_id
101
101
  @sampled = sampled.nil? || sampled
102
102
  @remote_parent = remote_parent
103
+ @distributed_sampling_priority = distributed_sampling_priority
103
104
  @span_links = span_links
104
105
  # Tags
105
106
  @agent_sample_rate = agent_sample_rate
@@ -114,8 +115,7 @@ module Datadog
114
115
  @service = service
115
116
  @profiling_enabled = profiling_enabled
116
117
  @apm_tracing_enabled = apm_tracing_enabled
117
- @trace_state = trace_state
118
- @trace_state_unknown_fields = trace_state_unknown_fields
118
+ @trace_state = trace_state || Distributed::TraceState.new
119
119
  @baggage = baggage
120
120
 
121
121
  # Generic tags
@@ -391,6 +391,15 @@ module Datadog
391
391
  @propagated = true
392
392
  events.trace_propagated.publish(self)
393
393
 
394
+ open_telemetry = @trace_state.open_telemetry.outbound(
395
+ trace_id: @id,
396
+ sampling_priority: @sampling_priority,
397
+ decision_maker: get_tag(Tracing::Metadata::Ext::Distributed::TAG_DECISION_MAKER),
398
+ applied_rate: @rule_sample_rate || @agent_sample_rate,
399
+ rate_limiter_rate: @rate_limiter_rate,
400
+ distributed_sampling_priority: @distributed_sampling_priority,
401
+ )
402
+
394
403
  TraceDigest.new(
395
404
  span_id: span_id,
396
405
  span_name: @active_span && @active_span.name,
@@ -407,8 +416,11 @@ module Datadog
407
416
  trace_runtime_id: Core::Environment::Identity.id,
408
417
  trace_sampling_priority: @sampling_priority,
409
418
  trace_service: service,
410
- trace_state: @trace_state,
411
- trace_state_unknown_fields: @trace_state_unknown_fields,
419
+ trace_state: @trace_state.unknown_vendors,
420
+ trace_state_unknown_fields: @trace_state.datadog.unknown_fields,
421
+ trace_otel_random_value: open_telemetry.random_value,
422
+ trace_otel_threshold: open_telemetry.threshold,
423
+ trace_otel_unknown_fields: open_telemetry.unknown_fields,
412
424
  span_remote: @remote_parent && @active_span.nil?,
413
425
  baggage: (@baggage.nil? || @baggage.empty?) ? nil : @baggage
414
426
  ).freeze
@@ -444,11 +456,11 @@ module Datadog
444
456
  sampled: @sampled,
445
457
  sampling_priority: @sampling_priority,
446
458
  service: service&.dup,
447
- trace_state: @trace_state&.dup,
448
- trace_state_unknown_fields: @trace_state_unknown_fields&.dup,
459
+ trace_state: @trace_state,
449
460
  tags: meta.dup,
450
461
  metrics: metrics.dup,
451
- remote_parent: @remote_parent
462
+ remote_parent: @remote_parent,
463
+ distributed_sampling_priority: @distributed_sampling_priority
452
464
  )
453
465
  end
454
466
 
@@ -375,9 +375,9 @@ module Datadog
375
375
  hostname = Core::Environment::Socket.resolved_hostname(Datadog.configuration)
376
376
 
377
377
  if digest
378
- sampling_priority = if propagate_sampling_priority?(upstream_tags: digest.trace_distributed_tags)
379
- digest.trace_sampling_priority
380
- end
378
+ propagate_sampling = propagate_sampling_priority?(upstream_tags: digest.trace_distributed_tags)
379
+ sampling_priority = digest.trace_sampling_priority if propagate_sampling
380
+ trace_state = Distributed::TraceState.from_digest(digest, propagate_sampling: propagate_sampling)
381
381
  TraceOperation.new(
382
382
  logger: logger,
383
383
  hostname: hostname,
@@ -390,9 +390,9 @@ module Datadog
390
390
  span_links: digest.span_links,
391
391
  # Distributed tags are just regular trace tags with special meaning to Datadog
392
392
  tags: digest.trace_distributed_tags,
393
- trace_state: digest.trace_state,
394
- trace_state_unknown_fields: digest.trace_state_unknown_fields,
393
+ trace_state: trace_state,
395
394
  remote_parent: digest.span_remote,
395
+ distributed_sampling_priority: !!sampling_priority,
396
396
  tracer: self,
397
397
  baggage: digest.baggage,
398
398
  auto_finish: auto_finish
@@ -3,7 +3,7 @@
3
3
  module Datadog
4
4
  module VERSION
5
5
  MAJOR = 2
6
- MINOR = 41
6
+ MINOR = 42
7
7
  PATCH = 0
8
8
  PRE = nil
9
9
  BUILD = nil
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: datadog
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.41.0
4
+ version: 2.42.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Datadog, Inc.
@@ -32,7 +32,7 @@ dependencies:
32
32
  version: '3.5'
33
33
  - - ">="
34
34
  - !ruby/object:Gem::Version
35
- version: 3.5.4
35
+ version: 3.5.5
36
36
  type: :runtime
37
37
  prerelease: false
38
38
  version_requirements: !ruby/object:Gem::Requirement
@@ -42,7 +42,7 @@ dependencies:
42
42
  version: '3.5'
43
43
  - - ">="
44
44
  - !ruby/object:Gem::Version
45
- version: 3.5.4
45
+ version: 3.5.5
46
46
  - !ruby/object:Gem::Dependency
47
47
  name: libddwaf
48
48
  requirement: !ruby/object:Gem::Requirement
@@ -63,14 +63,14 @@ dependencies:
63
63
  requirements:
64
64
  - - "~>"
65
65
  - !ruby/object:Gem::Version
66
- version: 40.0.0.1.0
66
+ version: 40.0.0.2.0
67
67
  type: :runtime
68
68
  prerelease: false
69
69
  version_requirements: !ruby/object:Gem::Requirement
70
70
  requirements:
71
71
  - - "~>"
72
72
  - !ruby/object:Gem::Version
73
- version: 40.0.0.1.0
73
+ version: 40.0.0.2.0
74
74
  - !ruby/object:Gem::Dependency
75
75
  name: logger
76
76
  requirement: !ruby/object:Gem::Requirement
@@ -181,6 +181,8 @@ files:
181
181
  - ext/libdatadog_api/init.c
182
182
  - ext/libdatadog_api/library_config.c
183
183
  - ext/libdatadog_api/library_config.h
184
+ - ext/libdatadog_api/otel_thread_context.c
185
+ - ext/libdatadog_api/otel_thread_context.h
184
186
  - ext/libdatadog_api/process_discovery.c
185
187
  - ext/libdatadog_api/process_discovery.h
186
188
  - ext/libdatadog_api/trace_exporter.c
@@ -1096,13 +1098,16 @@ files:
1096
1098
  - lib/datadog/tracing/distributed/b3_single.rb
1097
1099
  - lib/datadog/tracing/distributed/baggage.rb
1098
1100
  - lib/datadog/tracing/distributed/datadog.rb
1099
- - lib/datadog/tracing/distributed/datadog_tags_codec.rb
1100
1101
  - lib/datadog/tracing/distributed/fetcher.rb
1101
1102
  - lib/datadog/tracing/distributed/helpers.rb
1102
1103
  - lib/datadog/tracing/distributed/none.rb
1103
1104
  - lib/datadog/tracing/distributed/propagation.rb
1104
1105
  - lib/datadog/tracing/distributed/propagation_policy.rb
1105
1106
  - lib/datadog/tracing/distributed/trace_context.rb
1107
+ - lib/datadog/tracing/distributed/trace_state.rb
1108
+ - lib/datadog/tracing/distributed/trace_state/datadog.rb
1109
+ - lib/datadog/tracing/distributed/trace_state/ext.rb
1110
+ - lib/datadog/tracing/distributed/trace_state/open_telemetry.rb
1106
1111
  - lib/datadog/tracing/event.rb
1107
1112
  - lib/datadog/tracing/ext.rb
1108
1113
  - lib/datadog/tracing/flush.rb
@@ -1113,6 +1118,7 @@ files:
1113
1118
  - lib/datadog/tracing/metadata/metastruct.rb
1114
1119
  - lib/datadog/tracing/metadata/metastruct_tagging.rb
1115
1120
  - lib/datadog/tracing/metadata/tagging.rb
1121
+ - lib/datadog/tracing/otel_thread_context.rb
1116
1122
  - lib/datadog/tracing/pipeline.rb
1117
1123
  - lib/datadog/tracing/pipeline/span_filter.rb
1118
1124
  - lib/datadog/tracing/pipeline/span_processor.rb
@@ -1166,8 +1172,8 @@ licenses:
1166
1172
  - Apache-2.0
1167
1173
  metadata:
1168
1174
  allowed_push_host: https://rubygems.org
1169
- changelog_uri: https://github.com/DataDog/dd-trace-rb/blob/v2.41.0/CHANGELOG.md
1170
- source_code_uri: https://github.com/DataDog/dd-trace-rb/tree/v2.41.0
1175
+ changelog_uri: https://github.com/DataDog/dd-trace-rb/blob/v2.42.0/CHANGELOG.md
1176
+ source_code_uri: https://github.com/DataDog/dd-trace-rb/tree/v2.42.0
1171
1177
  post_install_message: 'JRuby support in the datadog gem is deprecated. Details: https://dtdg.co/jruby-deprecation'
1172
1178
  rdoc_options: []
1173
1179
  require_paths:
@@ -1,69 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Datadog
4
- module Tracing
5
- module Distributed
6
- # Encodes and decodes distributed 'x-datadog-tags' tags for transport
7
- # to and from external processes.
8
- module DatadogTagsCodec
9
- # ASCII characters 32-126, except `,`, `=`, and ` `. At least one character.
10
- VALID_KEY_CHARS = /\A(?:(?![,= ])[\u0020-\u007E])+\Z/.freeze
11
- # ASCII characters 32-126, except `,`. At least one character.
12
- VALID_VALUE_CHARS = /\A(?:(?!,)[\u0020-\u007E])+\Z/.freeze
13
-
14
- # Serializes a {Hash<String,String>} into a `x-datadog-tags`-compatible
15
- # String.
16
- #
17
- # @param tags [Hash<String,String>] trace tag hash
18
- # @return [String] serialized tags hash
19
- # @raise [EncodingError] if tags cannot be serialized to the `x-datadog-tags` format
20
- def self.encode(tags)
21
- tags.map do |raw_key, raw_value|
22
- key = raw_key.to_s
23
- value = raw_value.to_s
24
-
25
- raise EncodingError, "Invalid key `#{key}` for value `#{value}`" unless VALID_KEY_CHARS.match?(key)
26
- raise EncodingError, "Invalid value `#{value}` for key `#{key}`" unless VALID_VALUE_CHARS.match?(value)
27
-
28
- "#{key}=#{value.strip}"
29
- end.join(",")
30
- rescue => e
31
- raise EncodingError, "Error encoding tags `#{tags}`: `#{e.class}: #{e.message}`"
32
- end
33
-
34
- # Deserializes a `x-datadog-tags`-formatted String into a {Hash<String,String>}.
35
- #
36
- # @param string [String] tags as serialized by {#encode}
37
- # @return [Hash<String,String>] decoded input as a hash of strings
38
- # @raise [DecodingError] if string does not conform to the `x-datadog-tags` format
39
- def self.decode(string)
40
- result = (string.split(",").map do |raw_tag|
41
- raw_tag.split("=", 2).tap do |raw_key, raw_value|
42
- key = raw_key.to_s
43
- value = raw_value.to_s
44
-
45
- raise DecodingError, "Invalid key: #{key}" unless VALID_KEY_CHARS.match?(key)
46
- raise DecodingError, "Invalid value: #{value}" unless VALID_VALUE_CHARS.match?(value)
47
-
48
- value.strip!
49
- end
50
- end).to_h
51
-
52
- raise DecodingError, "Invalid empty tags: #{string}" if result.empty? && !string.empty?
53
-
54
- result
55
- end
56
-
57
- # An error occurred during distributed tags encoding.
58
- # See {#message} for more information.
59
- class EncodingError < StandardError
60
- end
61
-
62
- # An error occurred during distributed tags decoding.
63
- # See {#message} for more information.
64
- class DecodingError < StandardError
65
- end
66
- end
67
- end
68
- end
69
- end