ddtrace 1.16.0 → 1.18.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 (40) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +86 -1
  3. data/ext/ddtrace_profiling_native_extension/clock_id_from_pthread.c +3 -0
  4. data/ext/ddtrace_profiling_native_extension/collectors_thread_context.c +8 -1
  5. data/ext/ddtrace_profiling_native_extension/extconf.rb +28 -10
  6. data/ext/ddtrace_profiling_native_extension/http_transport.c +5 -2
  7. data/ext/ddtrace_profiling_native_extension/private_vm_api_access.c +78 -18
  8. data/ext/ddtrace_profiling_native_extension/private_vm_api_access.h +6 -0
  9. data/ext/ddtrace_profiling_native_extension/profiling.c +1 -0
  10. data/ext/ddtrace_profiling_native_extension/stack_recorder.c +1 -3
  11. data/lib/datadog/appsec/component.rb +4 -1
  12. data/lib/datadog/appsec/configuration/settings.rb +4 -6
  13. data/lib/datadog/appsec/contrib/devise/patcher/registration_controller_patch.rb +2 -0
  14. data/lib/datadog/appsec/contrib/rack/gateway/response.rb +0 -46
  15. data/lib/datadog/appsec/contrib/rack/reactive/response.rb +0 -5
  16. data/lib/datadog/appsec/contrib/rack/request_middleware.rb +0 -10
  17. data/lib/datadog/appsec/processor/rule_loader.rb +60 -0
  18. data/lib/datadog/appsec/remote.rb +12 -9
  19. data/lib/datadog/core/configuration/settings.rb +1 -1
  20. data/lib/datadog/core/configuration.rb +4 -0
  21. data/lib/datadog/core/remote/worker.rb +1 -0
  22. data/lib/datadog/core/workers/async.rb +1 -0
  23. data/lib/datadog/kit/enable_core_dumps.rb +5 -6
  24. data/lib/datadog/opentelemetry/sdk/span_processor.rb +39 -8
  25. data/lib/datadog/opentelemetry/sdk/trace/span.rb +102 -3
  26. data/lib/datadog/opentracer/text_map_propagator.rb +2 -1
  27. data/lib/datadog/profiling/collectors/cpu_and_wall_time_worker.rb +1 -0
  28. data/lib/datadog/profiling/collectors/idle_sampling_helper.rb +1 -0
  29. data/lib/datadog/profiling/component.rb +13 -5
  30. data/lib/datadog/tracing/configuration/ext.rb +3 -0
  31. data/lib/datadog/tracing/configuration/settings.rb +18 -3
  32. data/lib/datadog/tracing/contrib/concurrent_ruby/context_composite_executor_service.rb +1 -1
  33. data/lib/datadog/tracing/contrib/pg/configuration/settings.rb +5 -0
  34. data/lib/datadog/tracing/contrib/pg/instrumentation.rb +24 -0
  35. data/lib/datadog/tracing/distributed/datadog.rb +0 -1
  36. data/lib/datadog/tracing/distributed/propagation.rb +25 -4
  37. data/lib/datadog/tracing/trace_digest.rb +31 -0
  38. data/lib/datadog/tracing/workers.rb +1 -0
  39. data/lib/ddtrace/version.rb +1 -1
  40. metadata +7 -7
@@ -47,6 +47,13 @@ module Datadog
47
47
  data
48
48
  end
49
49
 
50
+ def load_exclusions(ip_passlist: [])
51
+ exclusions = []
52
+ exclusions << [passlist_exclusions(ip_passlist)] if ip_passlist.any?
53
+
54
+ exclusions
55
+ end
56
+
50
57
  private
51
58
 
52
59
  def denylist_data(id, denylist)
@@ -56,6 +63,59 @@ module Datadog
56
63
  'data' => denylist.map { |v| { 'value' => v.to_s, 'expiration' => 2**63 } }
57
64
  }
58
65
  end
66
+
67
+ def passlist_exclusions(ip_passlist) # rubocop:disable Metrics/MethodLength
68
+ case ip_passlist
69
+ when Array
70
+ pass = ip_passlist
71
+ monitor = []
72
+ when Hash
73
+ pass = ip_passlist[:pass]
74
+ monitor = ip_passlist[:monitor]
75
+ else
76
+ pass = []
77
+ monitor = []
78
+ end
79
+
80
+ exclusions = []
81
+
82
+ exclusions << {
83
+ 'conditions' => [
84
+ {
85
+ 'operator' => 'ip_match',
86
+ 'parameters' => {
87
+ 'inputs' => [
88
+ {
89
+ 'address' => 'http.client_ip'
90
+ }
91
+ ],
92
+ 'list' => pass
93
+ }
94
+ }
95
+ ],
96
+ 'id' => SecureRandom.uuid,
97
+ }
98
+
99
+ exclusions << {
100
+ 'conditions' => [
101
+ {
102
+ 'operator' => 'ip_match',
103
+ 'parameters' => {
104
+ 'inputs' => [
105
+ {
106
+ 'address' => 'http.client_ip'
107
+ }
108
+ ],
109
+ 'list' => monitor
110
+ }
111
+ }
112
+ ],
113
+ 'id' => SecureRandom.uuid,
114
+ 'on_match' => 'monitor'
115
+ }
116
+
117
+ exclusions
118
+ end
59
119
  end
60
120
  end
61
121
  end
@@ -12,15 +12,17 @@ module Datadog
12
12
  class NoRulesError < StandardError; end
13
13
 
14
14
  class << self
15
- CAP_ASM_ACTIVATION = 1 << 1 # Remote activation via ASM_FEATURES product
16
- CAP_ASM_IP_BLOCKING = 1 << 2 # accept IP blocking data from ASM_DATA product
17
- CAP_ASM_DD_RULES = 1 << 3 # read ASM rules from ASM_DD product
18
- CAP_ASM_EXCLUSIONS = 1 << 4 # exclusion filters (passlist) via ASM product
19
- CAP_ASM_REQUEST_BLOCKING = 1 << 5 # can block on request info
20
- CAP_ASM_RESPONSE_BLOCKING = 1 << 6 # can block on response info
21
- CAP_ASM_USER_BLOCKING = 1 << 7 # accept user blocking data from ASM_DATA product
22
- CAP_ASM_CUSTOM_RULES = 1 << 8 # accept custom rules
23
- CAP_ASM_CUSTOM_BLOCKING_RESPONSE = 1 << 9 # supports custom http code or redirect sa blocking response
15
+ CAP_ASM_RESERVED_1 = 1 << 0 # RESERVED
16
+ CAP_ASM_ACTIVATION = 1 << 1 # Remote activation via ASM_FEATURES product
17
+ CAP_ASM_IP_BLOCKING = 1 << 2 # accept IP blocking data from ASM_DATA product
18
+ CAP_ASM_DD_RULES = 1 << 3 # read ASM rules from ASM_DD product
19
+ CAP_ASM_EXCLUSIONS = 1 << 4 # exclusion filters (passlist) via ASM product
20
+ CAP_ASM_REQUEST_BLOCKING = 1 << 5 # can block on request info
21
+ CAP_ASM_RESPONSE_BLOCKING = 1 << 6 # can block on response info
22
+ CAP_ASM_USER_BLOCKING = 1 << 7 # accept user blocking data from ASM_DATA product
23
+ CAP_ASM_CUSTOM_RULES = 1 << 8 # accept custom rules
24
+ CAP_ASM_CUSTOM_BLOCKING_RESPONSE = 1 << 9 # supports custom http code or redirect sa blocking response
25
+ CAP_ASM_TRUSTED_IPS = 1 << 10 # supports trusted ip
24
26
 
25
27
  # TODO: we need to dynamically add CAP_ASM_ACTIVATION once we support it
26
28
  ASM_CAPABILITIES = [
@@ -32,6 +34,7 @@ module Datadog
32
34
  CAP_ASM_DD_RULES,
33
35
  CAP_ASM_CUSTOM_RULES,
34
36
  CAP_ASM_CUSTOM_BLOCKING_RESPONSE,
37
+ CAP_ASM_TRUSTED_IPS,
35
38
  ].freeze
36
39
 
37
40
  ASM_PRODUCTS = [
@@ -330,7 +330,7 @@ module Datadog
330
330
  # Caveat 3 (severe):
331
331
  # Ruby 3.2.0 to 3.2.2 have a bug in the newobj tracepoint (https://bugs.ruby-lang.org/issues/19482,
332
332
  # https://github.com/ruby/ruby/pull/7464) so that's an extra reason why it's not safe on those Rubies.
333
- # This bug is fixed on Ruby versions 3.2.2 and 3.3.0.
333
+ # This bug is fixed on Ruby versions 3.2.3 and 3.3.0.
334
334
  #
335
335
  # @default `true` on Ruby 2.x and 3.1.4+, 3.2.3+ and 3.3.0+; `false` for Ruby 3.0 and unpatched Rubies.
336
336
  option :allocation_counting_enabled do |o|
@@ -273,6 +273,10 @@ module Datadog
273
273
  def handle_interrupt_shutdown!
274
274
  logger = Datadog.logger
275
275
  shutdown_thread = Thread.new { shutdown! }
276
+ unless Gem::Version.new(RUBY_VERSION) < Gem::Version.new('2.3')
277
+ shutdown_thread.name = Datadog::Core::Configuration.name
278
+ end
279
+
276
280
  print_message_treshold_seconds = 0.2
277
281
 
278
282
  slow_shutdown = shutdown_thread.join(print_message_treshold_seconds).nil?
@@ -30,6 +30,7 @@ module Datadog
30
30
 
31
31
  thread = Thread.new { poll(@interval) }
32
32
  thread.name = self.class.name unless Gem::Version.new(RUBY_VERSION) < Gem::Version.new('2.3')
33
+ thread.thread_variable_set(:fork_safe, true)
33
34
  @thr = thread
34
35
 
35
36
  @started = true
@@ -147,6 +147,7 @@ module Datadog
147
147
  # rubocop:enable Lint/RescueException
148
148
  end
149
149
  @worker.name = self.class.name unless Gem::Version.new(RUBY_VERSION) < Gem::Version.new('2.3')
150
+ @worker.thread_variable_set(:fork_safe, true)
150
151
 
151
152
  nil
152
153
  end
@@ -16,11 +16,13 @@ module Datadog
16
16
  '(Could not open /proc/sys/kernel/core_pattern)'
17
17
  end
18
18
 
19
+ enabled_status = "Maximum size: #{maximum_size} Output pattern: '#{core_pattern}'"
20
+
19
21
  if maximum_size <= 0
20
22
  Kernel.warn("[ddtrace] Could not enable core dumps on crash, maximum size is #{maximum_size} (disabled).")
21
23
  return
22
24
  elsif maximum_size == current_size
23
- Kernel.warn('[ddtrace] Core dumps already enabled, nothing to do!')
25
+ Kernel.warn("[ddtrace] Core dumps already enabled, nothing to do. #{enabled_status}")
24
26
  return
25
27
  end
26
28
 
@@ -35,12 +37,9 @@ module Datadog
35
37
  end
36
38
 
37
39
  if current_size == 0
38
- Kernel.warn("[ddtrace] Enabled core dumps. Maximum size: #{maximum_size} Output pattern: '#{core_pattern}'")
40
+ Kernel.warn("[ddtrace] Enabled core dumps. #{enabled_status}")
39
41
  else
40
- Kernel.warn(
41
- "[ddtrace] Raised core dump limit. Old size: #{current_size} " \
42
- "Maximum size: #{maximum_size} Output pattern: '#{core_pattern}'"
43
- )
42
+ Kernel.warn("[ddtrace] Raised core dump limit. Old size: #{current_size} #{enabled_status}")
44
43
  end
45
44
  end
46
45
  end
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative 'trace/span'
4
+
3
5
  module Datadog
4
6
  module OpenTelemetry
5
7
  module SDK
@@ -76,16 +78,11 @@ module Datadog
76
78
  end
77
79
 
78
80
  def start_datadog_span(span)
79
- tags = span.resource.attribute_enumerator.to_h
81
+ attributes = span.attributes.dup # Dup to allow modification of frozen Hash
80
82
 
81
- kind = span.kind || 'internal'
82
- tags[Tracing::Metadata::Ext::TAG_KIND] = kind
83
+ name, kwargs = span_arguments(span, attributes)
83
84
 
84
- datadog_span = Tracing.trace(
85
- span.name,
86
- tags: tags,
87
- start_time: ns_to_time(span.start_timestamp)
88
- )
85
+ datadog_span = Tracing.trace(name, **kwargs)
89
86
 
90
87
  datadog_span.set_error([nil, span.status.description]) unless span.status.ok?
91
88
  datadog_span.set_tags(span.attributes)
@@ -93,6 +90,40 @@ module Datadog
93
90
  datadog_span
94
91
  end
95
92
 
93
+ # Some special attributes can override Datadog Span fields
94
+ def span_arguments(span, attributes)
95
+ if attributes.key?('analytics.event') && (analytics_event = attributes['analytics.event']).respond_to?(:casecmp)
96
+ attributes[Tracing::Metadata::Ext::Analytics::TAG_SAMPLE_RATE] = analytics_event.casecmp('true') == 0 ? 1 : 0
97
+ end
98
+ attributes[Tracing::Metadata::Ext::TAG_KIND] = span.kind || 'internal'
99
+
100
+ kwargs = { start_time: ns_to_time(span.start_timestamp) }
101
+
102
+ name = if attributes.key?('operation.name')
103
+ attributes['operation.name']
104
+ elsif (rich_name = Datadog::OpenTelemetry::Trace::Span.enrich_name(span.kind, attributes))
105
+ rich_name.downcase
106
+ else
107
+ span.kind
108
+ end
109
+
110
+ kwargs[:resource] = attributes.key?('resource.name') ? attributes['resource.name'] : span.name
111
+ kwargs[:service] = attributes['service.name'] if attributes.key?('service.name')
112
+ kwargs[:type] = attributes['span.type'] if attributes.key?('span.type')
113
+
114
+ attributes.reject! { |key, _| OpenTelemetry::Trace::Span::DATADOG_SPAN_ATTRIBUTE_OVERRIDES.include?(key) }
115
+
116
+ # DEV: There's no `flat_map!`; we have to split it into two operations
117
+ attributes = attributes.map do |key, value|
118
+ Datadog::OpenTelemetry::Trace::Span.serialize_attribute(key, value)
119
+ end
120
+ attributes.flatten!(1)
121
+
122
+ kwargs[:tags] = attributes
123
+
124
+ [name, kwargs]
125
+ end
126
+
96
127
  # From nanoseconds, used by OpenTelemetry, to a {Time} object, used by the Datadog Tracer.
97
128
  def ns_to_time(timestamp_ns)
98
129
  Time.at(timestamp_ns / 1000000000.0)
@@ -36,6 +36,78 @@ module Datadog
36
36
  span.set_error(status.description) if status && status.code == ::OpenTelemetry::Trace::Status::ERROR
37
37
  end
38
38
 
39
+ # Serialize values into Datadog span tags and metrics.
40
+ # Notably, arrays are exploded into many keys, each with
41
+ # a numeric suffix representing the array index, for example:
42
+ # `'foo' => ['a','b']` becomes `'foo.0' => 'a', 'foo.1' => 'b'`
43
+ def self.serialize_attribute(key, value)
44
+ if value.is_a?(Array)
45
+ value.flat_map.with_index do |v, idx|
46
+ serialize_attribute("#{key}.#{idx}", v)
47
+ end
48
+ elsif value.is_a?(TrueClass) || value.is_a?(FalseClass)
49
+ [[key, value.to_s]]
50
+ else
51
+ [[key, value]]
52
+ end
53
+ end
54
+
55
+ # Create a meaningful Datadog operation name from the OpenTelemetry
56
+ # semantic convention for span kind and span attributes.
57
+ # @see https://opentelemetry.io/docs/specs/semconv/general/trace/
58
+
59
+ # rubocop:disable Metrics/CyclomaticComplexity,Metrics/PerceivedComplexity
60
+ def self.enrich_name(kind, attrs)
61
+ if attrs.key?('http.request.method')
62
+ return 'http.server.request' if kind == :server
63
+ return 'http.client.request' if kind == :client
64
+ end
65
+
66
+ return "#{attrs['db.system']}.query" if attrs.key?('db.system') && kind == :client
67
+
68
+ if (attrs.key?('messaging.system') || attrs.key?('messaging.operation')) &&
69
+ [:consumer, :producer, :server, :client].include?(kind)
70
+
71
+ return "#{attrs['messaging.system']}.#{attrs['messaging.operation']}"
72
+ end
73
+
74
+ if attrs.key?('rpc.system')
75
+ if attrs['rpc.system'] == 'aws-api' && kind == :client
76
+ service = attrs['rpc.service']
77
+ return "aws.#{service || 'client'}.request"
78
+ end
79
+
80
+ if kind == :client
81
+ return "#{attrs['rpc.system']}.client.request"
82
+ elsif kind == :server
83
+ return "#{attrs['rpc.system']}.server.request"
84
+ end
85
+ end
86
+
87
+ if attrs.key?('faas.invoked_provider') && attrs.key?('faas.invoked_name') && kind == :client
88
+ provider = attrs['faas.invoked_provider']
89
+ name = attrs['faas.invoked_name']
90
+ return "#{provider}.#{name}.invoke"
91
+ end
92
+
93
+ return "#{attrs['faas.trigger']}.invoke" if attrs.key?('faas.trigger') && kind == :server
94
+
95
+ return 'graphql.server.request' if attrs.key?('graphql.operation.type')
96
+
97
+ if kind == :server
98
+ protocol = attrs['network.protocol.name']
99
+ return protocol ? "#{protocol}.server.request" : 'server.request'
100
+ end
101
+
102
+ if kind == :client
103
+ protocol = attrs['network.protocol.name']
104
+ return protocol ? "#{protocol}.client.request" : 'client.request'
105
+ end
106
+
107
+ kind.to_s
108
+ end
109
+ # rubocop:enable Metrics/CyclomaticComplexity,Metrics/PerceivedComplexity
110
+
39
111
  private
40
112
 
41
113
  def datadog_set_attribute(key)
@@ -46,10 +118,18 @@ module Datadog
46
118
  # DEV: Accesses `@attributes` directly, since using `#attributes`
47
119
  # DEV: clones the hash, causing unnecessary overhead.
48
120
  if @attributes.key?(key)
49
- value = @attributes[key]
50
- span.set_tag(key, value)
121
+ # Try to find a richer operation name, unless an explicit override was provided.
122
+ if !@attributes.key?('operation.name') && (rich_name = Span.enrich_name(kind, @attributes))
123
+ span.name = rich_name.downcase
124
+ end
125
+
126
+ Span.serialize_attribute(key, @attributes[key]).each do |new_key, value|
127
+ override_datadog_values(span, new_key, value)
51
128
 
52
- span.service = value if key == 'service.name'
129
+ # When an attribute is used to override a Datadog Span property,
130
+ # it should NOT be set as a Datadog Span tag.
131
+ span.set_tag(new_key, value) unless DATADOG_SPAN_ATTRIBUTE_OVERRIDES.include?(new_key)
132
+ end
53
133
  else
54
134
  span.clear_tag(key)
55
135
 
@@ -61,6 +141,25 @@ module Datadog
61
141
  end
62
142
  end
63
143
 
144
+ # Some special attributes can override Datadog Span fields beyond tags and metrics.
145
+ # @return [Boolean] true if the key is a Datadog Span override attribute, false otherwise
146
+ def override_datadog_values(span, key, value)
147
+ span.name = value if key == 'operation.name'
148
+ span.resource = value if key == 'resource.name'
149
+ span.service = value if key == 'service.name'
150
+ span.type = value if key == 'span.type'
151
+
152
+ if key == 'analytics.event' && value.respond_to?(:casecmp)
153
+ Datadog::Tracing::Analytics.set_sample_rate(
154
+ span,
155
+ value.casecmp('true') == 0 ? 1 : 0
156
+ )
157
+ end
158
+ end
159
+
160
+ DATADOG_SPAN_ATTRIBUTE_OVERRIDES = ['analytics.event', 'operation.name', 'resource.name', 'service.name',
161
+ 'span.type'].freeze
162
+
64
163
  ::OpenTelemetry::SDK::Trace::Span.prepend(self)
65
164
  end
66
165
  end
@@ -33,7 +33,8 @@ module Datadog
33
33
  carrier[Tracing::Distributed::Datadog::ORIGIN_KEY] = digest.trace_origin
34
34
  carrier[Tracing::Distributed::Datadog::PARENT_ID_KEY] = digest.span_id
35
35
  carrier[Tracing::Distributed::Datadog::SAMPLING_PRIORITY_KEY] = digest.trace_sampling_priority
36
- carrier[Tracing::Distributed::Datadog::TRACE_ID_KEY] = digest.trace_id
36
+ carrier[Tracing::Distributed::Datadog::TRACE_ID_KEY] =
37
+ Datadog::Tracing::Utils::TraceId.to_low_order(digest.trace_id)
37
38
 
38
39
  nil
39
40
  end
@@ -78,6 +78,7 @@ module Datadog
78
78
  end
79
79
  end
80
80
  @worker_thread.name = self.class.name # Repeated from above to make sure thread gets named asap
81
+ @worker_thread.thread_variable_set(:fork_safe, true)
81
82
  end
82
83
 
83
84
  true
@@ -43,6 +43,7 @@ module Datadog
43
43
  end
44
44
  end
45
45
  @worker_thread.name = self.class.name # Repeated from above to make sure thread gets named asap
46
+ @worker_thread.thread_variable_set(:fork_safe, true)
46
47
  end
47
48
 
48
49
  true
@@ -171,12 +171,11 @@ module Datadog
171
171
  return true
172
172
  end
173
173
 
174
- if defined?(::PhusionPassenger)
174
+ if (defined?(::PhusionPassenger) || Gem.loaded_specs['passenger']) && incompatible_passenger_version?
175
175
  Datadog.logger.warn(
176
- 'Enabling the profiling "no signals" workaround because the passenger web server is in use. ' \
177
- 'This is needed because passenger is currently incompatible with the normal working mode ' \
178
- 'of the profiler, as detailed in <https://github.com/DataDog/dd-trace-rb/issues/2976>. ' \
179
- 'Profiling data will have lower quality.'
176
+ 'Enabling the profiling "no signals" workaround because an incompatible version of the passenger gem is ' \
177
+ 'installed. Profiling data will have lower quality.' \
178
+ 'To fix this, upgrade the passenger gem to version 6.0.19 or above.'
180
179
  )
181
180
  return true
182
181
  end
@@ -237,6 +236,15 @@ module Datadog
237
236
  true
238
237
  end
239
238
  end
239
+
240
+ # See https://github.com/datadog/dd-trace-rb/issues/2976 for details.
241
+ private_class_method def self.incompatible_passenger_version?
242
+ if Gem.loaded_specs['passenger']
243
+ Gem.loaded_specs['passenger'].version < Gem::Version.new('6.0.19')
244
+ else
245
+ true
246
+ end
247
+ end
240
248
  end
241
249
  end
242
250
  end
@@ -62,6 +62,9 @@ module Datadog
62
62
  # @see https://opentelemetry.io/docs/concepts/sdk-configuration/general-sdk-configuration/#get_otel__propagators
63
63
  PROPAGATION_STYLE_NONE = 'none'
64
64
 
65
+ # Strictly stop at the first successfully serialized style.
66
+ EXTRACT_FIRST = 'DD_TRACE_PROPAGATION_EXTRACT_FIRST'
67
+
65
68
  ENV_X_DATADOG_TAGS_MAX_LENGTH = 'DD_TRACE_X_DATADOG_TAGS_MAX_LENGTH'
66
69
  end
67
70
 
@@ -63,6 +63,7 @@ module Datadog
63
63
  Tracing::Configuration::Ext::Distributed::PROPAGATION_STYLE_DATADOG,
64
64
  Tracing::Configuration::Ext::Distributed::PROPAGATION_STYLE_B3_MULTI_HEADER,
65
65
  Tracing::Configuration::Ext::Distributed::PROPAGATION_STYLE_B3_SINGLE_HEADER,
66
+ Tracing::Configuration::Ext::Distributed::PROPAGATION_STYLE_TRACE_CONTEXT,
66
67
  ]
67
68
  )
68
69
  o.after_set do |styles|
@@ -93,7 +94,10 @@ module Datadog
93
94
  o.deprecated_env Tracing::Configuration::Ext::Distributed::ENV_PROPAGATION_STYLE_INJECT_OLD
94
95
  o.env Tracing::Configuration::Ext::Distributed::ENV_PROPAGATION_STYLE_INJECT
95
96
  # DEV-2.0: Change default value to `tracecontext, Datadog`.
96
- o.default [Tracing::Configuration::Ext::Distributed::PROPAGATION_STYLE_DATADOG]
97
+ o.default [
98
+ Tracing::Configuration::Ext::Distributed::PROPAGATION_STYLE_DATADOG,
99
+ Tracing::Configuration::Ext::Distributed::PROPAGATION_STYLE_TRACE_CONTEXT,
100
+ ]
97
101
  o.after_set do |styles|
98
102
  # Modernize B3 options
99
103
  # DEV-2.0: Can be removed with the removal of deprecated B3 constants.
@@ -142,6 +146,17 @@ module Datadog
142
146
  set_option(:propagation_inject_style, styles)
143
147
  end
144
148
  end
149
+
150
+ # Strictly stop at the first successfully serialized style.
151
+ # This prevents the tracer from enriching the extracted context with information from
152
+ # other valid propagations styles present in the request.
153
+ # @default `DD_TRACE_PROPAGATION_EXTRACT_FIRST` environment variable, otherwise `false`.
154
+ # @return [Boolean]
155
+ option :propagation_extract_first do |o|
156
+ o.env Tracing::Configuration::Ext::Distributed::EXTRACT_FIRST
157
+ o.default false
158
+ o.type :bool
159
+ end
145
160
  end
146
161
 
147
162
  # Enable trace collection and span generation.
@@ -177,11 +192,11 @@ module Datadog
177
192
 
178
193
  # Enable 128 bit trace id generation.
179
194
  #
180
- # @default `DD_TRACE_128_BIT_TRACEID_GENERATION_ENABLED` environment variable, otherwise `false`
195
+ # @default `DD_TRACE_128_BIT_TRACEID_GENERATION_ENABLED` environment variable, otherwise `true`
181
196
  # @return [Boolean]
182
197
  option :trace_id_128_bit_generation_enabled do |o|
183
198
  o.env Tracing::Configuration::Ext::ENV_TRACE_ID_128_BIT_GENERATION_ENABLED
184
- o.default false
199
+ o.default true
185
200
  o.type :bool
186
201
  end
187
202
 
@@ -19,7 +19,7 @@ module Datadog
19
19
  # post method runs the task within composited executor - in a different thread. The original arguments are
20
20
  # captured to be propagated to the composited executor post method
21
21
  def post(*args, &task)
22
- digest = Tracing.active_trace.to_digest
22
+ digest = Tracing.active_trace && Tracing.active_trace.to_digest
23
23
  executor = @composited_executor.is_a?(Symbol) ? Concurrent.executor(@composited_executor) : @composited_executor
24
24
 
25
25
  # Pass the original arguments to the composited executor, which
@@ -25,6 +25,11 @@ module Datadog
25
25
  o.default false
26
26
  end
27
27
 
28
+ option :error_handler do |o|
29
+ o.type :proc
30
+ o.default_proc(&Tracing::SpanOperation::Events::DEFAULT_ON_ERROR)
31
+ end
32
+
28
33
  option :analytics_sample_rate do |o|
29
34
  o.type :float
30
35
  o.env Ext::ENV_ANALYTICS_SAMPLE_RATE
@@ -21,18 +21,24 @@ module Datadog
21
21
  # PG::Connection patch methods
22
22
  module InstanceMethods
23
23
  def exec(sql, *args, &block)
24
+ return super unless enabled?
25
+
24
26
  trace(Ext::SPAN_EXEC, sql: sql, block: block) do |sql_statement, wrapped_block|
25
27
  super(sql_statement, *args, &wrapped_block)
26
28
  end
27
29
  end
28
30
 
29
31
  def exec_params(sql, params, *args, &block)
32
+ return super unless enabled?
33
+
30
34
  trace(Ext::SPAN_EXEC_PARAMS, sql: sql, block: block) do |sql_statement, wrapped_block|
31
35
  super(sql_statement, params, *args, &wrapped_block)
32
36
  end
33
37
  end
34
38
 
35
39
  def exec_prepared(statement_name, params, *args, &block)
40
+ return super unless enabled?
41
+
36
42
  trace(Ext::SPAN_EXEC_PREPARED, statement_name: statement_name, block: block) do |_, wrapped_block|
37
43
  super(statement_name, params, *args, &wrapped_block)
38
44
  end
@@ -40,6 +46,8 @@ module Datadog
40
46
 
41
47
  # async_exec is an alias to exec
42
48
  def async_exec(sql, *args, &block)
49
+ return super unless enabled?
50
+
43
51
  trace(Ext::SPAN_ASYNC_EXEC, sql: sql, block: block) do |sql_statement, wrapped_block|
44
52
  super(sql_statement, *args, &wrapped_block)
45
53
  end
@@ -47,6 +55,8 @@ module Datadog
47
55
 
48
56
  # async_exec_params is an alias to exec_params
49
57
  def async_exec_params(sql, params, *args, &block)
58
+ return super unless enabled?
59
+
50
60
  trace(Ext::SPAN_ASYNC_EXEC_PARAMS, sql: sql, block: block) do |sql_statement, wrapped_block|
51
61
  super(sql_statement, params, *args, &wrapped_block)
52
62
  end
@@ -54,24 +64,32 @@ module Datadog
54
64
 
55
65
  # async_exec_prepared is an alias to exec_prepared
56
66
  def async_exec_prepared(statement_name, params, *args, &block)
67
+ return super unless enabled?
68
+
57
69
  trace(Ext::SPAN_ASYNC_EXEC_PREPARED, statement_name: statement_name, block: block) do |_, wrapped_block|
58
70
  super(statement_name, params, *args, &wrapped_block)
59
71
  end
60
72
  end
61
73
 
62
74
  def sync_exec(sql, *args, &block)
75
+ return super unless enabled?
76
+
63
77
  trace(Ext::SPAN_SYNC_EXEC, sql: sql, block: block) do |sql_statement, wrapped_block|
64
78
  super(sql_statement, *args, &wrapped_block)
65
79
  end
66
80
  end
67
81
 
68
82
  def sync_exec_params(sql, params, *args, &block)
83
+ return super unless enabled?
84
+
69
85
  trace(Ext::SPAN_SYNC_EXEC_PARAMS, sql: sql, block: block) do |sql_statement, wrapped_block|
70
86
  super(sql_statement, params, *args, &wrapped_block)
71
87
  end
72
88
  end
73
89
 
74
90
  def sync_exec_prepared(statement_name, params, *args, &block)
91
+ return super unless enabled?
92
+
75
93
  trace(Ext::SPAN_SYNC_EXEC_PREPARED, statement_name: statement_name, block: block) do |_, wrapped_block|
76
94
  super(statement_name, params, *args, &wrapped_block)
77
95
  end
@@ -81,10 +99,12 @@ module Datadog
81
99
 
82
100
  def trace(name, sql: nil, statement_name: nil, block: nil)
83
101
  service = Datadog.configuration_for(self, :service_name) || datadog_configuration[:service_name]
102
+ error_handler = datadog_configuration[:error_handler]
84
103
  resource = statement_name || sql
85
104
 
86
105
  Tracing.trace(
87
106
  name,
107
+ on_error: error_handler,
88
108
  service: service,
89
109
  resource: resource,
90
110
  type: Tracing::Metadata::Ext::SQL::TYPE
@@ -172,6 +192,10 @@ module Datadog
172
192
  def comment_propagation
173
193
  datadog_configuration[:comment_propagation]
174
194
  end
195
+
196
+ def enabled?
197
+ datadog_configuration[:enabled]
198
+ end
175
199
  end
176
200
  end
177
201
  end
@@ -49,7 +49,6 @@ module Datadog
49
49
  build_tags(digest).tap do |tags|
50
50
  inject_tags!(tags, data) unless tags.empty?
51
51
  end
52
-
53
52
  data
54
53
  end
55
54