datadog 2.12.1 → 2.13.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 +45 -2
- data/ext/datadog_profiling_native_extension/collectors_thread_context.c +14 -13
- data/ext/datadog_profiling_native_extension/private_vm_api_access.c +8 -0
- 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 +34 -0
- data/lib/datadog/appsec/contrib/rack/gateway/watcher.rb +27 -0
- data/lib/datadog/appsec/contrib/rack/request_middleware.rb +3 -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/instrumentation/gateway/middleware.rb +24 -0
- data/lib/datadog/appsec/instrumentation/gateway.rb +17 -22
- data/lib/datadog/appsec/monitor/gateway/watcher.rb +8 -3
- data/lib/datadog/appsec/processor/rule_merger.rb +2 -1
- data/lib/datadog/appsec/remote.rb +7 -0
- 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/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 +9 -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/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/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/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/metadata/metastruct.rb +36 -0
- data/lib/datadog/tracing/metadata/metastruct_tagging.rb +42 -0
- data/lib/datadog/tracing/metadata.rb +2 -0
- data/lib/datadog/tracing/sampling/span/rule.rb +0 -1
- data/lib/datadog/tracing/span.rb +10 -1
- data/lib/datadog/tracing/span_operation.rb +8 -2
- 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/serializable_trace.rb +3 -1
- data/lib/datadog/tracing/transport/trace_formatter.rb +7 -0
- data/lib/datadog/tracing/transport/traces.rb +21 -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
- metadata +20 -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
@@ -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
|
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'forwardable'
|
4
|
+
|
5
|
+
module Datadog
|
6
|
+
module Tracing
|
7
|
+
module Metadata
|
8
|
+
# This class is a data structure that is used to store
|
9
|
+
# complex metadata, such as an array of objects.
|
10
|
+
#
|
11
|
+
# It is serialized to MessagePack format when sent to the agent.
|
12
|
+
class Metastruct
|
13
|
+
extend Forwardable
|
14
|
+
|
15
|
+
def_delegators :@metastruct, :[], :[]=, :to_h
|
16
|
+
|
17
|
+
def initialize
|
18
|
+
@metastruct = {}
|
19
|
+
end
|
20
|
+
|
21
|
+
def to_msgpack(packer = nil)
|
22
|
+
# JRuby doesn't pass the packer
|
23
|
+
packer ||= MessagePack::Packer.new
|
24
|
+
|
25
|
+
packer.write(@metastruct.transform_values(&:to_msgpack))
|
26
|
+
end
|
27
|
+
|
28
|
+
def pretty_print(q)
|
29
|
+
q.seplist @metastruct.each do |key, value|
|
30
|
+
q.text "#{key} => #{value}"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'metastruct'
|
4
|
+
|
5
|
+
module Datadog
|
6
|
+
module Tracing
|
7
|
+
module Metadata
|
8
|
+
# Adds data storage for the `meta_struct` field.
|
9
|
+
#
|
10
|
+
# This field is used to send more complex data like an array of objects
|
11
|
+
# in MessagePack format to the agent, and has no size limitations.
|
12
|
+
#
|
13
|
+
# The agent fully supports meta_struct from version v7.35.0 (April 2022).
|
14
|
+
#
|
15
|
+
# On versions older than v7.35.0, sending traces containing meta_struct
|
16
|
+
# has no unexpected side-effects; traces are sent to the backend as expected,
|
17
|
+
# while the meta_struct field is stripped.
|
18
|
+
module MetastructTagging
|
19
|
+
# Set the given key / value tag pair on the metastruct.
|
20
|
+
#
|
21
|
+
# A valid example is:
|
22
|
+
#
|
23
|
+
# span.set_metastruct_tag('_dd.stack', [])
|
24
|
+
def set_metastruct_tag(key, value)
|
25
|
+
metastruct[key] = value
|
26
|
+
end
|
27
|
+
|
28
|
+
# Return the metastruct tag value for the given key,
|
29
|
+
# returns nil if the key doesn't exist.
|
30
|
+
def get_metastruct_tag(key)
|
31
|
+
metastruct[key]
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def metastruct
|
37
|
+
@metastruct ||= Metastruct.new
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
require_relative 'metadata/analytics'
|
4
4
|
require_relative 'metadata/tagging'
|
5
|
+
require_relative 'metadata/metastruct_tagging'
|
5
6
|
require_relative 'metadata/errors'
|
6
7
|
|
7
8
|
module Datadog
|
@@ -10,6 +11,7 @@ module Datadog
|
|
10
11
|
module Metadata
|
11
12
|
def self.included(base)
|
12
13
|
base.include(Metadata::Tagging)
|
14
|
+
base.include(Metadata::MetastructTagging)
|
13
15
|
base.include(Metadata::Errors)
|
14
16
|
|
15
17
|
# Additional extensions
|
data/lib/datadog/tracing/span.rb
CHANGED
@@ -33,6 +33,9 @@ module Datadog
|
|
33
33
|
:status,
|
34
34
|
:trace_id
|
35
35
|
|
36
|
+
attr_reader \
|
37
|
+
:metastruct
|
38
|
+
|
36
39
|
attr_writer \
|
37
40
|
:duration
|
38
41
|
|
@@ -54,6 +57,7 @@ module Datadog
|
|
54
57
|
id: nil,
|
55
58
|
meta: nil,
|
56
59
|
metrics: nil,
|
60
|
+
metastruct: nil,
|
57
61
|
parent_id: 0,
|
58
62
|
resource: name,
|
59
63
|
service: nil,
|
@@ -76,6 +80,7 @@ module Datadog
|
|
76
80
|
|
77
81
|
@meta = meta || {}
|
78
82
|
@metrics = metrics || {}
|
83
|
+
@metastruct = metastruct || {}
|
79
84
|
@status = status || 0
|
80
85
|
|
81
86
|
# start_time and end_time track wall clock. In Ruby, wall clock
|
@@ -144,6 +149,7 @@ module Datadog
|
|
144
149
|
error: @status,
|
145
150
|
meta: @meta,
|
146
151
|
metrics: @metrics,
|
152
|
+
meta_struct: @metastruct.to_h,
|
147
153
|
name: @name,
|
148
154
|
parent_id: @parent_id,
|
149
155
|
resource: @resource,
|
@@ -185,12 +191,15 @@ module Datadog
|
|
185
191
|
q.text "#{key} => #{value}"
|
186
192
|
end
|
187
193
|
end
|
188
|
-
q.group(2, 'Metrics: [',
|
194
|
+
q.group(2, 'Metrics: [', "]\n") do
|
189
195
|
q.breakable
|
190
196
|
q.seplist @metrics.each do |key, value|
|
191
197
|
q.text "#{key} => #{value}"
|
192
198
|
end
|
193
199
|
end
|
200
|
+
q.group(2, 'Metastruct: [', ']') do
|
201
|
+
metastruct.pretty_print(q)
|
202
|
+
end
|
194
203
|
end
|
195
204
|
end
|
196
205
|
|
@@ -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)
|
@@ -289,6 +290,7 @@ module Datadog
|
|
289
290
|
id: @id,
|
290
291
|
meta: meta,
|
291
292
|
metrics: metrics,
|
293
|
+
metastruct: metastruct,
|
292
294
|
name: @name,
|
293
295
|
parent_id: @parent_id,
|
294
296
|
resource: @resource,
|
@@ -328,12 +330,15 @@ module Datadog
|
|
328
330
|
q.text "#{key} => #{value}"
|
329
331
|
end
|
330
332
|
end
|
331
|
-
q.group(2, 'Metrics: [',
|
333
|
+
q.group(2, 'Metrics: [', "]\n") do
|
332
334
|
q.breakable
|
333
335
|
q.seplist metrics.each do |key, value|
|
334
336
|
q.text "#{key} => #{value}"
|
335
337
|
end
|
336
338
|
end
|
339
|
+
q.group(2, 'Metastruct: [', ']') do
|
340
|
+
metastruct.pretty_print(q)
|
341
|
+
end
|
337
342
|
end
|
338
343
|
end
|
339
344
|
|
@@ -456,6 +461,7 @@ module Datadog
|
|
456
461
|
id: @id,
|
457
462
|
meta: Core::Utils::SafeDup.frozen_or_dup(meta),
|
458
463
|
metrics: Core::Utils::SafeDup.frozen_or_dup(metrics),
|
464
|
+
metastruct: Core::Utils::SafeDup.frozen_or_dup(metastruct),
|
459
465
|
parent_id: @parent_id,
|
460
466
|
resource: @resource,
|
461
467
|
service: @service,
|
@@ -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
|
|