datadog 2.45.0 → 2.47.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 +49 -1
- data/ext/datadog_profiling_native_extension/collectors_stack.c +31 -14
- data/ext/datadog_profiling_native_extension/private_vm_api_access.c +5 -1
- data/ext/datadog_profiling_native_extension/private_vm_api_access.h +5 -0
- data/ext/datadog_profiling_native_extension/profiling.c +6 -0
- data/ext/libdatadog_api/di.c +30 -5
- data/ext/libdatadog_api/extconf.rb +2 -0
- data/ext/libdatadog_api/otel_thread_context.c +20 -14
- data/ext/libdatadog_api/process_discovery.c +15 -1
- data/ext/libdatadog_api/trace_exporter.c +105 -25
- data/ext/libdatadog_extconf_helpers.rb +1 -1
- data/lib/datadog/appsec/contrib/rails/gateway/watcher.rb +29 -2
- data/lib/datadog/appsec/contrib/rails/patches/render_to_body_patch.rb +8 -7
- data/lib/datadog/appsec/contrib/sinatra/gateway/watcher.rb +14 -2
- data/lib/datadog/appsec/contrib/sinatra/patches/json_patch.rb +8 -7
- data/lib/datadog/appsec/security_engine/engine.rb +2 -1
- data/lib/datadog/core/configuration/components.rb +40 -18
- data/lib/datadog/core/configuration/components_state.rb +8 -1
- data/lib/datadog/core/configuration/supported_configurations.rb +7 -2
- data/lib/datadog/core/process_discovery.rb +5 -1
- data/lib/datadog/core/remote/client/capabilities.rb +34 -29
- data/lib/datadog/core/remote/client.rb +44 -3
- data/lib/datadog/core/remote/component.rb +28 -12
- data/lib/datadog/core/remote/dispatcher.rb +47 -6
- data/lib/datadog/core/workers/runtime_metrics.rb +1 -1
- data/lib/datadog/di/boot.rb +1 -0
- data/lib/datadog/di/capture_expression_evaluator/result.rb +30 -0
- data/lib/datadog/di/capture_expression_evaluator.rb +39 -9
- data/lib/datadog/di/component.rb +108 -3
- data/lib/datadog/di/configuration.rb +53 -2
- data/lib/datadog/di/context.rb +7 -2
- data/lib/datadog/di/contrib/active_record.rb +8 -2
- data/lib/datadog/di/evaluation_failure.rb +28 -0
- data/lib/datadog/di/guardrails_telemetry/reason.rb +87 -0
- data/lib/datadog/di/guardrails_telemetry.rb +203 -0
- data/lib/datadog/di/instrumenter.rb +65 -15
- data/lib/datadog/di/logger.rb +30 -8
- data/lib/datadog/di/probe_manager.rb +48 -5
- data/lib/datadog/di/probe_notification_builder.rb +28 -26
- data/lib/datadog/di/probe_notifier_worker.rb +56 -6
- data/lib/datadog/di/remote.rb +46 -2
- data/lib/datadog/di/serializer.rb +147 -55
- data/lib/datadog/di/snapshot_event.rb +38 -0
- data/lib/datadog/di/transport/http.rb +13 -3
- data/lib/datadog/di/transport/input.rb +32 -7
- data/lib/datadog/open_feature/activation.rb +268 -0
- data/lib/datadog/open_feature/component.rb +31 -15
- data/lib/datadog/open_feature/configuration.rb +6 -0
- data/lib/datadog/open_feature/hooks/evaluation_telemetry_opt_out_hook.rb +25 -0
- data/lib/datadog/open_feature/provider.rb +304 -8
- data/lib/datadog/open_feature.rb +31 -1
- data/lib/datadog/profiling/collectors/info.rb +37 -6
- data/lib/datadog/profiling/component.rb +22 -20
- data/lib/datadog/profiling/exporter.rb +3 -5
- data/lib/datadog/tracing/component.rb +21 -2
- data/lib/datadog/tracing/configuration/ext.rb +2 -0
- data/lib/datadog/tracing/configuration/settings.rb +14 -1
- data/lib/datadog/tracing/context_provider.rb +8 -0
- data/lib/datadog/tracing/contrib/ethon/easy_patch.rb +10 -5
- data/lib/datadog/tracing/contrib/excon/middleware.rb +10 -3
- data/lib/datadog/tracing/contrib/faraday/middleware.rb +10 -4
- data/lib/datadog/tracing/contrib/http/instrumentation.rb +16 -1
- data/lib/datadog/tracing/contrib/httpclient/instrumentation.rb +8 -2
- data/lib/datadog/tracing/contrib/httprb/instrumentation.rb +10 -4
- data/lib/datadog/tracing/contrib/rest_client/request_patch.rb +10 -3
- data/lib/datadog/tracing/contrib/utils/quantization/http.rb +102 -0
- data/lib/datadog/tracing/otel_thread_context.rb +3 -5
- data/lib/datadog/tracing/remote.rb +50 -19
- data/lib/datadog/tracing/transport/http/telemetry.rb +94 -0
- data/lib/datadog/tracing/transport/http/traces.rb +2 -0
- data/lib/datadog/tracing/transport/native/telemetry.rb +17 -0
- data/lib/datadog/tracing/transport/native.rb +16 -1
- data/lib/datadog/tracing/transport/telemetry.rb +62 -0
- data/lib/datadog/tracing/transport/traces.rb +82 -15
- data/lib/datadog/version.rb +1 -1
- metadata +19 -10
- data/lib/datadog/appsec/utils/hash_coercion.rb +0 -23
|
@@ -21,6 +21,14 @@ module Datadog
|
|
|
21
21
|
def context=(ctx)
|
|
22
22
|
ctx.otel_thread_context = @otel_thread_context if ctx.respond_to?(:otel_thread_context=)
|
|
23
23
|
|
|
24
|
+
if (otel_thread_context = @otel_thread_context)
|
|
25
|
+
if (trace = ctx&.active_trace)
|
|
26
|
+
otel_thread_context.update_from_trace_op(trace)
|
|
27
|
+
else
|
|
28
|
+
otel_thread_context.clear
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
24
32
|
@context.local = ctx
|
|
25
33
|
end
|
|
26
34
|
|
|
@@ -7,6 +7,7 @@ require_relative "../../metadata/ext"
|
|
|
7
7
|
require_relative "../http"
|
|
8
8
|
require_relative "ext"
|
|
9
9
|
require_relative "../http_annotation_helper"
|
|
10
|
+
require_relative "../utils/quantization/http"
|
|
10
11
|
|
|
11
12
|
module Datadog
|
|
12
13
|
module Tracing
|
|
@@ -111,7 +112,7 @@ module Datadog
|
|
|
111
112
|
)
|
|
112
113
|
datadog_trace = Tracing.active_trace
|
|
113
114
|
|
|
114
|
-
datadog_tag_request
|
|
115
|
+
datadog_tag_request(uri)
|
|
115
116
|
|
|
116
117
|
if Tracing::Distributed::PropagationPolicy.enabled?(
|
|
117
118
|
global_config: datadog_configuration,
|
|
@@ -131,12 +132,17 @@ module Datadog
|
|
|
131
132
|
|
|
132
133
|
attr_reader :datadog_configuration
|
|
133
134
|
|
|
134
|
-
def datadog_tag_request
|
|
135
|
+
def datadog_tag_request(uri)
|
|
135
136
|
span = @datadog_span
|
|
136
137
|
span.set_tag(Tracing::Metadata::Ext::TAG_SVC_SRC, Ext::TAG_COMPONENT)
|
|
137
138
|
method = Ext::NOT_APPLICABLE_METHOD
|
|
138
139
|
method = @datadog_method.to_s if instance_variable_defined?(:@datadog_method) && !@datadog_method.nil?
|
|
139
|
-
|
|
140
|
+
path = uri&.path
|
|
141
|
+
span.resource = Contrib::Utils::Quantization::HTTP.client_resource(
|
|
142
|
+
method,
|
|
143
|
+
path,
|
|
144
|
+
enabled: Datadog.configuration.tracing.http_client_resource_name_quantize
|
|
145
|
+
)
|
|
140
146
|
|
|
141
147
|
if datadog_configuration[:peer_service]
|
|
142
148
|
span.set_tag(
|
|
@@ -153,10 +159,9 @@ module Datadog
|
|
|
153
159
|
|
|
154
160
|
span.set_tag(Tracing::Metadata::Ext::TAG_KIND, Tracing::Metadata::Ext::SpanKind::TAG_CLIENT)
|
|
155
161
|
|
|
156
|
-
uri = try_parse_uri
|
|
157
162
|
return unless uri
|
|
158
163
|
|
|
159
|
-
span.set_tag(Tracing::Metadata::Ext::HTTP::TAG_URL,
|
|
164
|
+
span.set_tag(Tracing::Metadata::Ext::HTTP::TAG_URL, path)
|
|
160
165
|
span.set_tag(Tracing::Metadata::Ext::HTTP::TAG_METHOD, method)
|
|
161
166
|
span.set_tag(Tracing::Metadata::Ext::NET::TAG_TARGET_HOST, uri.host)
|
|
162
167
|
span.set_tag(Tracing::Metadata::Ext::NET::TAG_TARGET_PORT, uri.port)
|
|
@@ -8,6 +8,7 @@ require_relative "../http"
|
|
|
8
8
|
require_relative "../analytics"
|
|
9
9
|
require_relative "ext"
|
|
10
10
|
require_relative "../http_annotation_helper"
|
|
11
|
+
require_relative "../utils/quantization/http"
|
|
11
12
|
|
|
12
13
|
module Datadog
|
|
13
14
|
module Tracing
|
|
@@ -117,7 +118,13 @@ module Datadog
|
|
|
117
118
|
end
|
|
118
119
|
|
|
119
120
|
def annotate!(span, datum)
|
|
120
|
-
|
|
121
|
+
http_method = datum[:method].to_s.upcase
|
|
122
|
+
path = datum[:path]
|
|
123
|
+
span.resource = Contrib::Utils::Quantization::HTTP.client_resource(
|
|
124
|
+
http_method,
|
|
125
|
+
path,
|
|
126
|
+
enabled: Datadog.configuration.tracing.http_client_resource_name_quantize
|
|
127
|
+
)
|
|
121
128
|
span.service = service_name(datum[:host], @options)
|
|
122
129
|
span.set_tag(Tracing::Metadata::Ext::TAG_SVC_SRC, Ext::TAG_COMPONENT)
|
|
123
130
|
span.type = Tracing::Metadata::Ext::HTTP::TYPE_OUTBOUND
|
|
@@ -139,8 +146,8 @@ module Datadog
|
|
|
139
146
|
# Set analytics sample rate
|
|
140
147
|
Contrib::Analytics.set_sample_rate(span, analytics_sample_rate) if analytics_enabled?
|
|
141
148
|
|
|
142
|
-
span.set_tag(Tracing::Metadata::Ext::HTTP::TAG_URL,
|
|
143
|
-
span.set_tag(Tracing::Metadata::Ext::HTTP::TAG_METHOD,
|
|
149
|
+
span.set_tag(Tracing::Metadata::Ext::HTTP::TAG_URL, path)
|
|
150
|
+
span.set_tag(Tracing::Metadata::Ext::HTTP::TAG_METHOD, http_method)
|
|
144
151
|
span.set_tag(Tracing::Metadata::Ext::NET::TAG_TARGET_HOST, datum[:host])
|
|
145
152
|
span.set_tag(Tracing::Metadata::Ext::NET::TAG_TARGET_PORT, datum[:port])
|
|
146
153
|
span.set_tags(
|
|
@@ -7,6 +7,7 @@ require_relative "../http"
|
|
|
7
7
|
require_relative "../analytics"
|
|
8
8
|
require_relative "ext"
|
|
9
9
|
require_relative "../http_annotation_helper"
|
|
10
|
+
require_relative "../utils/quantization/http"
|
|
10
11
|
require_relative "../../../core/telemetry/logger"
|
|
11
12
|
|
|
12
13
|
module Datadog
|
|
@@ -45,7 +46,8 @@ module Datadog
|
|
|
45
46
|
|
|
46
47
|
# rubocop:disable Metrics/AbcSize
|
|
47
48
|
def annotate!(span, env, options)
|
|
48
|
-
|
|
49
|
+
path = env[:url].path
|
|
50
|
+
span.resource = resource_name(env, path)
|
|
49
51
|
span.service = service_name(env[:url].host, options)
|
|
50
52
|
span.set_tag(Tracing::Metadata::Ext::TAG_SVC_SRC, Ext::TAG_COMPONENT)
|
|
51
53
|
span.type = Tracing::Metadata::Ext::HTTP::TYPE_OUTBOUND
|
|
@@ -69,7 +71,7 @@ module Datadog
|
|
|
69
71
|
Contrib::Analytics.set_sample_rate(span, options[:analytics_sample_rate])
|
|
70
72
|
end
|
|
71
73
|
|
|
72
|
-
span.set_tag(Tracing::Metadata::Ext::HTTP::TAG_URL,
|
|
74
|
+
span.set_tag(Tracing::Metadata::Ext::HTTP::TAG_URL, path)
|
|
73
75
|
span.set_tag(Tracing::Metadata::Ext::HTTP::TAG_METHOD, env[:method].to_s.upcase)
|
|
74
76
|
span.set_tag(Tracing::Metadata::Ext::NET::TAG_TARGET_HOST, env[:url].host)
|
|
75
77
|
span.set_tag(Tracing::Metadata::Ext::NET::TAG_TARGET_PORT, env[:url].port)
|
|
@@ -103,8 +105,12 @@ module Datadog
|
|
|
103
105
|
Contrib::HTTP.inject(trace, env[:request_headers])
|
|
104
106
|
end
|
|
105
107
|
|
|
106
|
-
def resource_name(env)
|
|
107
|
-
|
|
108
|
+
def resource_name(env, path)
|
|
109
|
+
Contrib::Utils::Quantization::HTTP.client_resource(
|
|
110
|
+
env[:method].to_s.upcase,
|
|
111
|
+
path,
|
|
112
|
+
enabled: Datadog.configuration.tracing.http_client_resource_name_quantize
|
|
113
|
+
)
|
|
108
114
|
end
|
|
109
115
|
|
|
110
116
|
def build_request_options!(env)
|
|
@@ -34,7 +34,12 @@ module Datadog
|
|
|
34
34
|
span.service = service_name(host, request_options, client_config)
|
|
35
35
|
span.set_tag(Tracing::Metadata::Ext::TAG_SVC_SRC, Ext::TAG_COMPONENT)
|
|
36
36
|
span.type = Tracing::Metadata::Ext::HTTP::TYPE_OUTBOUND
|
|
37
|
-
|
|
37
|
+
quantize_resource = Datadog.configuration.tracing.http_client_resource_name_quantize
|
|
38
|
+
span.resource = Contrib::Utils::Quantization::HTTP.client_resource(
|
|
39
|
+
req.method,
|
|
40
|
+
quantize_resource ? request_uri_path(req) : nil,
|
|
41
|
+
enabled: quantize_resource
|
|
42
|
+
)
|
|
38
43
|
|
|
39
44
|
if Tracing::Distributed::PropagationPolicy.enabled?(
|
|
40
45
|
pin_config: client_config,
|
|
@@ -116,6 +121,16 @@ module Datadog
|
|
|
116
121
|
|
|
117
122
|
private
|
|
118
123
|
|
|
124
|
+
def request_uri_path(request)
|
|
125
|
+
uri = request.uri if request.respond_to?(:uri)
|
|
126
|
+
return uri.path if uri
|
|
127
|
+
return request.path.split(/[?#]/, 2).first if request.path.start_with?("/")
|
|
128
|
+
|
|
129
|
+
URI.parse(request.path).path
|
|
130
|
+
rescue URI::InvalidURIError
|
|
131
|
+
nil
|
|
132
|
+
end
|
|
133
|
+
|
|
119
134
|
def host_and_port(request)
|
|
120
135
|
if request.respond_to?(:uri) && request.uri
|
|
121
136
|
[request.uri.host, request.uri.port]
|
|
@@ -4,6 +4,7 @@ require_relative "../../metadata/ext"
|
|
|
4
4
|
require_relative "../http"
|
|
5
5
|
require_relative "../analytics"
|
|
6
6
|
require_relative "../http_annotation_helper"
|
|
7
|
+
require_relative "../utils/quantization/http"
|
|
7
8
|
require_relative "../../../core/telemetry/logger"
|
|
8
9
|
|
|
9
10
|
module Datadog
|
|
@@ -74,10 +75,15 @@ module Datadog
|
|
|
74
75
|
|
|
75
76
|
http_method = req.header.request_method.upcase
|
|
76
77
|
uri = req.header.request_uri
|
|
78
|
+
path = uri.path
|
|
77
79
|
|
|
78
|
-
span.resource =
|
|
80
|
+
span.resource = Contrib::Utils::Quantization::HTTP.client_resource(
|
|
81
|
+
http_method,
|
|
82
|
+
path,
|
|
83
|
+
enabled: Datadog.configuration.tracing.http_client_resource_name_quantize
|
|
84
|
+
)
|
|
79
85
|
span.set_tag(Tracing::Metadata::Ext::HTTP::TAG_METHOD, http_method)
|
|
80
|
-
span.set_tag(Tracing::Metadata::Ext::HTTP::TAG_URL,
|
|
86
|
+
span.set_tag(Tracing::Metadata::Ext::HTTP::TAG_URL, path)
|
|
81
87
|
span.set_tag(Tracing::Metadata::Ext::NET::TAG_TARGET_HOST, uri.host)
|
|
82
88
|
span.set_tag(Tracing::Metadata::Ext::NET::TAG_TARGET_PORT, uri.port)
|
|
83
89
|
|
|
@@ -4,6 +4,7 @@ require_relative "../../metadata/ext"
|
|
|
4
4
|
require_relative "../http"
|
|
5
5
|
require_relative "../analytics"
|
|
6
6
|
require_relative "../http_annotation_helper"
|
|
7
|
+
require_relative "../utils/quantization/http"
|
|
7
8
|
require_relative "../../../core/telemetry/logger"
|
|
8
9
|
|
|
9
10
|
module Datadog
|
|
@@ -70,17 +71,22 @@ module Datadog
|
|
|
70
71
|
span.set_tag(Tracing::Metadata::Ext::TAG_COMPONENT, Ext::TAG_COMPONENT)
|
|
71
72
|
span.set_tag(Tracing::Metadata::Ext::TAG_OPERATION, Ext::TAG_OPERATION_REQUEST)
|
|
72
73
|
|
|
74
|
+
uri = req.uri
|
|
75
|
+
path = uri&.path
|
|
73
76
|
if req.verb&.is_a?(String) || req.verb.is_a?(Symbol)
|
|
74
77
|
http_method = req.verb.to_s.upcase
|
|
75
|
-
span.resource =
|
|
78
|
+
span.resource = Contrib::Utils::Quantization::HTTP.client_resource(
|
|
79
|
+
http_method,
|
|
80
|
+
path,
|
|
81
|
+
enabled: Datadog.configuration.tracing.http_client_resource_name_quantize
|
|
82
|
+
)
|
|
76
83
|
span.set_tag(Tracing::Metadata::Ext::HTTP::TAG_METHOD, http_method)
|
|
77
84
|
else
|
|
78
85
|
logger.debug("service #{req_options[:service_name]} span #{Ext::SPAN_REQUEST} missing request verb")
|
|
79
86
|
end
|
|
80
87
|
|
|
81
|
-
if
|
|
82
|
-
|
|
83
|
-
span.set_tag(Tracing::Metadata::Ext::HTTP::TAG_URL, uri.path)
|
|
88
|
+
if uri
|
|
89
|
+
span.set_tag(Tracing::Metadata::Ext::HTTP::TAG_URL, path)
|
|
84
90
|
span.set_tag(Tracing::Metadata::Ext::NET::TAG_TARGET_HOST, uri.host)
|
|
85
91
|
span.set_tag(Tracing::Metadata::Ext::NET::TAG_TARGET_PORT, uri.port)
|
|
86
92
|
|
|
@@ -6,6 +6,7 @@ require_relative "../../metadata/ext"
|
|
|
6
6
|
require_relative "../http"
|
|
7
7
|
require_relative "../analytics"
|
|
8
8
|
require_relative "ext"
|
|
9
|
+
require_relative "../utils/quantization/http"
|
|
9
10
|
|
|
10
11
|
module Datadog
|
|
11
12
|
module Tracing
|
|
@@ -38,7 +39,13 @@ module Datadog
|
|
|
38
39
|
|
|
39
40
|
def datadog_tag_request(uri, span)
|
|
40
41
|
span.set_tag(Tracing::Metadata::Ext::TAG_SVC_SRC, Ext::TAG_COMPONENT)
|
|
41
|
-
|
|
42
|
+
http_method = method.to_s.upcase
|
|
43
|
+
path = uri.path
|
|
44
|
+
span.resource = Contrib::Utils::Quantization::HTTP.client_resource(
|
|
45
|
+
http_method,
|
|
46
|
+
path,
|
|
47
|
+
enabled: Datadog.configuration.tracing.http_client_resource_name_quantize
|
|
48
|
+
)
|
|
42
49
|
|
|
43
50
|
if datadog_configuration[:peer_service]
|
|
44
51
|
span.set_tag(
|
|
@@ -57,8 +64,8 @@ module Datadog
|
|
|
57
64
|
# Set analytics sample rate
|
|
58
65
|
Contrib::Analytics.set_sample_rate(span, analytics_sample_rate) if analytics_enabled?
|
|
59
66
|
|
|
60
|
-
span.set_tag(Tracing::Metadata::Ext::HTTP::TAG_URL,
|
|
61
|
-
span.set_tag(Tracing::Metadata::Ext::HTTP::TAG_METHOD,
|
|
67
|
+
span.set_tag(Tracing::Metadata::Ext::HTTP::TAG_URL, path)
|
|
68
|
+
span.set_tag(Tracing::Metadata::Ext::HTTP::TAG_METHOD, http_method)
|
|
62
69
|
span.set_tag(Tracing::Metadata::Ext::NET::TAG_TARGET_HOST, uri.host)
|
|
63
70
|
span.set_tag(Tracing::Metadata::Ext::NET::TAG_TARGET_PORT, uri.port)
|
|
64
71
|
span.set_tags(
|
|
@@ -20,6 +20,96 @@ module Datadog
|
|
|
20
20
|
|
|
21
21
|
module_function
|
|
22
22
|
|
|
23
|
+
def client_resource(method, path, enabled:)
|
|
24
|
+
return method unless enabled && path
|
|
25
|
+
|
|
26
|
+
resource = method.dup
|
|
27
|
+
resource << (+" ").force_encoding(resource.encoding)
|
|
28
|
+
quantized_path = quantize_path(decode_path(path))
|
|
29
|
+
resource << quantized_path.force_encoding(resource.encoding)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def decode_path(path)
|
|
33
|
+
decoded = String.new(encoding: Encoding::BINARY)
|
|
34
|
+
index = 0
|
|
35
|
+
|
|
36
|
+
while index < path.bytesize
|
|
37
|
+
byte = path.getbyte(index)
|
|
38
|
+
break unless byte
|
|
39
|
+
|
|
40
|
+
if byte == 37 && index + 2 < path.bytesize
|
|
41
|
+
high_byte = path.getbyte(index + 1)
|
|
42
|
+
low_byte = path.getbyte(index + 2)
|
|
43
|
+
if high_byte && low_byte
|
|
44
|
+
high = decode_hex_byte(high_byte)
|
|
45
|
+
low = decode_hex_byte(low_byte)
|
|
46
|
+
if high && low
|
|
47
|
+
decoded << high * 16 + low
|
|
48
|
+
index += 3
|
|
49
|
+
next
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
decoded << byte
|
|
55
|
+
index += 1
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
decoded.force_encoding(path.encoding)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def quantize_path(path)
|
|
62
|
+
slash = (+"/").force_encoding(path.encoding)
|
|
63
|
+
normalized = if path.getbyte(0) == 47
|
|
64
|
+
path
|
|
65
|
+
else
|
|
66
|
+
String.new(encoding: path.encoding) << slash << path
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
output = String.new(encoding: path.encoding)
|
|
70
|
+
index = 1
|
|
71
|
+
replacements = 0
|
|
72
|
+
|
|
73
|
+
while index < normalized.bytesize
|
|
74
|
+
segment_end = index
|
|
75
|
+
allowed = 0
|
|
76
|
+
digits = 0
|
|
77
|
+
specials = 0
|
|
78
|
+
|
|
79
|
+
while segment_end < normalized.bytesize && normalized.getbyte(segment_end) != 47
|
|
80
|
+
byte = normalized.getbyte(segment_end)
|
|
81
|
+
break unless byte
|
|
82
|
+
|
|
83
|
+
if byte.between?(48, 57)
|
|
84
|
+
digits += 1
|
|
85
|
+
elsif byte.between?(65, 90) || byte.between?(97, 122) || byte == 45 || byte == 95
|
|
86
|
+
allowed += 1
|
|
87
|
+
else
|
|
88
|
+
specials += 1
|
|
89
|
+
end
|
|
90
|
+
segment_end += 1
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
output << slash
|
|
94
|
+
segment = normalized.byteslice(index, segment_end - index) || String.new(encoding: path.encoding)
|
|
95
|
+
if normalized.getbyte(index) == 118 && allowed == 1 && digits > 0 && specials.zero?
|
|
96
|
+
output << segment
|
|
97
|
+
elsif specials > 0 || digits > 0
|
|
98
|
+
output << (+"*").force_encoding(path.encoding)
|
|
99
|
+
replacements += 1
|
|
100
|
+
else
|
|
101
|
+
output << segment
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
index = segment_end + 1
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
return normalized.dup if replacements.zero?
|
|
108
|
+
|
|
109
|
+
output << slash if normalized.getbyte(normalized.bytesize - 1) == 47
|
|
110
|
+
output
|
|
111
|
+
end
|
|
112
|
+
|
|
23
113
|
def url(url, options = {})
|
|
24
114
|
url!(url, options)
|
|
25
115
|
rescue
|
|
@@ -118,6 +208,18 @@ module Datadog
|
|
|
118
208
|
|
|
119
209
|
private_class_method :collect_query
|
|
120
210
|
|
|
211
|
+
def decode_hex_byte(byte)
|
|
212
|
+
if byte.between?(48, 57)
|
|
213
|
+
byte - 48
|
|
214
|
+
elsif byte.between?(65, 70)
|
|
215
|
+
byte - 55
|
|
216
|
+
elsif byte.between?(97, 102)
|
|
217
|
+
byte - 87
|
|
218
|
+
end
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
private_class_method :decode_hex_byte
|
|
222
|
+
|
|
121
223
|
# Scans over the query string and obfuscates sensitive data by
|
|
122
224
|
# replacing matches with an opaque value
|
|
123
225
|
def obfuscate_query(query, options = {})
|
|
@@ -14,9 +14,11 @@ module Datadog
|
|
|
14
14
|
|
|
15
15
|
def self.build(tracing_settings)
|
|
16
16
|
return unless tracing_settings.otel_thread_context_enabled
|
|
17
|
+
return unless Datadog::Core::LIBDATADOG_API_FAILURE.nil?
|
|
17
18
|
|
|
18
19
|
instance = new
|
|
19
|
-
instance
|
|
20
|
+
instance._native_enable
|
|
21
|
+
instance
|
|
20
22
|
end
|
|
21
23
|
|
|
22
24
|
def initialize
|
|
@@ -65,10 +67,6 @@ module Datadog
|
|
|
65
67
|
false
|
|
66
68
|
end
|
|
67
69
|
|
|
68
|
-
def supported?
|
|
69
|
-
Datadog::Core::LIBDATADOG_API_FAILURE.nil? && _native_supported?
|
|
70
|
-
end
|
|
71
|
-
|
|
72
70
|
def update_from_trace_op(trace_op)
|
|
73
71
|
active_span = trace_op.active_span
|
|
74
72
|
|
|
@@ -62,6 +62,8 @@ module Datadog
|
|
|
62
62
|
|
|
63
63
|
# @type var parsed: Array[[::Datadog::Core::Remote::Configuration::Content, ::Hash[::String, untyped]]]
|
|
64
64
|
parsed = []
|
|
65
|
+
# @type var unparseable_contents: Array[Datadog::Core::Remote::Configuration::Content]
|
|
66
|
+
unparseable_contents = []
|
|
65
67
|
repository.contents.each do |content|
|
|
66
68
|
next unless content.path.product == PRODUCT
|
|
67
69
|
|
|
@@ -76,9 +78,8 @@ module Datadog
|
|
|
76
78
|
# A present but non-object lib_config (e.g. {"lib_config": []}) is a
|
|
77
79
|
# schema violation the customer can fix. Acknowledging it as applied
|
|
78
80
|
# would tell the backend the config was successfully applied when it
|
|
79
|
-
# was not
|
|
80
|
-
#
|
|
81
|
-
# payload is reported errored instead. A null or absent lib_config
|
|
81
|
+
# was not. Reject it per content so the malformed payload is
|
|
82
|
+
# reported errored instead. A null or absent lib_config
|
|
82
83
|
# carries no overrides and is left as a no-op.
|
|
83
84
|
lib_config = config["lib_config"]
|
|
84
85
|
if !lib_config.nil? && !lib_config.is_a?(Hash)
|
|
@@ -92,6 +93,7 @@ module Datadog
|
|
|
92
93
|
description: "Failed to parse APM_TRACING remote config",
|
|
93
94
|
)
|
|
94
95
|
content.errored("#{e.class}: #{e.message}: #{Array(e.backtrace).join("\n")}")
|
|
96
|
+
unparseable_contents << content
|
|
95
97
|
end
|
|
96
98
|
end
|
|
97
99
|
|
|
@@ -117,10 +119,26 @@ module Datadog
|
|
|
117
119
|
# deterministic merge.
|
|
118
120
|
ordered = applicable.sort_by { |content, config| [-config_priority(config), content.path.config_id] }
|
|
119
121
|
merged = merge_lib_configs(ordered.map { |_content, config| config })
|
|
122
|
+
# The applicable configs carrying a non-null dynamic_instrumentation_enabled
|
|
123
|
+
# value: any of their paths can still supply the signal after a later
|
|
124
|
+
# replacement, so the DI component records them all.
|
|
125
|
+
# @type var enable_signal_paths: Array[Datadog::Core::Remote::Configuration::Path]
|
|
126
|
+
enable_signal_paths = Core::Utils::EnumerableCompat.filter_map(ordered) do |pair|
|
|
127
|
+
content, config = pair
|
|
128
|
+
lib_config = config["lib_config"]
|
|
129
|
+
if lib_config.is_a?(Hash) && !lib_config["dynamic_instrumentation_enabled"].nil?
|
|
130
|
+
content.path
|
|
131
|
+
end
|
|
132
|
+
end
|
|
120
133
|
|
|
121
134
|
# Applied even when the set is empty: an emptied repository (last config
|
|
122
135
|
# removed) reverts the tracing overrides to their non-RC values.
|
|
123
|
-
apply_lib_config(
|
|
136
|
+
apply_lib_config(
|
|
137
|
+
merged,
|
|
138
|
+
repository,
|
|
139
|
+
unparseable_contents: unparseable_contents,
|
|
140
|
+
enable_signal_paths: enable_signal_paths,
|
|
141
|
+
)
|
|
124
142
|
|
|
125
143
|
parsed.each { |content, _config| content.applied }
|
|
126
144
|
nil
|
|
@@ -205,8 +223,10 @@ module Datadog
|
|
|
205
223
|
#
|
|
206
224
|
# @param lib_config [Hash[String, untyped]] the lib_config to apply
|
|
207
225
|
# @param repository [Core::Remote::Configuration::Repository, nil] forwarded to DI enablement
|
|
226
|
+
# @param unparseable_contents [Array<Core::Remote::Configuration::Content>] the APM_TRACING contents that failed to parse
|
|
227
|
+
# @param enable_signal_paths [Array<Core::Remote::Configuration::Path>] the paths of the applicable configs carrying the field
|
|
208
228
|
# @return [nil]
|
|
209
|
-
def apply_lib_config(lib_config, repository)
|
|
229
|
+
def apply_lib_config(lib_config, repository, unparseable_contents:, enable_signal_paths:)
|
|
210
230
|
env_vars = Datadog::Tracing::Configuration::Dynamic::OPTIONS.map do |name, env_var, option|
|
|
211
231
|
value = lib_config[name]
|
|
212
232
|
|
|
@@ -218,13 +238,30 @@ module Datadog
|
|
|
218
238
|
[env_var, telemetry_value]
|
|
219
239
|
end
|
|
220
240
|
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
241
|
+
di_enabled = lib_config["dynamic_instrumentation_enabled"]
|
|
242
|
+
# allow_initialization: false because this runs on the remote-config worker
|
|
243
|
+
# thread, and the default would build the component tree from that thread.
|
|
244
|
+
components = Datadog.send(:components, allow_initialization: false)
|
|
245
|
+
di_component = components&.dynamic_instrumentation
|
|
246
|
+
if di_enabled.nil? && di_component&.rc_enablement_signal_withdrawn?(unparseable_contents)
|
|
247
|
+
di_enabled = false
|
|
248
|
+
end
|
|
249
|
+
|
|
250
|
+
# Records the parsed carrier paths and the previously recorded paths whose
|
|
251
|
+
# replacements remain unparseable, on every merge including merges that keep
|
|
252
|
+
# the DI state.
|
|
253
|
+
if di_component
|
|
254
|
+
unparseable_recorded_paths = di_component.rc_enablement_signal_paths.select do |path|
|
|
255
|
+
unparseable_contents.any? { |content| content.path == path }
|
|
256
|
+
end
|
|
257
|
+
di_component.record_rc_enablement_signal_paths(enable_signal_paths + unparseable_recorded_paths)
|
|
258
|
+
end
|
|
259
|
+
|
|
260
|
+
unless di_enabled.nil?
|
|
261
|
+
# repository is forwarded for the stopped->started replay in
|
|
262
|
+
# Datadog::DI::Remote.handle_rc_enablement.
|
|
225
263
|
Datadog::DI::Remote.handle_rc_enablement(di_enabled, repository)
|
|
226
264
|
|
|
227
|
-
components = Datadog.send(:components, allow_initialization: false)
|
|
228
265
|
di_products = Datadog::DI::Remote.products +
|
|
229
266
|
Datadog::SymbolDatabase::Remote.deferred_products(Datadog.configuration)
|
|
230
267
|
|
|
@@ -236,7 +273,7 @@ module Datadog
|
|
|
236
273
|
# by DD_DYNAMIC_INSTRUMENTATION_ENABLED=false. Advertising then would
|
|
237
274
|
# report DI as in use when it is not and invite probe configs the
|
|
238
275
|
# tracer must refuse; withdraw the products otherwise.
|
|
239
|
-
if
|
|
276
|
+
if di_component&.started?
|
|
240
277
|
components&.remote&.add_products(*di_products)
|
|
241
278
|
else
|
|
242
279
|
components&.remote&.remove_products(*di_products)
|
|
@@ -249,13 +286,7 @@ module Datadog
|
|
|
249
286
|
Datadog.logger.debug { "APM_TRACING RC: merged dynamic_instrumentation_enabled=#{di_enabled}" }
|
|
250
287
|
end
|
|
251
288
|
|
|
252
|
-
|
|
253
|
-
# worker thread. If components haven't been built yet (e.g. during a
|
|
254
|
-
# teardown/reset window), the default value would synchronously build
|
|
255
|
-
# the entire component tree from this thread. The &. chain matches the
|
|
256
|
-
# pattern used by DI::Remote.handle_rc_enablement in the same dispatch
|
|
257
|
-
# path.
|
|
258
|
-
Datadog.send(:components, allow_initialization: false)&.telemetry&.client_configuration_change!(env_vars)
|
|
289
|
+
components&.telemetry&.client_configuration_change!(env_vars)
|
|
259
290
|
nil
|
|
260
291
|
end
|
|
261
292
|
|
|
@@ -269,7 +300,7 @@ module Datadog
|
|
|
269
300
|
|
|
270
301
|
def receiver(products = [PRODUCT], &block)
|
|
271
302
|
matcher = Core::Remote::Dispatcher::Matcher::Product.new(products)
|
|
272
|
-
[Core::Remote::Dispatcher::Receiver.new(matcher, &block)]
|
|
303
|
+
[Core::Remote::Dispatcher::Receiver.new(matcher, initial_reconcile: true, &block)]
|
|
273
304
|
end
|
|
274
305
|
|
|
275
306
|
private
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "net/http"
|
|
4
|
+
require_relative "../telemetry"
|
|
5
|
+
|
|
6
|
+
module Datadog
|
|
7
|
+
module Tracing
|
|
8
|
+
module Transport
|
|
9
|
+
module HTTP
|
|
10
|
+
class Telemetry < Datadog::Tracing::Transport::Telemetry
|
|
11
|
+
def initialize(client)
|
|
12
|
+
super(client, source: "ruby")
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def batch(traces)
|
|
16
|
+
return unless @client.enabled? && @client.metrics_manager.enabled
|
|
17
|
+
|
|
18
|
+
Batch.new(self, traces)
|
|
19
|
+
rescue
|
|
20
|
+
nil
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
class Batch
|
|
24
|
+
def initialize(reporter, traces)
|
|
25
|
+
@reporter = reporter
|
|
26
|
+
@remaining_chunks = traces.length
|
|
27
|
+
@remaining_spans = traces.sum(&:length)
|
|
28
|
+
@reporter.record(spans_enqueued_for_serialization: @remaining_spans)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def record_oversized_drop(span_count)
|
|
32
|
+
@remaining_chunks -= 1
|
|
33
|
+
@remaining_spans -= span_count
|
|
34
|
+
@reporter.record(chunks_dropped_payload_too_large: 1, spans_dropped_payload_too_large: span_count)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def serialization_failed
|
|
38
|
+
@reporter.record(chunks_dropped_serialization_error: @remaining_chunks,
|
|
39
|
+
spans_dropped_serialization_error: @remaining_spans,)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def sent(request, response, chunks, spans, bytes, fallback:)
|
|
43
|
+
@reporter.record(requests_count: 1)
|
|
44
|
+
return if fallback
|
|
45
|
+
|
|
46
|
+
@remaining_chunks -= chunks
|
|
47
|
+
@remaining_spans -= spans
|
|
48
|
+
observations = {} #: Hash[Symbol, Integer]
|
|
49
|
+
if (status = request.http_status)
|
|
50
|
+
observations[:responses_count] = 1
|
|
51
|
+
observations[:status_code] = status
|
|
52
|
+
end
|
|
53
|
+
success = status ? status.between?(200, 299) : request.http_success
|
|
54
|
+
if success
|
|
55
|
+
observations[:chunks_sent] = chunks
|
|
56
|
+
observations[:bytes_sent] = bytes
|
|
57
|
+
elsif status || success == false
|
|
58
|
+
observations[:errors_status_code] = 1 if status
|
|
59
|
+
observations[:chunks_dropped_send_failure] = chunks
|
|
60
|
+
observations[:spans_dropped_api_error] = spans
|
|
61
|
+
elsif response.is_a?(Core::Transport::InternalErrorResponse)
|
|
62
|
+
error = response.error
|
|
63
|
+
if error.is_a?(ArgumentError) || error.is_a?(TypeError)
|
|
64
|
+
observations[:chunks_dropped_serialization_error] = chunks
|
|
65
|
+
observations[:spans_dropped_serialization_error] = spans
|
|
66
|
+
else
|
|
67
|
+
observations[:chunks_dropped_send_failure] = chunks
|
|
68
|
+
observations[:spans_dropped_api_error] = spans
|
|
69
|
+
if error.is_a?(::Timeout::Error) || error.is_a?(Errno::ETIMEDOUT)
|
|
70
|
+
observations[:errors_timeout] = 1
|
|
71
|
+
elsif network_error?(error)
|
|
72
|
+
observations[:errors_network] = 1
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
@reporter.record(observations)
|
|
77
|
+
rescue
|
|
78
|
+
nil
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
private
|
|
82
|
+
|
|
83
|
+
def network_error?(error)
|
|
84
|
+
error.is_a?(SystemCallError) || error.is_a?(IOError) || error.is_a?(SocketError) ||
|
|
85
|
+
error.is_a?(::Net::ProtocolError) || error.is_a?(::Net::HTTPBadResponse) ||
|
|
86
|
+
error.is_a?(::Net::HTTPHeaderSyntaxError) ||
|
|
87
|
+
(defined?(::OpenSSL::SSL::SSLError) && error.is_a?(::OpenSSL::SSL::SSLError))
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
end
|
|
@@ -51,6 +51,8 @@ module Datadog
|
|
|
51
51
|
|
|
52
52
|
# Query for response
|
|
53
53
|
http_response = super
|
|
54
|
+
# Delivery succeeded or failed before service-rate parsing can raise.
|
|
55
|
+
env.request.capture_status(http_response)
|
|
54
56
|
|
|
55
57
|
# Process the response
|
|
56
58
|
response_options = {trace_count: env.request.parcel.trace_count}.tap do |options|
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../telemetry"
|
|
4
|
+
|
|
5
|
+
module Datadog
|
|
6
|
+
module Tracing
|
|
7
|
+
module Transport
|
|
8
|
+
module Native
|
|
9
|
+
class Telemetry < Datadog::Tracing::Transport::Telemetry
|
|
10
|
+
def initialize(client)
|
|
11
|
+
super(client, source: "libdatadog")
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|