datadog 2.42.0 → 2.43.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 +24 -2
- data/README.md +3 -0
- data/ext/datadog_profiling_native_extension/collectors_cpu_and_wall_time_worker.c +10 -0
- data/ext/datadog_profiling_native_extension/collectors_thread_context.c +15 -5
- data/ext/datadog_profiling_native_extension/heap_recorder.c +13 -0
- data/ext/datadog_profiling_native_extension/heap_recorder.h +4 -0
- data/ext/datadog_profiling_native_extension/private_vm_api_access.c +9 -2
- data/ext/datadog_profiling_native_extension/stack_recorder.c +13 -0
- data/ext/datadog_profiling_native_extension/time_helpers.h +2 -1
- data/ext/libdatadog_api/otel_thread_context.c +15 -0
- data/ext/libdatadog_api/trace_exporter.c +642 -22
- data/lib/datadog/open_feature/transport.rb +5 -0
- data/lib/datadog/profiling/collectors/info.rb +2 -6
- data/lib/datadog/tracing/contrib/sequel/jdbc_connection_string.rb +140 -0
- data/lib/datadog/tracing/contrib/sequel/utils.rb +49 -62
- data/lib/datadog/tracing/otel_thread_context.rb +4 -0
- data/lib/datadog/tracing/transport/native.rb +17 -25
- data/lib/datadog/tracing/transport/span_events_negotiation.rb +41 -0
- data/lib/datadog/tracing/transport/traces.rb +2 -22
- data/lib/datadog/version.rb +1 -1
- metadata +5 -3
|
@@ -8,6 +8,7 @@ require_relative "../core/transport/http/api/endpoint"
|
|
|
8
8
|
require_relative "../core/transport/http/api/instance"
|
|
9
9
|
require_relative "../core/transport/parcel"
|
|
10
10
|
require_relative "../core/transport/request"
|
|
11
|
+
require_relative "../version"
|
|
11
12
|
|
|
12
13
|
module Datadog
|
|
13
14
|
module OpenFeature
|
|
@@ -27,6 +28,8 @@ module Datadog
|
|
|
27
28
|
request_env.headers["Content-Type"] = env.request.parcel.content_type
|
|
28
29
|
request_env.headers[Core::EVP::SUBDOMAIN_HEADER_NAME] =
|
|
29
30
|
Core::EVP::EVENT_PLATFORM_INTAKE_SUBDOMAIN
|
|
31
|
+
request_env.headers["DD-EVP-ORIGIN"] = "dd-trace-rb"
|
|
32
|
+
request_env.headers["DD-EVP-ORIGIN-VERSION"] = Datadog::VERSION::STRING
|
|
30
33
|
request_env.body = env.request.parcel.data
|
|
31
34
|
|
|
32
35
|
block.call(request_env)
|
|
@@ -49,6 +52,8 @@ module Datadog
|
|
|
49
52
|
request_env.headers["Content-Type"] = env.request.parcel.content_type
|
|
50
53
|
request_env.headers[Core::EVP::SUBDOMAIN_HEADER_NAME] =
|
|
51
54
|
Core::EVP::EVENT_PLATFORM_INTAKE_SUBDOMAIN
|
|
55
|
+
request_env.headers["DD-EVP-ORIGIN"] = "dd-trace-rb"
|
|
56
|
+
request_env.headers["DD-EVP-ORIGIN-VERSION"] = Datadog::VERSION::STRING
|
|
52
57
|
request_env.body = env.request.parcel.data
|
|
53
58
|
|
|
54
59
|
block.call(request_env)
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require "set"
|
|
4
|
-
require "time"
|
|
5
3
|
require "libdatadog"
|
|
4
|
+
require_relative "../../core/utils/time"
|
|
6
5
|
|
|
7
6
|
module Datadog
|
|
8
7
|
module Profiling
|
|
@@ -71,10 +70,7 @@ module Datadog
|
|
|
71
70
|
# Instead of trying to figure out real process start time by checking
|
|
72
71
|
# /proc or some other complex/non-portable way, approximate start time
|
|
73
72
|
# by time of requirement of this file.
|
|
74
|
-
|
|
75
|
-
# Note: this does not use Core::Utils::Time.now because this constant
|
|
76
|
-
# gets initialized before a user has a chance to configure the library.
|
|
77
|
-
START_TIME = Time.now.utc.freeze
|
|
73
|
+
START_TIME = Datadog::Core::Utils::Time.now.utc.freeze
|
|
78
74
|
|
|
79
75
|
#: () -> ::Hash[::Symbol, untyped]
|
|
80
76
|
def collect_platform_info
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Datadog
|
|
4
|
+
module Tracing
|
|
5
|
+
module Contrib
|
|
6
|
+
module Sequel
|
|
7
|
+
# Extracts connection metadata from JDBC connection strings.
|
|
8
|
+
module JDBCConnectionString
|
|
9
|
+
MAX_BYTES = 8_192
|
|
10
|
+
|
|
11
|
+
# Matches JDBC connection strings whose subname uses `[transport:]//host...`.
|
|
12
|
+
CONNECTION_STRING_PATTERN =
|
|
13
|
+
%r{\Ajdbc:[a-z][a-z0-9+.-]*:(?:[a-z][a-z0-9+.-]*:)?//(?<subname>.+)\z}im
|
|
14
|
+
|
|
15
|
+
# Extracts the host and port from a string.
|
|
16
|
+
# The host can be a multi-host value, a bracketed IPv6 host, or an ordinary host.
|
|
17
|
+
HOST_AND_PORT_PATTERN =
|
|
18
|
+
/\A(?:\[(?<ipv6_host>[^\[\]]+)\]|(?<host>[^,]+(?:,[^,]+)+|[^:]+))(?::(?<port>\d+))?\z/
|
|
19
|
+
|
|
20
|
+
DATABASE_PROPERTY_PATTERN =
|
|
21
|
+
/(?:\A|[&;])(?:databaseName|database)=(?<value>[^&;]+)/i
|
|
22
|
+
LIBRARIES_PROPERTY_PATTERN =
|
|
23
|
+
/(?:\A|[&;])libraries=,*(?<value>[^,&;]+)/i
|
|
24
|
+
DATABASE_PATH_DELIMITER_PATTERN = %r{[:@\[\]?&=#]}
|
|
25
|
+
|
|
26
|
+
private_constant :MAX_BYTES, :CONNECTION_STRING_PATTERN,
|
|
27
|
+
:DATABASE_PROPERTY_PATTERN, :LIBRARIES_PROPERTY_PATTERN,
|
|
28
|
+
:DATABASE_PATH_DELIMITER_PATTERN, :HOST_AND_PORT_PATTERN
|
|
29
|
+
|
|
30
|
+
class << self
|
|
31
|
+
# The returned Hash guarantees the existence of all keys,
|
|
32
|
+
# but Hash values can be `nil` when not parseable from the connection string.
|
|
33
|
+
#
|
|
34
|
+
# @param connection_string [String, nil] the JDBC connection string to parse
|
|
35
|
+
# @return [Hash{Symbol => String, nil}]
|
|
36
|
+
# - `:host` — host value when the subname uses authority syntax: `//host[:port]`
|
|
37
|
+
# - `:port` — port when the subname uses authority syntax: `//host[:port]`
|
|
38
|
+
# - `:database` — best-effort database name
|
|
39
|
+
def parse(connection_string)
|
|
40
|
+
# @type var result: metadata
|
|
41
|
+
result = {host: nil, port: nil, database: nil}
|
|
42
|
+
return result unless connection_string.is_a?(String) && connection_string.valid_encoding?
|
|
43
|
+
|
|
44
|
+
if connection_string.bytesize > MAX_BYTES
|
|
45
|
+
# Strip userinfo before truncation. Otherwise, an `@` beyond the limit could be
|
|
46
|
+
# discarded and leave a credential prefix looking like a valid authority/host.
|
|
47
|
+
authority_marker = connection_string.index("//")
|
|
48
|
+
if authority_marker
|
|
49
|
+
authority_start = authority_marker + 2
|
|
50
|
+
authority_end = [
|
|
51
|
+
connection_string.index("/", authority_start),
|
|
52
|
+
connection_string.index(";", authority_start),
|
|
53
|
+
connection_string.index("?", authority_start),
|
|
54
|
+
].compact.min || connection_string.length
|
|
55
|
+
userinfo_end = connection_string.rindex("@", authority_end - 1)
|
|
56
|
+
|
|
57
|
+
if userinfo_end && userinfo_end >= authority_start
|
|
58
|
+
connection_string =
|
|
59
|
+
# Steep: https://github.com/soutaro/steep/issues/1219
|
|
60
|
+
connection_string[0...authority_start] + # steep:ignore NoMethod
|
|
61
|
+
connection_string[(userinfo_end + 1)..-1].to_s
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# Keep one extra byte, then let `chop` safely remove multi-byte unicode characters.
|
|
66
|
+
if connection_string.bytesize > MAX_BYTES
|
|
67
|
+
connection_string = connection_string.byteslice(0, MAX_BYTES + 1).chop
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
match = CONNECTION_STRING_PATTERN.match(connection_string)
|
|
72
|
+
return result unless match
|
|
73
|
+
|
|
74
|
+
# We start with: `host[:port][/database][;properties][?query]`.
|
|
75
|
+
subname = match[:subname]
|
|
76
|
+
|
|
77
|
+
# Extract `query` from the end, leaving `host[:port][/database][;properties]`.
|
|
78
|
+
subname, query_separator, query = subname.partition("?")
|
|
79
|
+
query = nil if query_separator.empty?
|
|
80
|
+
|
|
81
|
+
# Extract `properties` next, leaving `host[:port][/database]`.
|
|
82
|
+
subname, properties_separator, properties = subname.partition(";")
|
|
83
|
+
properties = nil if properties_separator.empty?
|
|
84
|
+
|
|
85
|
+
# Separate the authority (`host[:port]`) from the optional database path.
|
|
86
|
+
authority, path = subname.split("/", 2)
|
|
87
|
+
return result if authority.nil? || authority.empty?
|
|
88
|
+
|
|
89
|
+
host, port = host_and_port_from_authority(authority)
|
|
90
|
+
return result unless host
|
|
91
|
+
|
|
92
|
+
database = database_from_path(path) ||
|
|
93
|
+
database_from_properties(properties) || database_from_properties(query)
|
|
94
|
+
|
|
95
|
+
{host: host, port: port, database: database}
|
|
96
|
+
rescue Encoding::CompatibilityError, ArgumentError
|
|
97
|
+
result
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
private
|
|
101
|
+
|
|
102
|
+
def database_from_path(path)
|
|
103
|
+
return if path.nil? || path.empty?
|
|
104
|
+
|
|
105
|
+
database = path.split(DATABASE_PATH_DELIMITER_PATTERN, 2).first
|
|
106
|
+
return if database.nil? || database.empty?
|
|
107
|
+
|
|
108
|
+
database
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def host_and_port_from_authority(authority)
|
|
112
|
+
# Discard optional `userinfo@`, retaining only `host[:port]`.
|
|
113
|
+
authority = authority.rpartition("@").last
|
|
114
|
+
return if authority.empty?
|
|
115
|
+
|
|
116
|
+
match = HOST_AND_PORT_PATTERN.match(authority)
|
|
117
|
+
return unless match
|
|
118
|
+
|
|
119
|
+
# Only one of `ipv6_host` or `host` will be populated.
|
|
120
|
+
host = match[:ipv6_host] || match[:host]
|
|
121
|
+
port = match[:port]
|
|
122
|
+
|
|
123
|
+
[host, port]
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def database_from_properties(properties)
|
|
127
|
+
return unless properties
|
|
128
|
+
|
|
129
|
+
database = DATABASE_PROPERTY_PATTERN.match(properties)
|
|
130
|
+
return database[:value] if database
|
|
131
|
+
|
|
132
|
+
libraries = LIBRARIES_PROPERTY_PATTERN.match(properties)
|
|
133
|
+
libraries && libraries[:value]
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
end
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require "uri"
|
|
4
|
-
|
|
5
3
|
require_relative "../../metadata/ext"
|
|
6
4
|
require_relative "../utils/database"
|
|
7
5
|
require_relative "ext"
|
|
6
|
+
require_relative "jdbc_connection_string"
|
|
8
7
|
require_relative "../ext"
|
|
9
8
|
require_relative "../span_attribute_schema"
|
|
10
9
|
|
|
@@ -14,11 +13,6 @@ module Datadog
|
|
|
14
13
|
module Sequel
|
|
15
14
|
# General purpose functions for Sequel
|
|
16
15
|
module Utils
|
|
17
|
-
JDBC_URI_PATTERN = %r{\Ajdbc:(?<vendor>[a-z][a-z0-9+.-]*):(?<location>//[^\r\n]*)\z}i
|
|
18
|
-
DATABASE_PROPERTY_PATTERN =
|
|
19
|
-
/(?:\A|[&;])(?<key>databaseName|database|libraries)=(?<value>[^&;]+)/i
|
|
20
|
-
private_constant :JDBC_URI_PATTERN, :DATABASE_PROPERTY_PATTERN
|
|
21
|
-
|
|
22
16
|
class << self
|
|
23
17
|
# Ruby database connector library
|
|
24
18
|
#
|
|
@@ -42,34 +36,6 @@ module Datadog
|
|
|
42
36
|
Contrib::Utils::Database.normalize_vendor(database.database_type.to_s)
|
|
43
37
|
end
|
|
44
38
|
|
|
45
|
-
# Parses URI-style JDBC connection strings, extracting host, port, and
|
|
46
|
-
# (best-effort) database name. Unsupported or ambiguous forms return empty
|
|
47
|
-
# metadata rather than potentially incorrect tags.
|
|
48
|
-
def parse_jdbc_uri(uri)
|
|
49
|
-
result = {host: nil, port: nil, database: nil}
|
|
50
|
-
return result unless uri.is_a?(String) && uri.valid_encoding?
|
|
51
|
-
|
|
52
|
-
match = JDBC_URI_PATTERN.match(uri)
|
|
53
|
-
return result unless match
|
|
54
|
-
|
|
55
|
-
vendor = match[:vendor].downcase
|
|
56
|
-
location, properties = match[:location].split(";", 2)
|
|
57
|
-
|
|
58
|
-
# Several JDBC vendors append properties with semicolons, outside the URI
|
|
59
|
-
# grammar. Parse the URI-compatible location separately from those properties.
|
|
60
|
-
parsed = URI.parse("#{vendor}:#{location}")
|
|
61
|
-
|
|
62
|
-
host = parsed.hostname
|
|
63
|
-
port = parsed.port
|
|
64
|
-
|
|
65
|
-
database = database_from_path(parsed.path) ||
|
|
66
|
-
database_from_properties(properties) || database_from_properties(parsed.query)
|
|
67
|
-
|
|
68
|
-
{host: host, port: port&.to_s, database: database}
|
|
69
|
-
rescue URI::InvalidURIError, Encoding::CompatibilityError, ArgumentError
|
|
70
|
-
result
|
|
71
|
-
end
|
|
72
|
-
|
|
73
39
|
def parse_opts(sql, opts, db_opts, dataset = nil)
|
|
74
40
|
# Prepared statements don't provide their sql query in the +sql+ parameter.
|
|
75
41
|
if !sql.is_a?(String) && dataset&.respond_to?(:prepared_sql) &&
|
|
@@ -121,25 +87,38 @@ module Datadog
|
|
|
121
87
|
Contrib::Analytics.set_sample_rate(span, analytics_sample_rate) if analytics_enabled?
|
|
122
88
|
end
|
|
123
89
|
|
|
124
|
-
# Resolves the connection host/port/database for a Sequel::Database.
|
|
125
|
-
#
|
|
126
|
-
#
|
|
90
|
+
# Resolves the connection host/port/database for a Sequel::Database. For Sequel's
|
|
91
|
+
# JDBC adapter (used on JRuby), metadata is parsed from the JDBC connection string
|
|
92
|
+
# regardless of whether opts[:host] is set.
|
|
127
93
|
def connection_metadata(db)
|
|
128
94
|
opts = db.opts || {}
|
|
129
95
|
host = opts[:host]
|
|
130
96
|
port = opts[:port]
|
|
131
97
|
database = opts[:database]
|
|
132
98
|
|
|
133
|
-
# A JDBC
|
|
134
|
-
#
|
|
135
|
-
|
|
136
|
-
is_jdbc =
|
|
99
|
+
# A JDBC connection string (in :uri, :url, or :database) can carry credentials, so
|
|
100
|
+
# always emit only parsed metadata -- never the raw connection string.
|
|
101
|
+
connection_string = opts[:uri] || opts[:url] || opts[:database]
|
|
102
|
+
is_jdbc = connection_string.is_a?(String) &&
|
|
103
|
+
connection_string.byteslice(0, 5)&.casecmp("jdbc:") == 0
|
|
137
104
|
if is_jdbc
|
|
138
|
-
parsed =
|
|
105
|
+
parsed = JDBCConnectionString.parse(connection_string)
|
|
106
|
+
|
|
107
|
+
# JNDI/DataSource-managed connections keep only a lookup name in opts (e.g.
|
|
108
|
+
# "jdbc:jndi:..."), so nothing can be parsed from it. Recover the endpoint from the
|
|
109
|
+
# live connection's JDBC metadata, the same way Sequel resolves JNDI. This stays a
|
|
110
|
+
# fallback rather than the primary source: it requires a connection checkout and
|
|
111
|
+
# some drivers report no connection string, whereas the opts value is free and
|
|
112
|
+
# already present for direct connections (and non-JDBC adapters have no such
|
|
113
|
+
# metadata at all).
|
|
114
|
+
if parsed[:host].nil? && parsed[:port].nil? && parsed[:database].nil?
|
|
115
|
+
fallback_metadata = jdbc_metadata_from_connection(db)
|
|
116
|
+
parsed = fallback_metadata if fallback_metadata
|
|
117
|
+
end
|
|
139
118
|
|
|
140
|
-
# Sequel's JDBC adapter connects with the
|
|
119
|
+
# Sequel's JDBC adapter connects with the connection string and ignores separate
|
|
141
120
|
# :host/:port options, unlike native adapters where those options take precedence.
|
|
142
|
-
if
|
|
121
|
+
if parsed[:host] || parsed[:port] || parsed[:database]
|
|
143
122
|
host = parsed[:host]
|
|
144
123
|
port = parsed[:port]
|
|
145
124
|
end
|
|
@@ -151,24 +130,32 @@ module Datadog
|
|
|
151
130
|
|
|
152
131
|
private
|
|
153
132
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
133
|
+
# Resolves host/port/database from the live connection's JDBC metadata
|
|
134
|
+
# (java.sql.DatabaseMetaData#getURL), for JNDI/DataSource connections whose opts hold
|
|
135
|
+
# only a lookup name. Returns the parsed metadata, or nil when it can't be resolved.
|
|
136
|
+
#
|
|
137
|
+
# Only *parsed, credential-free* metadata is memoized -- the raw connection string is
|
|
138
|
+
# used transiently and never stored or logged. A completed lookup that yields no usable
|
|
139
|
+
# connection string is a permanent property of the connection, so it is cached to avoid
|
|
140
|
+
# re-checking out a connection on every query. A raised error is treated as transient
|
|
141
|
+
# (pool checkout timeout, dropped connection, ...) and left uncached, so a later query
|
|
142
|
+
# can retry once connectivity recovers.
|
|
143
|
+
def jdbc_metadata_from_connection(db)
|
|
144
|
+
return db.instance_variable_get(:@datadog_jdbc_metadata) if db.instance_variable_defined?(:@datadog_jdbc_metadata)
|
|
145
|
+
|
|
146
|
+
connection_string =
|
|
147
|
+
begin
|
|
148
|
+
db.synchronize do |conn|
|
|
149
|
+
conn.get_meta_data.get_url if conn.respond_to?(:get_meta_data)
|
|
150
|
+
end
|
|
151
|
+
rescue => e
|
|
152
|
+
Datadog.logger.debug { "Sequel: unable to resolve JDBC connection metadata (#{e.class})" }
|
|
153
|
+
return nil
|
|
154
|
+
end
|
|
168
155
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
156
|
+
metadata = connection_string && JDBCConnectionString.parse(connection_string)
|
|
157
|
+
db.instance_variable_set(:@datadog_jdbc_metadata, metadata)
|
|
158
|
+
metadata
|
|
172
159
|
end
|
|
173
160
|
|
|
174
161
|
def datadog_configuration
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
require "json"
|
|
4
4
|
require_relative "trace_formatter"
|
|
5
5
|
require_relative "statistics"
|
|
6
|
+
require_relative "span_events_negotiation"
|
|
6
7
|
|
|
7
8
|
module Datadog
|
|
8
9
|
module Tracing
|
|
@@ -44,6 +45,7 @@ module Datadog
|
|
|
44
45
|
# Drop-in transport that delegates to the native trace exporter.
|
|
45
46
|
class Transport
|
|
46
47
|
include Statistics
|
|
48
|
+
include SpanEventsNegotiation
|
|
47
49
|
|
|
48
50
|
attr_reader :logger
|
|
49
51
|
|
|
@@ -57,10 +59,6 @@ module Datadog
|
|
|
57
59
|
|
|
58
60
|
@logger = logger
|
|
59
61
|
|
|
60
|
-
# Guards the one-shot warning about span fields the native exporter
|
|
61
|
-
# does not yet convert (see #warn_unsupported_fields!).
|
|
62
|
-
@unsupported_fields_warned = false
|
|
63
|
-
|
|
64
62
|
# Serializes native sends and is held across a fork. See the
|
|
65
63
|
# fork-safety note below.
|
|
66
64
|
@send_mutex = Mutex.new
|
|
@@ -272,9 +270,8 @@ module Datadog
|
|
|
272
270
|
# Each trace segment becomes one inner array (one trace chunk).
|
|
273
271
|
chunks = traces.map(&:spans)
|
|
274
272
|
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
warn_unsupported_fields!(chunks)
|
|
273
|
+
native_events_supported = native_events_supported?
|
|
274
|
+
apply_legacy_span_events!(chunks, native_events_supported)
|
|
278
275
|
|
|
279
276
|
# Serialize the native send and hold the mutex across it so a
|
|
280
277
|
# concurrent fork's :before hook blocks until this send drains
|
|
@@ -287,7 +284,7 @@ module Datadog
|
|
|
287
284
|
exporter = @exporter
|
|
288
285
|
raise "Native transport has been closed" if exporter.nil?
|
|
289
286
|
|
|
290
|
-
exporter._native_send_traces(chunks)
|
|
287
|
+
exporter._native_send_traces(chunks, native_events_supported)
|
|
291
288
|
end
|
|
292
289
|
|
|
293
290
|
# Update statistics from the response
|
|
@@ -302,29 +299,24 @@ module Datadog
|
|
|
302
299
|
|
|
303
300
|
private
|
|
304
301
|
|
|
305
|
-
#
|
|
306
|
-
# the
|
|
307
|
-
#
|
|
308
|
-
#
|
|
309
|
-
#
|
|
310
|
-
|
|
311
|
-
|
|
302
|
+
# Writes each span's events into the legacy JSON +events+ meta tag
|
|
303
|
+
# when the agent lacks typed-event support, mutating spans in place.
|
|
304
|
+
#
|
|
305
|
+
# @param chunks [Array<Array<Datadog::Tracing::Span>>] trace chunks to serialize
|
|
306
|
+
# @param native_events_supported [Boolean] whether the agent accepts typed events
|
|
307
|
+
# @return [void]
|
|
308
|
+
def apply_legacy_span_events!(chunks, native_events_supported)
|
|
309
|
+
return if native_events_supported
|
|
312
310
|
|
|
313
|
-
unsupported = []
|
|
314
311
|
chunks.each do |spans|
|
|
315
312
|
spans.each do |span|
|
|
316
|
-
|
|
317
|
-
|
|
313
|
+
next if span.events.empty?
|
|
314
|
+
|
|
315
|
+
span.set_tag("events", span.events.map(&:to_hash).to_json)
|
|
318
316
|
end
|
|
319
317
|
end
|
|
320
|
-
return if unsupported.empty?
|
|
321
318
|
|
|
322
|
-
|
|
323
|
-
fields = unsupported.uniq.join(", ")
|
|
324
|
-
logger.warn do
|
|
325
|
-
"Native transport does not yet support: #{fields}. This data will not be sent to Datadog. " \
|
|
326
|
-
"Unset DD_EXPERIMENTAL_NATIVE_TRANSPORT_ENABLED to use the default transport if you rely on these."
|
|
327
|
-
end
|
|
319
|
+
nil
|
|
328
320
|
end
|
|
329
321
|
|
|
330
322
|
def tracer_version_string
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Datadog
|
|
4
|
+
module Tracing
|
|
5
|
+
module Transport
|
|
6
|
+
# Shared agent capability negotiation for span event wire formats.
|
|
7
|
+
module SpanEventsNegotiation
|
|
8
|
+
private
|
|
9
|
+
|
|
10
|
+
# Queries whether the agent accepts typed span events, which selects
|
|
11
|
+
# between the typed field and legacy JSON metadata. Only successful
|
|
12
|
+
# capability responses are cached so a later flush can recover.
|
|
13
|
+
#
|
|
14
|
+
# The memo is read and written without synchronization, independent of
|
|
15
|
+
# any lock the including transport holds for its own sends (the native
|
|
16
|
+
# transport's +@send_mutex+, for example). Two concurrent sends can both
|
|
17
|
+
# observe it unset and each issue an +agent_info.fetch+; the duplicate
|
|
18
|
+
# fetch is self-correcting because the last writer wins.
|
|
19
|
+
#
|
|
20
|
+
# @return [Boolean] true if typed span events are supported
|
|
21
|
+
def native_events_supported?
|
|
22
|
+
return @native_events_supported if defined?(@native_events_supported)
|
|
23
|
+
|
|
24
|
+
option = Datadog.configuration.tracing.native_span_events
|
|
25
|
+
unless option.nil?
|
|
26
|
+
@native_events_supported = option
|
|
27
|
+
return option
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
components = Datadog.send(:components, allow_initialization: false)
|
|
31
|
+
return false unless components
|
|
32
|
+
|
|
33
|
+
response = components.agent_info.fetch
|
|
34
|
+
return false unless response
|
|
35
|
+
|
|
36
|
+
@native_events_supported = response.span_events == true
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -7,6 +7,7 @@ require_relative "../../core/transport/transport"
|
|
|
7
7
|
require_relative "../../core/utils/enumerable_compat"
|
|
8
8
|
require_relative "http/client"
|
|
9
9
|
require_relative "serializable_trace"
|
|
10
|
+
require_relative "span_events_negotiation"
|
|
10
11
|
require_relative "trace_formatter"
|
|
11
12
|
|
|
12
13
|
module Datadog
|
|
@@ -118,6 +119,7 @@ module Datadog
|
|
|
118
119
|
# batches of traces into smaller chunks and handles
|
|
119
120
|
# API version downgrade handshake.
|
|
120
121
|
class Transport < Core::Transport::Transport
|
|
122
|
+
include SpanEventsNegotiation
|
|
121
123
|
self.http_client_class = Tracing::Transport::HTTP::Client
|
|
122
124
|
|
|
123
125
|
def send_traces(traces)
|
|
@@ -161,28 +163,6 @@ module Datadog
|
|
|
161
163
|
def stats
|
|
162
164
|
client.stats
|
|
163
165
|
end
|
|
164
|
-
|
|
165
|
-
private
|
|
166
|
-
|
|
167
|
-
# Queries the agent for native span events serialization support.
|
|
168
|
-
# This changes how the serialization of span events performed.
|
|
169
|
-
def native_events_supported?
|
|
170
|
-
return @native_events_supported if defined?(@native_events_supported)
|
|
171
|
-
|
|
172
|
-
# Check for an explicit override
|
|
173
|
-
option = Datadog.configuration.tracing.native_span_events
|
|
174
|
-
unless option.nil?
|
|
175
|
-
@native_events_supported = option
|
|
176
|
-
return option
|
|
177
|
-
end
|
|
178
|
-
|
|
179
|
-
# Otherwise, check for agent support, to ensure a configuration-less setup.
|
|
180
|
-
if (res = Datadog.send(:components).agent_info.fetch)
|
|
181
|
-
@native_events_supported = res.span_events == true
|
|
182
|
-
else
|
|
183
|
-
false
|
|
184
|
-
end
|
|
185
|
-
end
|
|
186
166
|
end
|
|
187
167
|
end
|
|
188
168
|
end
|
data/lib/datadog/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: datadog
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.
|
|
4
|
+
version: 2.43.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Datadog, Inc.
|
|
@@ -1025,6 +1025,7 @@ files:
|
|
|
1025
1025
|
- lib/datadog/tracing/contrib/sequel/dataset.rb
|
|
1026
1026
|
- lib/datadog/tracing/contrib/sequel/ext.rb
|
|
1027
1027
|
- lib/datadog/tracing/contrib/sequel/integration.rb
|
|
1028
|
+
- lib/datadog/tracing/contrib/sequel/jdbc_connection_string.rb
|
|
1028
1029
|
- lib/datadog/tracing/contrib/sequel/patcher.rb
|
|
1029
1030
|
- lib/datadog/tracing/contrib/sequel/utils.rb
|
|
1030
1031
|
- lib/datadog/tracing/contrib/shoryuken/configuration/settings.rb
|
|
@@ -1159,6 +1160,7 @@ files:
|
|
|
1159
1160
|
- lib/datadog/tracing/transport/native.rb
|
|
1160
1161
|
- lib/datadog/tracing/transport/native/response.rb
|
|
1161
1162
|
- lib/datadog/tracing/transport/serializable_trace.rb
|
|
1163
|
+
- lib/datadog/tracing/transport/span_events_negotiation.rb
|
|
1162
1164
|
- lib/datadog/tracing/transport/statistics.rb
|
|
1163
1165
|
- lib/datadog/tracing/transport/trace_formatter.rb
|
|
1164
1166
|
- lib/datadog/tracing/transport/traces.rb
|
|
@@ -1172,8 +1174,8 @@ licenses:
|
|
|
1172
1174
|
- Apache-2.0
|
|
1173
1175
|
metadata:
|
|
1174
1176
|
allowed_push_host: https://rubygems.org
|
|
1175
|
-
changelog_uri: https://github.com/DataDog/dd-trace-rb/blob/v2.
|
|
1176
|
-
source_code_uri: https://github.com/DataDog/dd-trace-rb/tree/v2.
|
|
1177
|
+
changelog_uri: https://github.com/DataDog/dd-trace-rb/blob/v2.43.0/CHANGELOG.md
|
|
1178
|
+
source_code_uri: https://github.com/DataDog/dd-trace-rb/tree/v2.43.0
|
|
1177
1179
|
post_install_message: 'JRuby support in the datadog gem is deprecated. Details: https://dtdg.co/jruby-deprecation'
|
|
1178
1180
|
rdoc_options: []
|
|
1179
1181
|
require_paths:
|