datadog 2.0.0 → 2.1.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5008d4cb7f37cf4c4e1ed7956198b1fba9837c52f379b5d892898506ce4b2640
4
- data.tar.gz: 684c2b438ef7230e7f30ebd69b43041b2eea81413bbe2d4aedfe8140af01e955
3
+ metadata.gz: e0297728b2d8779a69af39f3dffa86af6b3765e3f2dd19cb685340ca7ad8e2ac
4
+ data.tar.gz: 3c7d3506df76790fea0b2e2047d1b2c4919e9d928ccb644086194197125391e7
5
5
  SHA512:
6
- metadata.gz: 1582a1f36cdf990613dc46e6febadb29f45275a363d32f4213237b5c8dc5be145218226639a590cb16e2fe7881a91b05dfb714c018e85fbb99f407376f68d71c
7
- data.tar.gz: e08d4d1645d47bd4fb8e4c6d03f088571bca24df622bc8e9da0d5ca696b33602fe28dc855e34da9f1783c62e4797916e1a0736f5d8fa29850d71d57a5508ec4e
6
+ metadata.gz: ec2862773c6ee93e5d698d6b586a576413689a84f7d94a621c20088759469e1ad6742e13fc1e7f9250046212cec0e284abf4fb0048e255802c19f378cf7d428c
7
+ data.tar.gz: 507fbfd3f8879333c11336646e1a56ca453fbaf92c84fb0bae3b0e38435f3ea1ec6b3ddc756f848c76113a4e5832f8097cd521532541bf9ca8fdff6cca1e5ff3
data/CHANGELOG.md CHANGED
@@ -2,6 +2,16 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [2.1.0] - 2024-06-10
6
+
7
+ ### Added
8
+
9
+ * Tracing: Configuration by OpenTelemetry environment variables ([#3657][])
10
+
11
+ ### Fixed
12
+
13
+ * Tracing: Improved compatibility with W3C Trace Context propagation ([#3631][])
14
+
5
15
  ## [2.0.0] - 2024-06-06
6
16
 
7
17
  ### Added
@@ -2894,7 +2904,8 @@ Release notes: https://github.com/DataDog/dd-trace-rb/releases/tag/v0.3.1
2894
2904
  Git diff: https://github.com/DataDog/dd-trace-rb/compare/v0.3.0...v0.3.1
2895
2905
 
2896
2906
 
2897
- [Unreleased]: https://github.com/DataDog/dd-trace-rb/compare/v2.0.0...master
2907
+ [Unreleased]: https://github.com/DataDog/dd-trace-rb/compare/v2.1.0...master
2908
+ [2.1.0]: https://github.com/DataDog/dd-trace-rb/compare/v2.0.0...v2.1.0
2898
2909
  [2.0.0]: https://github.com/DataDog/dd-trace-rb/compare/v2.0.0.rc1...v2.0.0
2899
2910
  [2.0.0.rc1]: https://github.com/DataDog/dd-trace-rb/compare/v2.0.0.beta2...v2.0.0.rc1
2900
2911
  [1.23.0]: https://github.com/DataDog/dd-trace-rb/compare/v1.22.0...v1.23.0
@@ -4267,8 +4278,10 @@ Git diff: https://github.com/DataDog/dd-trace-rb/compare/v0.3.0...v0.3.1
4267
4278
  [#3624]: https://github.com/DataDog/dd-trace-rb/issues/3624
4268
4279
  [#3627]: https://github.com/DataDog/dd-trace-rb/issues/3627
4269
4280
  [#3630]: https://github.com/DataDog/dd-trace-rb/issues/3630
4281
+ [#3631]: https://github.com/DataDog/dd-trace-rb/issues/3631
4270
4282
  [#3645]: https://github.com/DataDog/dd-trace-rb/issues/3645
4271
4283
  [#3651]: https://github.com/DataDog/dd-trace-rb/issues/3651
4284
+ [#3657]: https://github.com/DataDog/dd-trace-rb/issues/3657
4272
4285
  [#3664]: https://github.com/DataDog/dd-trace-rb/issues/3664
4273
4286
  [@AdrianLC]: https://github.com/AdrianLC
4274
4287
  [@Azure7111]: https://github.com/Azure7111
data/README.md CHANGED
@@ -8,7 +8,7 @@
8
8
 
9
9
  ## Getting started
10
10
 
11
- **If you're upgrading from a 0.x version, check out our [upgrade guide](https://github.com/DataDog/dd-trace-rb/blob/master/docs/UpgradeGuide.md#from-0x-to-10).**
11
+ **If you're upgrading from a 1.x version, check out the [upgrade guide](https://github.com/DataDog/dd-trace-rb/blob/release/docs/UpgradeGuide2.md).**
12
12
 
13
13
  For a product overview, installation, and configuration check out our [documentation][public docs].
14
14
 
@@ -192,6 +192,11 @@ module Datadog
192
192
  end
193
193
  end
194
194
  end
195
+
196
+ option :sca_enabled do |o|
197
+ o.type :bool, nilable: true
198
+ o.env 'DD_APPSEC_SCA_ENABLED'
199
+ end
195
200
  end
196
201
  end
197
202
  end
@@ -15,7 +15,6 @@ module Datadog
15
15
  module AppSec
16
16
  module Contrib
17
17
  module Rack
18
- # Create an array of lowercased headers
19
18
  WAF_VENDOR_HEADERS_TAGS = %w[
20
19
  X-Amzn-Trace-Id
21
20
  Cloudfront-Viewer-Ja3-Fingerprint
@@ -9,6 +9,7 @@ module Datadog
9
9
  # @public_api
10
10
  module Diagnostics
11
11
  ENV_DEBUG_ENABLED = 'DD_TRACE_DEBUG'
12
+ ENV_OTEL_LOG_LEVEL = 'OTEL_LOG_LEVEL'
12
13
  ENV_HEALTH_METRICS_ENABLED = 'DD_HEALTH_METRICS_ENABLED'
13
14
  ENV_STARTUP_LOGS_ENABLED = 'DD_TRACE_STARTUP_LOGS'
14
15
  end
@@ -14,7 +14,7 @@ module Datadog
14
14
  # @!attribute [r] precedence_set
15
15
  # When this option was last set, what was the value precedence used?
16
16
  # @return [Precedence::Value]
17
- attr_reader :definition, :precedence_set
17
+ attr_reader :definition, :precedence_set, :resolved_env
18
18
 
19
19
  # Option setting precedence.
20
20
  module Precedence
@@ -50,6 +50,7 @@ module Datadog
50
50
  @context = context
51
51
  @value = nil
52
52
  @is_set = false
53
+ @resolved_env = nil
53
54
 
54
55
  # One value is stored per precedence, to allow unsetting a higher
55
56
  # precedence value and falling back to a lower precedence one.
@@ -65,7 +66,7 @@ module Datadog
65
66
  #
66
67
  # @param value [Object] the new value to be associated with this option
67
68
  # @param precedence [Precedence] from what precedence order this new value comes from
68
- def set(value, precedence: Precedence::PROGRAMMATIC)
69
+ def set(value, precedence: Precedence::PROGRAMMATIC, resolved_env: nil)
69
70
  # Is there a higher precedence value set?
70
71
  if @precedence_set > precedence
71
72
  # This should be uncommon, as higher precedence values tend to
@@ -84,7 +85,7 @@ module Datadog
84
85
  return @value
85
86
  end
86
87
 
87
- internal_set(value, precedence)
88
+ internal_set(value, precedence, resolved_env)
88
89
  end
89
90
 
90
91
  def unset(precedence)
@@ -102,7 +103,7 @@ module Datadog
102
103
  # Look for value that is set.
103
104
  # The hash `@value_per_precedence` has a custom default value of `UNSET`.
104
105
  if (value = @value_per_precedence[p]) != UNSET
105
- internal_set(value, p)
106
+ internal_set(value, p, nil)
106
107
  return nil
107
108
  end
108
109
  end
@@ -260,11 +261,12 @@ module Datadog
260
261
  end
261
262
 
262
263
  # Directly manipulates the current value and currently set precedence.
263
- def internal_set(value, precedence)
264
+ def internal_set(value, precedence, resolved_env)
264
265
  old_value = @value
265
266
  (@value = context_exec(validate_type(value), old_value, &definition.setter)).tap do |v|
266
267
  @is_set = true
267
268
  @precedence_set = precedence
269
+ @resolved_env = resolved_env
268
270
  # Store original value to ensure we can always safely call `#internal_set`
269
271
  # when restoring a value from `@value_per_precedence`, and we are only running `definition.setter`
270
272
  # on the original value, not on a valud that has already been processed by `definition.setter`.
@@ -284,16 +286,21 @@ module Datadog
284
286
  def set_value_from_env_or_default
285
287
  value = nil
286
288
  precedence = nil
287
- effective_env = nil
289
+ resolved_env = nil
288
290
 
289
- if definition.env && ENV[definition.env]
290
- effective_env = definition.env
291
- value = coerce_env_variable(ENV[definition.env])
292
- precedence = Precedence::PROGRAMMATIC
291
+ if definition.env
292
+ Array(definition.env).each do |env|
293
+ next if ENV[env].nil?
294
+
295
+ resolved_env = env
296
+ value = coerce_env_variable(ENV[env])
297
+ precedence = Precedence::PROGRAMMATIC
298
+ break
299
+ end
293
300
  end
294
301
 
295
302
  if value.nil? && definition.deprecated_env && ENV[definition.deprecated_env]
296
- effective_env = definition.deprecated_env
303
+ resolved_env = definition.deprecated_env
297
304
  value = coerce_env_variable(ENV[definition.deprecated_env])
298
305
  precedence = Precedence::PROGRAMMATIC
299
306
 
@@ -304,11 +311,11 @@ module Datadog
304
311
 
305
312
  option_value = value.nil? ? default_value : value
306
313
 
307
- set(option_value, precedence: precedence || Precedence::DEFAULT)
314
+ set(option_value, precedence: precedence || Precedence::DEFAULT, resolved_env: resolved_env)
308
315
  rescue ArgumentError
309
316
  raise ArgumentError,
310
- "Expected environment variable #{effective_env} to be a #{@definition.type}, " \
311
- "but '#{ENV[effective_env]}' was provided"
317
+ "Expected environment variable #{resolved_env} to be a #{@definition.type}, " \
318
+ "but '#{ENV[resolved_env]}' was provided"
312
319
  end
313
320
 
314
321
  # Anchor object that represents a value that is not set.
@@ -68,7 +68,7 @@ module Datadog
68
68
  end
69
69
 
70
70
  def set_option(name, value, precedence: Configuration::Option::Precedence::PROGRAMMATIC)
71
- resolve_option(name).set(value, precedence: precedence)
71
+ resolve_option(name).set(value, precedence: precedence, resolved_env: resolved_env(name))
72
72
  end
73
73
 
74
74
  def unset_option(name, precedence: Configuration::Option::Precedence::PROGRAMMATIC)
@@ -116,6 +116,10 @@ module Datadog
116
116
  options[name] = definition.build(self)
117
117
  end
118
118
 
119
+ def resolved_env(name)
120
+ return options[name].resolved_env if options.key?(name)
121
+ end
122
+
119
123
  def assert_valid_option!(name)
120
124
  raise(InvalidOptionError, "#{self.class.name} doesn't define the option: #{name}") unless option_defined?(name)
121
125
  end
@@ -122,9 +122,18 @@ module Datadog
122
122
  # @default `DD_TRACE_DEBUG` environment variable, otherwise `false`
123
123
  # @return [Boolean]
124
124
  option :debug do |o|
125
- o.env Datadog::Core::Configuration::Ext::Diagnostics::ENV_DEBUG_ENABLED
125
+ o.env [Datadog::Core::Configuration::Ext::Diagnostics::ENV_DEBUG_ENABLED,
126
+ Datadog::Core::Configuration::Ext::Diagnostics::ENV_OTEL_LOG_LEVEL]
126
127
  o.default false
127
128
  o.type :bool
129
+ o.env_parser do |value|
130
+ if value
131
+ value = value.strip.downcase
132
+ # Debug is enabled when DD_TRACE_DEBUG is true or 1 OR
133
+ # when OTEL_LOG_LEVEL is set to debug
134
+ ['true', '1', 'debug'].include?(value)
135
+ end
136
+ end
128
137
  o.after_set do |enabled|
129
138
  # Enable rich debug print statements.
130
139
  # We do not need to unnecessarily load 'pp' unless in debugging mode.
@@ -465,7 +474,7 @@ module Datadog
465
474
  o.type :string, nilable: true
466
475
 
467
476
  # NOTE: service also gets set as a side effect of tags. See the WORKAROUND note in #initialize for details.
468
- o.env Core::Environment::Ext::ENV_SERVICE
477
+ o.env [Core::Environment::Ext::ENV_SERVICE, Core::Environment::Ext::ENV_OTEL_SERVICE]
469
478
  o.default Core::Environment::Ext::FALLBACK_SERVICE_NAME
470
479
 
471
480
  # There's a few cases where we don't want to use the fallback service name, so this helper allows us to get a
@@ -500,14 +509,13 @@ module Datadog
500
509
  # @return [Hash<String,String>]
501
510
  option :tags do |o|
502
511
  o.type :hash, nilable: true
503
- o.env Core::Environment::Ext::ENV_TAGS
512
+ o.env [Core::Environment::Ext::ENV_TAGS, Core::Environment::Ext::ENV_OTEL_RESOURCE_ATTRIBUTES]
504
513
  o.env_parser do |env_value|
505
514
  values = if env_value.include?(',')
506
515
  env_value.split(',')
507
516
  else
508
517
  env_value.split(' ') # rubocop:disable Style/RedundantArgument
509
518
  end
510
-
511
519
  values.map! do |v|
512
520
  v.gsub!(/\A[\s,]*|[\s,]*\Z/, '')
513
521
 
@@ -517,7 +525,23 @@ module Datadog
517
525
  values.compact!
518
526
  values.each_with_object({}) do |tag, tags|
519
527
  key, value = tag.split(':', 2)
520
- tags[key] = value if value && !value.empty?
528
+ if value.nil?
529
+ # support tags/attributes delimited by the OpenTelemetry separator (`=`)
530
+ key, value = tag.split('=', 2)
531
+ end
532
+ next if value.nil? || value.empty?
533
+
534
+ # maps OpenTelemetry semantic attributes to Datadog tags
535
+ case key.downcase
536
+ when 'deployment.environment'
537
+ tags['env'] = value
538
+ when 'service.version'
539
+ tags['version'] = value
540
+ when 'service.name'
541
+ tags['service'] = value
542
+ else
543
+ tags[key] = value
544
+ end
521
545
  end
522
546
  end
523
547
  o.setter do |new_value, old_value|
@@ -18,8 +18,10 @@ module Datadog
18
18
  ENV_API_KEY = 'DD_API_KEY'
19
19
  ENV_ENVIRONMENT = 'DD_ENV'
20
20
  ENV_SERVICE = 'DD_SERVICE'
21
+ ENV_OTEL_SERVICE = 'OTEL_SERVICE_NAME'
21
22
  ENV_SITE = 'DD_SITE'
22
23
  ENV_TAGS = 'DD_TAGS'
24
+ ENV_OTEL_RESOURCE_ATTRIBUTES = 'OTEL_RESOURCE_ATTRIBUTES'
23
25
  ENV_VERSION = 'DD_VERSION'
24
26
  FALLBACK_SERVICE_NAME =
25
27
  begin
@@ -13,6 +13,7 @@ module Datadog
13
13
  # @public_api
14
14
  module Metrics
15
15
  ENV_ENABLED = 'DD_RUNTIME_METRICS_ENABLED'
16
+ ENV_OTEL_METRICS_EXPORTER = 'OTEL_METRICS_EXPORTER'
16
17
 
17
18
  METRIC_CLASS_COUNT = 'runtime.ruby.class_count'
18
19
  METRIC_GC_PREFIX = 'runtime.ruby.gc'
@@ -113,7 +113,10 @@ module Datadog
113
113
  conf_value('tracing.opentelemetry.enabled', !defined?(Datadog::OpenTelemetry::LOADED).nil?),
114
114
  )
115
115
  list << conf_value('logger.instance', config.logger.instance.class.to_s) if config.logger.instance
116
- list << conf_value('appsec.enabled', config.dig('appsec', 'enabled')) if config.respond_to?('appsec')
116
+ if config.respond_to?('appsec')
117
+ list << conf_value('appsec.enabled', config.dig('appsec', 'enabled'))
118
+ list << conf_value('appsec.sca_enabled', config.dig('appsec', 'sca_enabled'))
119
+ end
117
120
  list << conf_value('ci.enabled', config.dig('ci', 'enabled')) if config.respond_to?('ci')
118
121
 
119
122
  list.reject! { |entry| entry[:value].nil? }
@@ -242,15 +245,30 @@ module Datadog
242
245
  end
243
246
 
244
247
  def payload(seq_id)
245
- {
246
- configuration: @changes.map do |name, value|
247
- {
248
- name: name,
249
- value: value,
250
- origin: @origin,
251
- }
252
- end
253
- }
248
+ { configuration: configuration(seq_id) }
249
+ end
250
+
251
+ def configuration(seq_id)
252
+ config = Datadog.configuration
253
+
254
+ res = @changes.map do |name, value|
255
+ {
256
+ name: name,
257
+ value: value,
258
+ origin: @origin,
259
+ }
260
+ end
261
+
262
+ unless config.dig('appsec', 'sca_enabled').nil?
263
+ res << {
264
+ name: 'appsec.sca_enabled',
265
+ value: config.appsec.sca_enabled,
266
+ origin: 'code',
267
+ seq_id: seq_id,
268
+ }
269
+ end
270
+
271
+ res
254
272
  end
255
273
  end
256
274
 
@@ -9,6 +9,7 @@ module Datadog
9
9
  # e.g. Env vars, default values, enums, etc...
10
10
  module Ext
11
11
  ENV_ENABLED = 'DD_TRACE_ENABLED'
12
+ ENV_OTEL_TRACES_EXPORTER = 'OTEL_TRACES_EXPORTER'
12
13
  ENV_HEADER_TAGS = 'DD_TRACE_HEADER_TAGS'
13
14
  ENV_TRACE_ID_128_BIT_GENERATION_ENABLED = 'DD_TRACE_128_BIT_TRACEID_GENERATION_ENABLED'
14
15
 
@@ -39,10 +40,14 @@ module Datadog
39
40
  # W3C Trace Context
40
41
  PROPAGATION_STYLE_TRACE_CONTEXT = 'tracecontext'
41
42
 
43
+ PROPAGATION_STYLE_SUPPORTED = [PROPAGATION_STYLE_DATADOG, PROPAGATION_STYLE_B3_MULTI_HEADER,
44
+ PROPAGATION_STYLE_B3_SINGLE_HEADER, PROPAGATION_STYLE_TRACE_CONTEXT].freeze
45
+
42
46
  # Sets both extract and inject propagation style tho the provided value.
43
47
  # Has lower precedence than `DD_TRACE_PROPAGATION_STYLE_INJECT` or
44
48
  # `DD_TRACE_PROPAGATION_STYLE_EXTRACT`.
45
49
  ENV_PROPAGATION_STYLE = 'DD_TRACE_PROPAGATION_STYLE'
50
+ ENV_OTEL_PROPAGATION_STYLE = 'OTEL_PROPAGATORS'
46
51
 
47
52
  ENV_PROPAGATION_STYLE_INJECT = 'DD_TRACE_PROPAGATION_STYLE_INJECT'
48
53
 
@@ -68,6 +73,8 @@ module Datadog
68
73
  ENV_SAMPLE_RATE = 'DD_TRACE_SAMPLE_RATE'
69
74
  ENV_RATE_LIMIT = 'DD_TRACE_RATE_LIMIT'
70
75
  ENV_RULES = 'DD_TRACE_SAMPLING_RULES'
76
+ ENV_OTEL_TRACES_SAMPLER = 'OTEL_TRACES_SAMPLER'
77
+ OTEL_TRACES_SAMPLER_ARG = 'OTEL_TRACES_SAMPLER_ARG'
71
78
 
72
79
  # @public_api
73
80
  module Span
@@ -13,6 +13,8 @@ module Datadog
13
13
  # rubocop:disable Metrics/BlockLength
14
14
  # rubocop:disable Metrics/MethodLength
15
15
  # rubocop:disable Layout/LineLength
16
+ # rubocop:disable Metrics/CyclomaticComplexity
17
+ # rubocop:disable Metrics/PerceivedComplexity
16
18
  module Settings
17
19
  def self.extended(base)
18
20
  base.class_eval do
@@ -89,7 +91,7 @@ module Datadog
89
91
  # @return [Array<String>]
90
92
  option :propagation_style do |o|
91
93
  o.type :array
92
- o.env Configuration::Ext::Distributed::ENV_PROPAGATION_STYLE
94
+ o.env [Configuration::Ext::Distributed::ENV_PROPAGATION_STYLE, Configuration::Ext::Distributed::ENV_OTEL_PROPAGATION_STYLE]
93
95
  o.default []
94
96
  o.after_set do |styles|
95
97
  next if styles.empty?
@@ -97,6 +99,14 @@ module Datadog
97
99
  # Make values case-insensitive
98
100
  styles.map!(&:downcase)
99
101
 
102
+ styles.select! do |s|
103
+ if Configuration::Ext::Distributed::PROPAGATION_STYLE_SUPPORTED.include?(s)
104
+ true
105
+ else
106
+ Datadog.logger.warn("Unsupported propagation style: #{s}")
107
+ false
108
+ end
109
+ end
100
110
  set_option(:propagation_style_extract, styles)
101
111
  set_option(:propagation_style_inject, styles)
102
112
  end
@@ -121,9 +131,23 @@ module Datadog
121
131
  # @default `DD_TRACE_ENABLED` environment variable, otherwise `true`
122
132
  # @return [Boolean]
123
133
  option :enabled do |o|
124
- o.env Tracing::Configuration::Ext::ENV_ENABLED
134
+ o.env [Tracing::Configuration::Ext::ENV_ENABLED, Tracing::Configuration::Ext::ENV_OTEL_TRACES_EXPORTER]
125
135
  o.default true
126
136
  o.type :bool
137
+ o.env_parser do |value|
138
+ value = value&.downcase
139
+ # Tracing is disabled when OTEL_TRACES_EXPORTER is none or
140
+ # DD_TRACE_ENABLED is 0 or false.
141
+ if ['none', 'false', '0'].include?(value)
142
+ false
143
+ # Tracing is enabled when DD_TRACE_ENABLED is true or 1
144
+ elsif ['true', '1'].include?(value)
145
+ true
146
+ else
147
+ Datadog.logger.warn("Unsupported value for exporting datadog traces: #{value}. Traces will be sent to Datadog.")
148
+ nil
149
+ end
150
+ end
127
151
  end
128
152
 
129
153
  # Comma-separated, case-insensitive list of header names that are reported in incoming and outgoing HTTP requests.
@@ -245,7 +269,30 @@ module Datadog
245
269
  # @return [Float, nil]
246
270
  option :default_rate do |o|
247
271
  o.type :float, nilable: true
248
- o.env Tracing::Configuration::Ext::Sampling::ENV_SAMPLE_RATE
272
+ o.env [Tracing::Configuration::Ext::Sampling::ENV_SAMPLE_RATE, Tracing::Configuration::Ext::Sampling::ENV_OTEL_TRACES_SAMPLER]
273
+ o.env_parser do |value|
274
+ # Parse the value as a float
275
+ next if value.nil?
276
+
277
+ value = value&.downcase
278
+ if ['always_on', 'always_off', 'traceidratio'].include?(value)
279
+ Datadog.logger.warn("The value '#{value}' is not yet supported. 'parentbased_#{value}' will be used instead.")
280
+ value = "parentbased_#{value}"
281
+ end
282
+ # OTEL_TRACES_SAMPLER can be set to always_on, always_off, traceidratio, and/or parentbased value.
283
+ # These values are mapped to a sample rate.
284
+ # DD_TRACE_SAMPLE_RATE sets the sample rate to float.
285
+ case value
286
+ when 'parentbased_always_on'
287
+ 1.0
288
+ when 'parentbased_always_off'
289
+ 0.0
290
+ when 'parentbased_traceidratio'
291
+ ENV.fetch(Tracing::Configuration::Ext::Sampling::OTEL_TRACES_SAMPLER_ARG, 1.0).to_f
292
+ else
293
+ value.to_f
294
+ end
295
+ end
249
296
  end
250
297
 
251
298
  # Rate limit for number of spans per second.
@@ -417,6 +464,8 @@ module Datadog
417
464
  # rubocop:enable Metrics/BlockLength
418
465
  # rubocop:enable Metrics/MethodLength
419
466
  # rubocop:enable Layout/LineLength
467
+ # rubocop:enable Metrics/CyclomaticComplexity
468
+ # rubocop:enable Metrics/PerceivedComplexity
420
469
  end
421
470
  end
422
471
  end
@@ -101,10 +101,22 @@ module Datadog
101
101
  # Only parse if it represent the same trace as the successfully extracted one
102
102
  next unless tracecontext_digest.trace_id == extracted_trace_digest.trace_id
103
103
 
104
- # Preserve the `tracestate`
104
+ parent_id = extracted_trace_digest.span_id
105
+ distributed_tags = extracted_trace_digest.trace_distributed_tags
106
+ unless extracted_trace_digest.span_id == tracecontext_digest.span_id
107
+ # span_id in the tracecontext header takes precedence over the value in all conflicting headers
108
+ parent_id = tracecontext_digest.span_id
109
+ if (lp_id = last_datadog_parent_id(data, tracecontext_digest.trace_distributed_tags))
110
+ distributed_tags = extracted_trace_digest.trace_distributed_tags&.dup || {}
111
+ distributed_tags[Tracing::Metadata::Ext::Distributed::TAG_DD_PARENT_ID] = lp_id
112
+ end
113
+ end
114
+ # Preserve the trace state and last datadog span id
105
115
  extracted_trace_digest = extracted_trace_digest.merge(
116
+ span_id: parent_id,
106
117
  trace_state: tracecontext_digest.trace_state,
107
- trace_state_unknown_fields: tracecontext_digest.trace_state_unknown_fields
118
+ trace_state_unknown_fields: tracecontext_digest.trace_state_unknown_fields,
119
+ trace_distributed_tags: distributed_tags
108
120
  )
109
121
  end
110
122
  rescue => e
@@ -115,6 +127,22 @@ module Datadog
115
127
 
116
128
  extracted_trace_digest
117
129
  end
130
+
131
+ private
132
+
133
+ def last_datadog_parent_id(headers, tracecontext_tags)
134
+ dd_propagator = @propagation_style_extract.find { |propagator| propagator.is_a?(Datadog) }
135
+ if tracecontext_tags&.fetch(
136
+ Tracing::Metadata::Ext::Distributed::TAG_DD_PARENT_ID,
137
+ Tracing::Metadata::Ext::Distributed::DD_PARENT_ID_DEFAULT
138
+ ) != Tracing::Metadata::Ext::Distributed::DD_PARENT_ID_DEFAULT
139
+ # tracecontext headers contain a p value, ensure this value is sent to backend
140
+ tracecontext_tags[Tracing::Metadata::Ext::Distributed::TAG_DD_PARENT_ID]
141
+ elsif dd_propagator && (dd_digest = dd_propagator.extract(headers))
142
+ # if p value is not present in tracestate, use the parent id from the datadog headers
143
+ format('%016x', dd_digest.span_id)
144
+ end
145
+ end
118
146
  end
119
147
  end
120
148
  end
@@ -57,7 +57,8 @@ module Datadog
57
57
  end
58
58
 
59
59
  tags ||= {}
60
- tags[Tracing::Metadata::Ext::Distributed::TAG_DD_PARENT_ID] = ts_parent_id || '0000000000000000'
60
+ tags[Tracing::Metadata::Ext::Distributed::TAG_DD_PARENT_ID] =
61
+ ts_parent_id || Tracing::Metadata::Ext::Distributed::DD_PARENT_ID_DEFAULT
61
62
 
62
63
  TraceDigest.new(
63
64
  span_id: parent_id,
@@ -55,6 +55,7 @@ module Datadog
55
55
  TAG_SAMPLING_PRIORITY = '_sampling_priority_v1'
56
56
 
57
57
  TAG_DD_PARENT_ID = '_dd.parent_id'
58
+ DD_PARENT_ID_DEFAULT = '0000000000000000'
58
59
 
59
60
  # Trace tags with this prefix will propagate from a trace through distributed tracing.
60
61
  # Distributed headers tags with this prefix will be injected into the active trace.
@@ -3,7 +3,7 @@
3
3
  module Datadog
4
4
  module VERSION
5
5
  MAJOR = 2
6
- MINOR = 0
6
+ MINOR = 1
7
7
  PATCH = 0
8
8
  PRE = nil
9
9
  BUILD = nil
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: datadog
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.0
4
+ version: 2.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Datadog, Inc.
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-06-06 00:00:00.000000000 Z
11
+ date: 2024-06-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: msgpack
@@ -859,7 +859,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
859
859
  - !ruby/object:Gem::Version
860
860
  version: 2.0.0
861
861
  requirements: []
862
- rubygems_version: 3.4.21
862
+ rubygems_version: 3.4.10
863
863
  signing_key:
864
864
  specification_version: 4
865
865
  summary: Datadog tracing code for your Ruby applications