datadog 2.12.2 → 2.14.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 +4 -4
- data/CHANGELOG.md +51 -1
- data/ext/datadog_profiling_native_extension/collectors_thread_context.c +14 -13
- data/lib/datadog/appsec/actions_handler/serializable_backtrace.rb +89 -0
- data/lib/datadog/appsec/actions_handler.rb +22 -1
- data/lib/datadog/appsec/anonymizer.rb +16 -0
- data/lib/datadog/appsec/configuration/settings.rb +62 -10
- data/lib/datadog/appsec/contrib/auto_instrument.rb +1 -1
- data/lib/datadog/appsec/contrib/devise/configuration.rb +7 -31
- data/lib/datadog/appsec/contrib/devise/data_extractor.rb +79 -0
- data/lib/datadog/appsec/contrib/devise/ext.rb +21 -0
- data/lib/datadog/appsec/contrib/devise/integration.rb +0 -1
- data/lib/datadog/appsec/contrib/devise/patcher.rb +36 -23
- data/lib/datadog/appsec/contrib/devise/patches/signin_tracking_patch.rb +102 -0
- data/lib/datadog/appsec/contrib/devise/patches/signup_tracking_patch.rb +69 -0
- data/lib/datadog/appsec/contrib/devise/{patcher/rememberable_patch.rb → patches/skip_signin_tracking_patch.rb} +2 -2
- data/lib/datadog/appsec/contrib/devise/tracking_middleware.rb +93 -0
- data/lib/datadog/appsec/contrib/rack/ext.rb +14 -0
- data/lib/datadog/appsec/contrib/rack/gateway/watcher.rb +10 -3
- data/lib/datadog/appsec/contrib/rack/request_middleware.rb +0 -2
- data/lib/datadog/appsec/event.rb +1 -1
- data/lib/datadog/appsec/ext.rb +4 -2
- data/lib/datadog/appsec/instrumentation/gateway/argument.rb +4 -2
- data/lib/datadog/appsec/monitor/gateway/watcher.rb +8 -3
- data/lib/datadog/appsec/security_engine/runner.rb +2 -2
- data/lib/datadog/appsec/utils.rb +0 -2
- data/lib/datadog/core/configuration/components.rb +2 -1
- data/lib/datadog/core/configuration/ext.rb +4 -0
- data/lib/datadog/core/configuration/options.rb +2 -2
- data/lib/datadog/core/configuration/settings.rb +53 -30
- data/lib/datadog/core/environment/agent_info.rb +4 -3
- data/lib/datadog/core/metrics/client.rb +1 -1
- data/lib/datadog/core/remote/client.rb +1 -1
- data/lib/datadog/core/remote/component.rb +3 -6
- data/lib/datadog/core/remote/configuration/repository.rb +2 -1
- data/lib/datadog/core/remote/negotiation.rb +9 -9
- data/lib/datadog/core/remote/transport/config.rb +4 -3
- data/lib/datadog/core/remote/transport/http/client.rb +4 -3
- data/lib/datadog/core/remote/transport/http/config.rb +6 -32
- data/lib/datadog/core/remote/transport/http/negotiation.rb +6 -32
- data/lib/datadog/core/remote/transport/http.rb +22 -57
- data/lib/datadog/core/remote/transport/negotiation.rb +4 -3
- data/lib/datadog/core/runtime/metrics.rb +8 -1
- data/lib/datadog/core/telemetry/http/adapters/net.rb +1 -1
- data/lib/datadog/core/transport/http/api/instance.rb +17 -0
- data/lib/datadog/core/transport/http/api/spec.rb +17 -0
- data/lib/datadog/core/transport/http/builder.rb +5 -3
- data/lib/datadog/core/transport/http.rb +39 -2
- data/lib/datadog/di/component.rb +0 -2
- data/lib/datadog/di/probe_notifier_worker.rb +16 -16
- data/lib/datadog/di/transport/diagnostics.rb +4 -3
- data/lib/datadog/di/transport/http/api.rb +2 -12
- data/lib/datadog/di/transport/http/client.rb +4 -3
- data/lib/datadog/di/transport/http/diagnostics.rb +7 -33
- data/lib/datadog/di/transport/http/input.rb +7 -33
- data/lib/datadog/di/transport/http.rb +14 -56
- data/lib/datadog/di/transport/input.rb +4 -3
- data/lib/datadog/di/utils.rb +5 -0
- data/lib/datadog/kit/appsec/events.rb +12 -0
- data/lib/datadog/kit/identity.rb +5 -1
- data/lib/datadog/opentelemetry/api/baggage.rb +90 -0
- data/lib/datadog/opentelemetry/api/baggage.rbs +26 -0
- data/lib/datadog/opentelemetry/api/context.rb +16 -2
- data/lib/datadog/opentelemetry/sdk/trace/span.rb +1 -1
- data/lib/datadog/opentelemetry.rb +2 -1
- data/lib/datadog/profiling/collectors/thread_context.rb +1 -1
- data/lib/datadog/profiling.rb +5 -2
- data/lib/datadog/tracing/component.rb +15 -12
- data/lib/datadog/tracing/configuration/ext.rb +7 -1
- data/lib/datadog/tracing/configuration/settings.rb +18 -2
- data/lib/datadog/tracing/context_provider.rb +1 -1
- data/lib/datadog/tracing/contrib/configuration/settings.rb +1 -1
- data/lib/datadog/tracing/contrib/ethon/easy_patch.rb +4 -5
- data/lib/datadog/tracing/contrib/excon/middleware.rb +5 -3
- data/lib/datadog/tracing/contrib/ext.rb +1 -0
- data/lib/datadog/tracing/contrib/faraday/middleware.rb +5 -3
- data/lib/datadog/tracing/contrib/grpc/datadog_interceptor/client.rb +7 -1
- data/lib/datadog/tracing/contrib/grpc/distributed/propagation.rb +3 -0
- data/lib/datadog/tracing/contrib/http/circuit_breaker.rb +0 -15
- data/lib/datadog/tracing/contrib/http/distributed/propagation.rb +4 -1
- data/lib/datadog/tracing/contrib/http/instrumentation.rb +5 -5
- data/lib/datadog/tracing/contrib/httpclient/instrumentation.rb +5 -11
- data/lib/datadog/tracing/contrib/httprb/instrumentation.rb +6 -10
- data/lib/datadog/tracing/contrib/karafka/configuration/settings.rb +27 -0
- data/lib/datadog/tracing/contrib/karafka/distributed/propagation.rb +46 -0
- data/lib/datadog/tracing/contrib/karafka/ext.rb +27 -0
- data/lib/datadog/tracing/contrib/karafka/integration.rb +45 -0
- data/lib/datadog/tracing/contrib/karafka/monitor.rb +66 -0
- data/lib/datadog/tracing/contrib/karafka/patcher.rb +71 -0
- data/lib/datadog/tracing/contrib/karafka.rb +37 -0
- data/lib/datadog/tracing/contrib/rest_client/request_patch.rb +5 -3
- data/lib/datadog/tracing/contrib/sidekiq/client_tracer.rb +6 -1
- data/lib/datadog/tracing/contrib/sidekiq/distributed/propagation.rb +3 -0
- data/lib/datadog/tracing/contrib.rb +1 -0
- data/lib/datadog/tracing/correlation.rb +9 -2
- data/lib/datadog/tracing/distributed/baggage.rb +131 -0
- data/lib/datadog/tracing/distributed/datadog.rb +2 -0
- data/lib/datadog/tracing/distributed/propagation.rb +25 -4
- data/lib/datadog/tracing/distributed/propagation_policy.rb +42 -0
- data/lib/datadog/tracing/metadata/ext.rb +5 -0
- data/lib/datadog/tracing/sampling/span/rule.rb +0 -1
- data/lib/datadog/tracing/span_operation.rb +2 -1
- data/lib/datadog/tracing/sync_writer.rb +1 -2
- data/lib/datadog/tracing/trace_digest.rb +9 -2
- data/lib/datadog/tracing/trace_operation.rb +29 -17
- data/lib/datadog/tracing/trace_segment.rb +6 -4
- data/lib/datadog/tracing/tracer.rb +38 -2
- data/lib/datadog/tracing/transport/http/api.rb +2 -10
- data/lib/datadog/tracing/transport/http/client.rb +5 -4
- data/lib/datadog/tracing/transport/http/traces.rb +13 -41
- data/lib/datadog/tracing/transport/http.rb +11 -44
- data/lib/datadog/tracing/transport/trace_formatter.rb +7 -0
- data/lib/datadog/tracing/transport/traces.rb +26 -9
- data/lib/datadog/tracing/workers/trace_writer.rb +2 -6
- data/lib/datadog/tracing/writer.rb +2 -6
- data/lib/datadog/tracing.rb +16 -3
- data/lib/datadog/version.rb +2 -2
- data/lib/datadog.rb +1 -1
- metadata +24 -13
- data/lib/datadog/appsec/contrib/devise/event.rb +0 -54
- data/lib/datadog/appsec/contrib/devise/patcher/authenticatable_patch.rb +0 -72
- data/lib/datadog/appsec/contrib/devise/patcher/registration_controller_patch.rb +0 -47
- data/lib/datadog/appsec/contrib/devise/resource.rb +0 -35
- data/lib/datadog/appsec/contrib/devise/tracking.rb +0 -57
- data/lib/datadog/appsec/utils/trace_operation.rb +0 -15
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
require_relative '../../../distributed/fetcher'
|
4
4
|
require_relative '../../../distributed/propagation'
|
5
|
+
require_relative '../../../distributed/propagation_policy'
|
5
6
|
require_relative '../../../distributed/b3_multi'
|
6
7
|
require_relative '../../../distributed/b3_single'
|
7
8
|
require_relative '../../../distributed/datadog'
|
@@ -31,6 +32,8 @@ module Datadog
|
|
31
32
|
Tracing::Distributed::Datadog.new(fetcher: Tracing::Distributed::Fetcher),
|
32
33
|
Tracing::Configuration::Ext::Distributed::PROPAGATION_STYLE_TRACE_CONTEXT =>
|
33
34
|
Tracing::Distributed::TraceContext.new(fetcher: Tracing::Distributed::Fetcher),
|
35
|
+
Tracing::Configuration::Ext::Distributed::PROPAGATION_STYLE_BAGGAGE =>
|
36
|
+
Tracing::Distributed::Baggage.new(fetcher: Tracing::Distributed::Fetcher),
|
34
37
|
Tracing::Configuration::Ext::Distributed::PROPAGATION_STYLE_NONE => Tracing::Distributed::None.new
|
35
38
|
},
|
36
39
|
propagation_style_inject: propagation_style_inject,
|
@@ -55,6 +55,7 @@ require_relative 'contrib/httpclient/integration'
|
|
55
55
|
require_relative 'contrib/httprb/integration'
|
56
56
|
require_relative 'contrib/integration'
|
57
57
|
require_relative 'contrib/kafka/integration'
|
58
|
+
require_relative 'contrib/karafka'
|
58
59
|
require_relative 'contrib/lograge/integration'
|
59
60
|
require_relative 'contrib/mongodb/integration'
|
60
61
|
require_relative 'contrib/mysql2/integration'
|
@@ -94,8 +94,15 @@ module Datadog
|
|
94
94
|
end
|
95
95
|
|
96
96
|
def format_trace_id(trace_id)
|
97
|
-
if Datadog.configuration.tracing.trace_id_128_bit_logging_enabled
|
98
|
-
|
97
|
+
if Datadog.configuration.tracing.trace_id_128_bit_logging_enabled
|
98
|
+
format_trace_id_128(trace_id)
|
99
|
+
else
|
100
|
+
Tracing::Utils::TraceId.to_low_order(trace_id).to_s
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def format_trace_id_128(trace_id)
|
105
|
+
if !Tracing::Utils::TraceId.to_high_order(trace_id).zero?
|
99
106
|
Kernel.format('%032x', trace_id)
|
100
107
|
else
|
101
108
|
Tracing::Utils::TraceId.to_low_order(trace_id).to_s
|
@@ -0,0 +1,131 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../metadata/ext'
|
4
|
+
require_relative '../trace_digest'
|
5
|
+
require_relative 'datadog_tags_codec'
|
6
|
+
require_relative '../utils'
|
7
|
+
require_relative 'helpers'
|
8
|
+
require 'uri'
|
9
|
+
|
10
|
+
module Datadog
|
11
|
+
module Tracing
|
12
|
+
module Distributed
|
13
|
+
# W3C Baggage propagator implementation.
|
14
|
+
# The baggage header is propagated through `baggage`.
|
15
|
+
# @see https://www.w3.org/TR/baggage/
|
16
|
+
class Baggage
|
17
|
+
BAGGAGE_KEY = 'baggage'
|
18
|
+
DD_TRACE_BAGGAGE_MAX_ITEMS = 64
|
19
|
+
DD_TRACE_BAGGAGE_MAX_BYTES = 8192
|
20
|
+
SAFE_CHARACTERS_KEY = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789$!#&'*+-.^_`|~"
|
21
|
+
SAFE_CHARACTERS_VALUE = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789$!#&'()*+-./:<>?@[]^_`{|}~"
|
22
|
+
|
23
|
+
def initialize(
|
24
|
+
fetcher:,
|
25
|
+
baggage_key: BAGGAGE_KEY
|
26
|
+
)
|
27
|
+
@baggage_key = baggage_key
|
28
|
+
@fetcher = fetcher
|
29
|
+
end
|
30
|
+
|
31
|
+
def inject!(digest, data)
|
32
|
+
return if digest.nil? || digest.baggage.nil?
|
33
|
+
|
34
|
+
baggage_items = digest.baggage.reject { |k, v| k.nil? || v.nil? }
|
35
|
+
return if baggage_items.empty?
|
36
|
+
|
37
|
+
begin
|
38
|
+
if baggage_items.size > DD_TRACE_BAGGAGE_MAX_ITEMS
|
39
|
+
::Datadog.logger.warn('Baggage item limit exceeded, dropping excess items')
|
40
|
+
baggage_items = baggage_items.first(DD_TRACE_BAGGAGE_MAX_ITEMS)
|
41
|
+
end
|
42
|
+
|
43
|
+
encoded_items = []
|
44
|
+
total_size = 0
|
45
|
+
|
46
|
+
baggage_items.each do |key, value|
|
47
|
+
item = "#{encode_item(key, SAFE_CHARACTERS_KEY)}=#{encode_item(value, SAFE_CHARACTERS_VALUE)}"
|
48
|
+
item_size = item.bytesize + (encoded_items.empty? ? 0 : 1) # +1 for comma if not first item
|
49
|
+
if total_size + item_size > DD_TRACE_BAGGAGE_MAX_BYTES
|
50
|
+
::Datadog.logger.warn('Baggage header size exceeded, dropping excess items')
|
51
|
+
break # stop adding items when size limit is reached
|
52
|
+
end
|
53
|
+
encoded_items << item
|
54
|
+
total_size += item_size
|
55
|
+
end
|
56
|
+
|
57
|
+
# edge case where a single item is too large
|
58
|
+
return if encoded_items.empty?
|
59
|
+
|
60
|
+
header_value = encoded_items.join(',')
|
61
|
+
data[@baggage_key] = header_value
|
62
|
+
rescue => e
|
63
|
+
::Datadog.logger.warn("Failed to encode and inject baggage header: #{e.message}")
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def extract(data)
|
68
|
+
fetcher = @fetcher.new(data)
|
69
|
+
data = fetcher[@baggage_key]
|
70
|
+
return unless data
|
71
|
+
|
72
|
+
baggage = parse_baggage_header(fetcher[@baggage_key])
|
73
|
+
return unless baggage
|
74
|
+
|
75
|
+
TraceDigest.new(
|
76
|
+
baggage: baggage,
|
77
|
+
)
|
78
|
+
end
|
79
|
+
|
80
|
+
private
|
81
|
+
|
82
|
+
def encode_item(item, safe_characters)
|
83
|
+
# Strip whitespace and URL-encode the item
|
84
|
+
result = URI.encode_www_form_component(item.strip)
|
85
|
+
# Replace '+' with '%20' for space encoding consistency with W3C spec
|
86
|
+
result = result.gsub('+', '%20')
|
87
|
+
# Selectively decode percent-encoded characters that are considered "safe" in W3C Baggage spec
|
88
|
+
result.gsub(/%[0-9A-F]{2}/) do |encoded|
|
89
|
+
if encoded.size >= 3 && encoded[1..2] =~ /\A[0-9A-F]{2}\z/
|
90
|
+
hex_str = encoded[1..2]
|
91
|
+
next encoded unless hex_str && !hex_str.empty?
|
92
|
+
|
93
|
+
# Convert hex representation back to character
|
94
|
+
char = [hex_str.hex].pack('C')
|
95
|
+
# Keep the character as-is if it's in the safe character set, otherwise keep it encoded
|
96
|
+
safe_characters.include?(char) ? char : encoded
|
97
|
+
else
|
98
|
+
encoded
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
# Parses a W3C Baggage header string into a hash of key-value pairs
|
104
|
+
# The header format follows the W3C Baggage specification:
|
105
|
+
# - Multiple baggage items are separated by commas
|
106
|
+
# - Each baggage item is a key-value pair separated by '='
|
107
|
+
# - Keys and values are URL-encoded
|
108
|
+
# - Returns an empty hash if the baggage header is malformed
|
109
|
+
#
|
110
|
+
# @param baggage_header [String] The W3C Baggage header string to parse
|
111
|
+
# @return [Hash<String, String>] A hash of decoded baggage items
|
112
|
+
def parse_baggage_header(baggage_header)
|
113
|
+
baggage = {}
|
114
|
+
baggages = baggage_header.split(',')
|
115
|
+
baggages.each do |key_value|
|
116
|
+
key, value = key_value.split('=', 2)
|
117
|
+
# If baggage is malformed, return an empty hash
|
118
|
+
return {} unless key && value
|
119
|
+
|
120
|
+
key = URI.decode_www_form_component(key.strip)
|
121
|
+
value = URI.decode_www_form_component(value.strip)
|
122
|
+
return {} if key.empty? || value.empty?
|
123
|
+
|
124
|
+
baggage[key] = value
|
125
|
+
end
|
126
|
+
baggage
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
@@ -116,6 +116,8 @@ module Datadog
|
|
116
116
|
def extract_trace_id!(trace_id, tags)
|
117
117
|
return trace_id unless tags
|
118
118
|
return trace_id unless (high_order = tags.delete(Tracing::Metadata::Ext::Distributed::TAG_TID))
|
119
|
+
return trace_id unless high_order.size == 16
|
120
|
+
return trace_id unless /\A[0-9a-f]+\z/i.match?(high_order)
|
119
121
|
|
120
122
|
Tracing::Utils::TraceId.concatenate(high_order.to_i(16), trace_id)
|
121
123
|
end
|
@@ -4,6 +4,7 @@ require_relative '../configuration/ext'
|
|
4
4
|
require_relative '../trace_digest'
|
5
5
|
require_relative '../trace_operation'
|
6
6
|
require_relative '../../core/telemetry/logger'
|
7
|
+
require_relative 'baggage'
|
7
8
|
|
8
9
|
module Datadog
|
9
10
|
module Tracing
|
@@ -26,9 +27,13 @@ module Datadog
|
|
26
27
|
)
|
27
28
|
@propagation_styles = propagation_styles
|
28
29
|
@propagation_extract_first = propagation_extract_first
|
29
|
-
|
30
30
|
@propagation_style_inject = propagation_style_inject.map { |style| propagation_styles[style] }
|
31
31
|
@propagation_style_extract = propagation_style_extract.map { |style| propagation_styles[style] }
|
32
|
+
|
33
|
+
# The baggage propagator is unique in that baggage should always be extracted, if present.
|
34
|
+
# Therefore we remove it from the `propagation_style_extract` list.
|
35
|
+
@baggage_propagator = @propagation_style_extract.find { |propagator| propagator.is_a?(Baggage) }
|
36
|
+
@propagation_style_extract.delete(@baggage_propagator) if @baggage_propagator
|
32
37
|
end
|
33
38
|
|
34
39
|
# inject! populates the env with span ID, trace ID and sampling priority
|
@@ -57,9 +62,8 @@ module Datadog
|
|
57
62
|
end
|
58
63
|
|
59
64
|
digest = digest.to_digest if digest.respond_to?(:to_digest)
|
60
|
-
|
61
|
-
|
62
|
-
::Datadog.logger.debug('Cannot inject distributed trace data: digest.trace_id is nil.')
|
65
|
+
if digest.trace_id.nil? && digest.baggage.nil?
|
66
|
+
::Datadog.logger.debug('Cannot inject distributed trace data: digest.trace_id and digest.baggage are both nil.')
|
63
67
|
return nil
|
64
68
|
end
|
65
69
|
|
@@ -138,12 +142,29 @@ module Datadog
|
|
138
142
|
"Error extracting distributed trace data. Cause: #{e} Location: #{Array(e.backtrace).first}"
|
139
143
|
)
|
140
144
|
end
|
145
|
+
# Handle baggage after all other styles if present
|
146
|
+
extracted_trace_digest = propagate_baggage(data, extracted_trace_digest) if @baggage_propagator
|
141
147
|
|
142
148
|
extracted_trace_digest
|
143
149
|
end
|
144
150
|
|
145
151
|
private
|
146
152
|
|
153
|
+
def propagate_baggage(data, extracted_trace_digest)
|
154
|
+
if extracted_trace_digest
|
155
|
+
# Merge with baggage if present
|
156
|
+
digest = @baggage_propagator.extract(data)
|
157
|
+
if digest
|
158
|
+
extracted_trace_digest.merge(baggage: digest.baggage)
|
159
|
+
else
|
160
|
+
extracted_trace_digest
|
161
|
+
end
|
162
|
+
else
|
163
|
+
# Baggage is the only style
|
164
|
+
@baggage_propagator.extract(data)
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
147
168
|
def last_datadog_parent_id(headers, tracecontext_tags)
|
148
169
|
dd_propagator = @propagation_style_extract.find { |propagator| propagator.is_a?(Datadog) }
|
149
170
|
if tracecontext_tags&.fetch(
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Datadog
|
4
|
+
module Tracing
|
5
|
+
module Distributed
|
6
|
+
# Helper method to decide when to skip distributed tracing
|
7
|
+
module PropagationPolicy
|
8
|
+
module_function
|
9
|
+
|
10
|
+
# Skips distributed tracing if disabled for this instrumentation
|
11
|
+
# or if APM is disabled unless there is an AppSec event (from upstream distributed trace or local)
|
12
|
+
#
|
13
|
+
# Both pin_config and global_config are configuration for integrations.
|
14
|
+
# pin_config is a Datadog::Core::Pin object, which gives the configuration of a single instance of an integration.
|
15
|
+
# global_config is the config for all instances of an integration.
|
16
|
+
def enabled?(pin_config: nil, global_config: nil, trace: nil)
|
17
|
+
return false unless Tracing.enabled?
|
18
|
+
|
19
|
+
unless ::Datadog.configuration.apm.tracing.enabled
|
20
|
+
return false if trace.nil?
|
21
|
+
|
22
|
+
trace_source = trace.get_tag(::Datadog::Tracing::Metadata::Ext::Distributed::TAG_TRACE_SOURCE)&.to_i(16)
|
23
|
+
return false if trace_source.nil?
|
24
|
+
|
25
|
+
# If AppSec is enabled and AppSec bit is set in the trace, we should not skip distributed tracing
|
26
|
+
# Other products that will use dd.p.ts should implement similar behavior here
|
27
|
+
if ::Datadog.configuration.appsec.enabled && (trace_source & ::Datadog::AppSec::Ext::PRODUCT_BIT) != 0
|
28
|
+
return true
|
29
|
+
end
|
30
|
+
|
31
|
+
return false
|
32
|
+
end
|
33
|
+
|
34
|
+
return pin_config[:distributed_tracing] if pin_config && pin_config.key?(:distributed_tracing)
|
35
|
+
return global_config[:distributed_tracing] if global_config
|
36
|
+
|
37
|
+
true
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -31,6 +31,8 @@ module Datadog
|
|
31
31
|
# See Datadog-internal "RFC: Identifying which spans have profiling enabled " for details
|
32
32
|
TAG_PROFILING_ENABLED = '_dd.profiling.enabled'
|
33
33
|
|
34
|
+
TAG_APM_ENABLED = '_dd.apm.enabled'
|
35
|
+
|
34
36
|
# Defines constants for trace analytics
|
35
37
|
# @public_api
|
36
38
|
module Analytics
|
@@ -55,6 +57,9 @@ module Datadog
|
|
55
57
|
# @see Datadog::Tracing::Sampling::Ext::Mechanism
|
56
58
|
TAG_DECISION_MAKER = '_dd.p.dm'
|
57
59
|
|
60
|
+
# Bitmask for which product generated an event. E.g.: 2 for an AppSec event.
|
61
|
+
TAG_TRACE_SOURCE = '_dd.p.ts'
|
62
|
+
|
58
63
|
TAG_ORIGIN = '_dd.origin'
|
59
64
|
TAG_SAMPLING_PRIORITY = '_sampling_priority_v1'
|
60
65
|
|
@@ -269,7 +269,8 @@ module Datadog
|
|
269
269
|
|
270
270
|
def duration
|
271
271
|
return @duration_end - @duration_start if @duration_start && @duration_end
|
272
|
-
|
272
|
+
|
273
|
+
@end_time - @start_time if @start_time && @end_time
|
273
274
|
end
|
274
275
|
|
275
276
|
def set_error(e)
|
@@ -32,8 +32,7 @@ module Datadog
|
|
32
32
|
@agent_settings = agent_settings
|
33
33
|
|
34
34
|
@transport = transport || begin
|
35
|
-
|
36
|
-
Transport::HTTP.default(**transport_options)
|
35
|
+
Transport::HTTP.default(agent_settings: agent_settings, logger: logger, **transport_options)
|
37
36
|
end
|
38
37
|
|
39
38
|
@events = Writer::Events.new
|
@@ -80,6 +80,9 @@ module Datadog
|
|
80
80
|
# This allows later propagation to include those unknown fields, as they can represent future versions of the spec
|
81
81
|
# sending data through this service. This value ends in a trailing `;` to facilitate serialization.
|
82
82
|
# @return [String]
|
83
|
+
# @!attribute [r] baggage
|
84
|
+
# The W3C "baggage" extracted from a distributed context. This field is a hash of key/value pairs.
|
85
|
+
# @return [Hash<String,String>]
|
83
86
|
# TODO: The documentation for the last attribute above won't be rendered.
|
84
87
|
# TODO: This might be a YARD bug as adding an attribute, making it now second-last attribute, renders correctly.
|
85
88
|
attr_reader \
|
@@ -102,7 +105,8 @@ module Datadog
|
|
102
105
|
:trace_flags,
|
103
106
|
:trace_state,
|
104
107
|
:trace_state_unknown_fields,
|
105
|
-
:span_remote
|
108
|
+
:span_remote,
|
109
|
+
:baggage
|
106
110
|
|
107
111
|
def initialize(
|
108
112
|
span_id: nil,
|
@@ -124,7 +128,8 @@ module Datadog
|
|
124
128
|
trace_flags: nil,
|
125
129
|
trace_state: nil,
|
126
130
|
trace_state_unknown_fields: nil,
|
127
|
-
span_remote: true
|
131
|
+
span_remote: true,
|
132
|
+
baggage: nil
|
128
133
|
)
|
129
134
|
@span_id = span_id
|
130
135
|
@span_name = span_name && span_name.dup.freeze
|
@@ -146,6 +151,7 @@ module Datadog
|
|
146
151
|
@trace_state = trace_state && trace_state.dup.freeze
|
147
152
|
@trace_state_unknown_fields = trace_state_unknown_fields && trace_state_unknown_fields.dup.freeze
|
148
153
|
@span_remote = span_remote
|
154
|
+
@baggage = baggage && baggage.dup.freeze
|
149
155
|
freeze
|
150
156
|
end
|
151
157
|
|
@@ -177,6 +183,7 @@ module Datadog
|
|
177
183
|
trace_state: trace_state,
|
178
184
|
trace_state_unknown_fields: trace_state_unknown_fields,
|
179
185
|
span_remote: span_remote,
|
186
|
+
baggage: baggage
|
180
187
|
}.merge!(field_value_pairs)
|
181
188
|
)
|
182
189
|
end
|
@@ -2,7 +2,6 @@
|
|
2
2
|
|
3
3
|
require_relative '../core/environment/identity'
|
4
4
|
require_relative '../core/utils'
|
5
|
-
require_relative 'tracer'
|
6
5
|
require_relative 'event'
|
7
6
|
require_relative 'metadata/tagging'
|
8
7
|
require_relative 'sampling/ext'
|
@@ -37,7 +36,8 @@ module Datadog
|
|
37
36
|
:rule_sample_rate,
|
38
37
|
:sample_rate,
|
39
38
|
:sampling_priority,
|
40
|
-
:remote_parent
|
39
|
+
:remote_parent,
|
40
|
+
:baggage
|
41
41
|
|
42
42
|
attr_reader \
|
43
43
|
:active_span_count,
|
@@ -71,19 +71,21 @@ module Datadog
|
|
71
71
|
sampling_priority: nil,
|
72
72
|
service: nil,
|
73
73
|
profiling_enabled: nil,
|
74
|
+
apm_tracing_enabled: nil,
|
74
75
|
tags: nil,
|
75
76
|
metrics: nil,
|
76
77
|
trace_state: nil,
|
77
78
|
trace_state_unknown_fields: nil,
|
78
79
|
remote_parent: false,
|
79
|
-
tracer: nil
|
80
|
+
tracer: nil,
|
81
|
+
baggage: nil
|
80
82
|
|
81
83
|
)
|
82
84
|
# Attributes
|
83
85
|
@id = id || Tracing::Utils::TraceId.next_id
|
84
86
|
@max_length = max_length || DEFAULT_MAX_LENGTH
|
85
87
|
@parent_span_id = parent_span_id
|
86
|
-
@sampled = sampled.nil?
|
88
|
+
@sampled = sampled.nil? || sampled
|
87
89
|
@remote_parent = remote_parent
|
88
90
|
|
89
91
|
# Tags
|
@@ -98,9 +100,11 @@ module Datadog
|
|
98
100
|
@sampling_priority = sampling_priority
|
99
101
|
@service = service
|
100
102
|
@profiling_enabled = profiling_enabled
|
103
|
+
@apm_tracing_enabled = apm_tracing_enabled
|
101
104
|
@trace_state = trace_state
|
102
105
|
@trace_state_unknown_fields = trace_state_unknown_fields
|
103
106
|
@tracer = tracer
|
107
|
+
@baggage = baggage
|
104
108
|
|
105
109
|
# Generic tags
|
106
110
|
set_tags(tags) if tags
|
@@ -173,6 +177,12 @@ module Datadog
|
|
173
177
|
super || (root_span && root_span.get_metric(key))
|
174
178
|
end
|
175
179
|
|
180
|
+
def set_distributed_source(product_bit)
|
181
|
+
source = get_tag(Metadata::Ext::Distributed::TAG_TRACE_SOURCE)&.to_i(16) || 0
|
182
|
+
source |= product_bit
|
183
|
+
set_tag(Metadata::Ext::Distributed::TAG_TRACE_SOURCE, format('%02X', source))
|
184
|
+
end
|
185
|
+
|
176
186
|
def tags
|
177
187
|
all_tags = {}
|
178
188
|
all_tags.merge!(root_span&.tags || {}) if root_span
|
@@ -315,10 +325,10 @@ module Datadog
|
|
315
325
|
|
316
326
|
TraceDigest.new(
|
317
327
|
span_id: span_id,
|
318
|
-
span_name:
|
319
|
-
span_resource:
|
320
|
-
span_service:
|
321
|
-
span_type:
|
328
|
+
span_name: @active_span && @active_span.name,
|
329
|
+
span_resource: @active_span && @active_span.resource,
|
330
|
+
span_service: @active_span && @active_span.service,
|
331
|
+
span_type: @active_span && @active_span.type,
|
322
332
|
trace_distributed_tags: distributed_tags,
|
323
333
|
trace_hostname: @hostname,
|
324
334
|
trace_id: @id,
|
@@ -331,7 +341,8 @@ module Datadog
|
|
331
341
|
trace_service: service,
|
332
342
|
trace_state: @trace_state,
|
333
343
|
trace_state_unknown_fields: @trace_state_unknown_fields,
|
334
|
-
span_remote:
|
344
|
+
span_remote: @remote_parent && @active_span.nil?,
|
345
|
+
baggage: @baggage.nil? || @baggage.empty? ? nil : @baggage
|
335
346
|
).freeze
|
336
347
|
end
|
337
348
|
|
@@ -351,22 +362,22 @@ module Datadog
|
|
351
362
|
def fork_clone
|
352
363
|
self.class.new(
|
353
364
|
agent_sample_rate: @agent_sample_rate,
|
354
|
-
events:
|
355
|
-
hostname:
|
365
|
+
events: @events && @events.dup,
|
366
|
+
hostname: @hostname && @hostname.dup,
|
356
367
|
id: @id,
|
357
368
|
max_length: @max_length,
|
358
|
-
name:
|
359
|
-
origin:
|
369
|
+
name: name && name.dup,
|
370
|
+
origin: @origin && @origin.dup,
|
360
371
|
parent_span_id: (@active_span && @active_span.id) || @parent_span_id,
|
361
372
|
rate_limiter_rate: @rate_limiter_rate,
|
362
|
-
resource:
|
373
|
+
resource: resource && resource.dup,
|
363
374
|
rule_sample_rate: @rule_sample_rate,
|
364
375
|
sample_rate: @sample_rate,
|
365
376
|
sampled: @sampled,
|
366
377
|
sampling_priority: @sampling_priority,
|
367
|
-
service:
|
368
|
-
trace_state:
|
369
|
-
trace_state_unknown_fields:
|
378
|
+
service: service && service.dup,
|
379
|
+
trace_state: @trace_state && @trace_state.dup,
|
380
|
+
trace_state_unknown_fields: @trace_state_unknown_fields && @trace_state_unknown_fields.dup,
|
370
381
|
tags: meta.dup,
|
371
382
|
metrics: metrics.dup,
|
372
383
|
remote_parent: @remote_parent
|
@@ -510,6 +521,7 @@ module Datadog
|
|
510
521
|
metrics: metrics,
|
511
522
|
root_span_id: !partial ? root_span && root_span.id : nil,
|
512
523
|
profiling_enabled: @profiling_enabled,
|
524
|
+
apm_tracing_enabled: @apm_tracing_enabled
|
513
525
|
)
|
514
526
|
end
|
515
527
|
|
@@ -34,7 +34,8 @@ module Datadog
|
|
34
34
|
:sampling_decision_maker,
|
35
35
|
:sampling_priority,
|
36
36
|
:service,
|
37
|
-
:profiling_enabled
|
37
|
+
:profiling_enabled,
|
38
|
+
:apm_tracing_enabled
|
38
39
|
|
39
40
|
# rubocop:disable Metrics/CyclomaticComplexity
|
40
41
|
# rubocop:disable Metrics/PerceivedComplexity
|
@@ -58,7 +59,8 @@ module Datadog
|
|
58
59
|
service: nil,
|
59
60
|
tags: nil,
|
60
61
|
metrics: nil,
|
61
|
-
profiling_enabled: nil
|
62
|
+
profiling_enabled: nil,
|
63
|
+
apm_tracing_enabled: nil
|
62
64
|
)
|
63
65
|
@id = id
|
64
66
|
@root_span_id = root_span_id
|
@@ -85,6 +87,7 @@ module Datadog
|
|
85
87
|
@sampling_priority = sampling_priority || sampling_priority_tag
|
86
88
|
@service = Core::Utils::SafeDup.frozen_or_dup(service || service_tag)
|
87
89
|
@profiling_enabled = profiling_enabled
|
90
|
+
@apm_tracing_enabled = apm_tracing_enabled
|
88
91
|
end
|
89
92
|
# rubocop:enable Metrics/PerceivedComplexity
|
90
93
|
# rubocop:enable Metrics/CyclomaticComplexity
|
@@ -128,8 +131,7 @@ module Datadog
|
|
128
131
|
end
|
129
132
|
|
130
133
|
def sampled?
|
131
|
-
|
132
|
-
|| sampling_priority == Sampling::Ext::Priority::USER_KEEP
|
134
|
+
[Sampling::Ext::Priority::AUTO_KEEP, Sampling::Ext::Priority::USER_KEEP].include?(sampling_priority)
|
133
135
|
end
|
134
136
|
|
135
137
|
# Returns the high order part of the trace id as a hexadecimal string; the most significant 64 bits.
|
@@ -338,24 +338,30 @@ module Datadog
|
|
338
338
|
hostname = hostname && !hostname.empty? ? hostname : nil
|
339
339
|
|
340
340
|
if digest
|
341
|
+
sampling_priority = if propagate_sampling_priority?(upstream_tags: digest.trace_distributed_tags)
|
342
|
+
digest.trace_sampling_priority
|
343
|
+
end
|
341
344
|
TraceOperation.new(
|
342
345
|
hostname: hostname,
|
343
346
|
profiling_enabled: profiling_enabled,
|
347
|
+
apm_tracing_enabled: apm_tracing_enabled,
|
344
348
|
id: digest.trace_id,
|
345
349
|
origin: digest.trace_origin,
|
346
350
|
parent_span_id: digest.span_id,
|
347
|
-
sampling_priority:
|
351
|
+
sampling_priority: sampling_priority,
|
348
352
|
# Distributed tags are just regular trace tags with special meaning to Datadog
|
349
353
|
tags: digest.trace_distributed_tags,
|
350
354
|
trace_state: digest.trace_state,
|
351
355
|
trace_state_unknown_fields: digest.trace_state_unknown_fields,
|
352
356
|
remote_parent: digest.span_remote,
|
353
|
-
tracer: self
|
357
|
+
tracer: self,
|
358
|
+
baggage: digest.baggage
|
354
359
|
)
|
355
360
|
else
|
356
361
|
TraceOperation.new(
|
357
362
|
hostname: hostname,
|
358
363
|
profiling_enabled: profiling_enabled,
|
364
|
+
apm_tracing_enabled: apm_tracing_enabled,
|
359
365
|
remote_parent: false,
|
360
366
|
tracer: self
|
361
367
|
)
|
@@ -545,10 +551,40 @@ module Datadog
|
|
545
551
|
end
|
546
552
|
end
|
547
553
|
|
554
|
+
# Decide whether upstream sampling priority should be propagated, by taking into account
|
555
|
+
# the upstream tags and the configuration.
|
556
|
+
# We should always propagate if APM is enabled.
|
557
|
+
#
|
558
|
+
# e.g.: upstream tags containing dd.p.ts: 02, and appsec is enabled, return true.
|
559
|
+
def propagate_sampling_priority?(upstream_tags:)
|
560
|
+
return true if apm_tracing_enabled
|
561
|
+
|
562
|
+
if upstream_tags&.key?(Tracing::Metadata::Ext::Distributed::TAG_TRACE_SOURCE)
|
563
|
+
appsec_bit = upstream_tags[Tracing::Metadata::Ext::Distributed::TAG_TRACE_SOURCE].to_i(16) &
|
564
|
+
Datadog::AppSec::Ext::PRODUCT_BIT
|
565
|
+
return appsec_enabled if appsec_bit != 0
|
566
|
+
end
|
567
|
+
|
568
|
+
false
|
569
|
+
end
|
570
|
+
|
548
571
|
def profiling_enabled
|
549
572
|
@profiling_enabled ||=
|
550
573
|
!!(defined?(Datadog::Profiling) && Datadog::Profiling.respond_to?(:enabled?) && Datadog::Profiling.enabled?)
|
551
574
|
end
|
575
|
+
|
576
|
+
def appsec_enabled
|
577
|
+
@appsec_enabled ||= Datadog.configuration.appsec.enabled
|
578
|
+
end
|
579
|
+
|
580
|
+
# Due to APM Tracing (the product) and Tracing (the transport) being intertwined, we cannot completely disabled APM
|
581
|
+
# without also disabling the tracer. When setting `@apm_tracing_enabled` to `false`, it does not disable the tracer,
|
582
|
+
# but rather only sends heartbeat traces (1 per minutes), so that the service is considered alive in the backend.
|
583
|
+
# Other products (like ASM) can then set the sampling priority of their traces to `MANUAL_KEEP`,
|
584
|
+
# effectively allowing standalone products to work without APM.
|
585
|
+
def apm_tracing_enabled
|
586
|
+
@apm_tracing_enabled ||= Datadog.configuration.apm.tracing.enabled
|
587
|
+
end
|
552
588
|
end
|
553
589
|
end
|
554
590
|
end
|
@@ -22,14 +22,14 @@ module Datadog
|
|
22
22
|
|
23
23
|
def defaults
|
24
24
|
Core::Transport::HTTP::API::Map[
|
25
|
-
V4 => Spec.new do |s|
|
25
|
+
V4 => Traces::API::Spec.new do |s|
|
26
26
|
s.traces = Traces::API::Endpoint.new(
|
27
27
|
'/v0.4/traces',
|
28
28
|
Core::Encoding::MsgpackEncoder,
|
29
29
|
service_rates: true
|
30
30
|
)
|
31
31
|
end,
|
32
|
-
V3 => Spec.new do |s|
|
32
|
+
V3 => Traces::API::Spec.new do |s|
|
33
33
|
s.traces = Traces::API::Endpoint.new(
|
34
34
|
'/v0.3/traces',
|
35
35
|
Core::Encoding::MsgpackEncoder
|
@@ -37,14 +37,6 @@ module Datadog
|
|
37
37
|
end,
|
38
38
|
].with_fallbacks(V4 => V3)
|
39
39
|
end
|
40
|
-
|
41
|
-
class Instance < Core::Transport::HTTP::API::Instance
|
42
|
-
include Traces::API::Instance
|
43
|
-
end
|
44
|
-
|
45
|
-
class Spec < Core::Transport::HTTP::API::Spec
|
46
|
-
include Traces::API::Spec
|
47
|
-
end
|
48
40
|
end
|
49
41
|
end
|
50
42
|
end
|