datadog 2.0.0.rc1 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5c8f4fef81d3a238299c70c27f6ece67dc31e76e4b6ad2180a2d1126e4c9545a
4
- data.tar.gz: 17bc14574f265b2fdba65d4030e37e513f6af33af6ce8be77e1bbb535d4f6ae4
3
+ metadata.gz: e0297728b2d8779a69af39f3dffa86af6b3765e3f2dd19cb685340ca7ad8e2ac
4
+ data.tar.gz: 3c7d3506df76790fea0b2e2047d1b2c4919e9d928ccb644086194197125391e7
5
5
  SHA512:
6
- metadata.gz: fff160e4a8e316ec82381e5ae6ef5687a434aa0798debcc689c37e127d688e3d0c0f1009befb6871096c77032caeed348df777ba9baab4c8f7d6f4582d02c8bd
7
- data.tar.gz: 6fb4d250c8838a101a489cc10ee0672c23dd4a9793ad850b17bc2c375881c0e3e4cf2c7c3bf5645a6ce8bce1e59c06cbb82609dffe489101fb3ba158d655f034
6
+ metadata.gz: ec2862773c6ee93e5d698d6b586a576413689a84f7d94a621c20088759469e1ad6742e13fc1e7f9250046212cec0e284abf4fb0048e255802c19f378cf7d428c
7
+ data.tar.gz: 507fbfd3f8879333c11336646e1a56ca453fbaf92c84fb0bae3b0e38435f3ea1ec6b3ddc756f848c76113a4e5832f8097cd521532541bf9ca8fdff6cca1e5ff3
data/CHANGELOG.md CHANGED
@@ -2,6 +2,22 @@
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
+
15
+ ## [2.0.0] - 2024-06-06
16
+
17
+ ### Added
18
+
19
+ * Tracing: Remap http status code tag for otel span for trace metrics ([#3664][])
20
+
5
21
  ## [2.0.0.rc1] - 2024-05-24
6
22
 
7
23
  ### Added
@@ -2888,7 +2904,9 @@ Release notes: https://github.com/DataDog/dd-trace-rb/releases/tag/v0.3.1
2888
2904
  Git diff: https://github.com/DataDog/dd-trace-rb/compare/v0.3.0...v0.3.1
2889
2905
 
2890
2906
 
2891
- [Unreleased]: https://github.com/DataDog/dd-trace-rb/compare/v2.0.0.rc1...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
2909
+ [2.0.0]: https://github.com/DataDog/dd-trace-rb/compare/v2.0.0.rc1...v2.0.0
2892
2910
  [2.0.0.rc1]: https://github.com/DataDog/dd-trace-rb/compare/v2.0.0.beta2...v2.0.0.rc1
2893
2911
  [1.23.0]: https://github.com/DataDog/dd-trace-rb/compare/v1.22.0...v1.23.0
2894
2912
  [2.0.0.beta2]: https://github.com/DataDog/dd-trace-rb/compare/v2.0.0.beta1...v2.0.0.beta2
@@ -4260,8 +4278,11 @@ Git diff: https://github.com/DataDog/dd-trace-rb/compare/v0.3.0...v0.3.1
4260
4278
  [#3624]: https://github.com/DataDog/dd-trace-rb/issues/3624
4261
4279
  [#3627]: https://github.com/DataDog/dd-trace-rb/issues/3627
4262
4280
  [#3630]: https://github.com/DataDog/dd-trace-rb/issues/3630
4281
+ [#3631]: https://github.com/DataDog/dd-trace-rb/issues/3631
4263
4282
  [#3645]: https://github.com/DataDog/dd-trace-rb/issues/3645
4264
4283
  [#3651]: https://github.com/DataDog/dd-trace-rb/issues/3651
4284
+ [#3657]: https://github.com/DataDog/dd-trace-rb/issues/3657
4285
+ [#3664]: https://github.com/DataDog/dd-trace-rb/issues/3664
4265
4286
  [@AdrianLC]: https://github.com/AdrianLC
4266
4287
  [@Azure7111]: https://github.com/Azure7111
4267
4288
  [@BabyGroot]: https://github.com/BabyGroot
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
 
@@ -112,6 +112,11 @@ module Datadog
112
112
  if attributes.key?('analytics.event') && (analytics_event = attributes['analytics.event']).respond_to?(:casecmp)
113
113
  attributes[Tracing::Metadata::Ext::Analytics::TAG_SAMPLE_RATE] = analytics_event.casecmp('true') == 0 ? 1 : 0
114
114
  end
115
+
116
+ if attributes.key?('http.response.status_code')
117
+ attributes[Tracing::Metadata::Ext::HTTP::TAG_STATUS_CODE] = attributes.delete('http.response.status_code')
118
+ end
119
+
115
120
  attributes[Tracing::Metadata::Ext::TAG_KIND] = span.kind || 'internal'
116
121
 
117
122
  kwargs = { start_time: ns_to_time(span.start_timestamp) }
@@ -141,10 +141,12 @@ module Datadog
141
141
  value.casecmp('true') == 0 ? 1 : 0
142
142
  )
143
143
  end
144
+
145
+ span.set_tag('http.status_code', value) if key == 'http.response.status_code'
144
146
  end
145
147
 
146
148
  DATADOG_SPAN_ATTRIBUTE_OVERRIDES = ['analytics.event', 'operation.name', 'resource.name', 'service.name',
147
- 'span.type'].freeze
149
+ 'span.type', 'http.response.status_code'].freeze
148
150
 
149
151
  ::OpenTelemetry::SDK::Trace::Span.prepend(self)
150
152
  end
@@ -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
@@ -73,12 +73,7 @@ module Datadog
73
73
  end
74
74
 
75
75
  def trace_id
76
- if Datadog.configuration.tracing.trace_id_128_bit_logging_enabled &&
77
- !Tracing::Utils::TraceId.to_high_order(@trace_id).zero?
78
- Kernel.format('%032x', @trace_id)
79
- else
80
- Tracing::Utils::TraceId.to_low_order(@trace_id).to_s
81
- end
76
+ Correlation.format_trace_id(@trace_id)
82
77
  end
83
78
  end
84
79
 
@@ -97,6 +92,15 @@ module Datadog
97
92
  trace_id: digest.trace_id,
98
93
  )
99
94
  end
95
+
96
+ def format_trace_id(trace_id)
97
+ if Datadog.configuration.tracing.trace_id_128_bit_logging_enabled &&
98
+ !Tracing::Utils::TraceId.to_high_order(trace_id).zero?
99
+ Kernel.format('%032x', trace_id)
100
+ else
101
+ Tracing::Utils::TraceId.to_low_order(trace_id).to_s
102
+ end
103
+ end
100
104
  end
101
105
  end
102
106
  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,9 +3,9 @@
3
3
  module Datadog
4
4
  module VERSION
5
5
  MAJOR = 2
6
- MINOR = 0
6
+ MINOR = 1
7
7
  PATCH = 0
8
- PRE = 'rc1'
8
+ PRE = nil
9
9
  BUILD = nil
10
10
  # PRE and BUILD above are modified for dev gems during gem build GHA workflow
11
11
 
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.rc1
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-05-24 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
@@ -837,6 +837,7 @@ files:
837
837
  homepage: https://github.com/DataDog/dd-trace-rb
838
838
  licenses:
839
839
  - BSD-3-Clause
840
+ - Apache-2.0
840
841
  metadata:
841
842
  allowed_push_host: https://rubygems.org
842
843
  changelog_uri: https://github.com/DataDog/dd-trace-rb/blob/master/CHANGELOG.md