datadog 2.32.0 → 2.34.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 +30 -1
- data/ext/datadog_profiling_native_extension/clock_id.h +9 -1
- data/ext/datadog_profiling_native_extension/clock_id_from_mach.c +73 -0
- data/ext/datadog_profiling_native_extension/clock_id_from_pthread.c +1 -1
- data/ext/datadog_profiling_native_extension/collectors_cpu_and_wall_time_worker.c +20 -0
- data/ext/datadog_profiling_native_extension/collectors_thread_context.c +5 -1
- data/ext/datadog_profiling_native_extension/extconf.rb +3 -0
- data/ext/datadog_profiling_native_extension/macos_sampler_thread.h +55 -0
- data/ext/datadog_profiling_native_extension/stack_recorder.c +3 -9
- data/ext/datadog_profiling_native_extension/time_helpers.h +1 -0
- data/ext/libdatadog_api/crashtracker.c +2 -0
- data/ext/libdatadog_extconf_helpers.rb +1 -1
- data/lib/datadog/ai_guard/autoload.rb +10 -0
- data/lib/datadog/ai_guard/component.rb +1 -1
- data/lib/datadog/ai_guard/contrib/auto_instrument.rb +24 -0
- data/lib/datadog/ai_guard/contrib/rack/integration.rb +42 -0
- data/lib/datadog/ai_guard/contrib/rack/patcher.rb +26 -0
- data/lib/datadog/ai_guard/contrib/rack/request_middleware.rb +83 -0
- data/lib/datadog/ai_guard/contrib/rails/integration.rb +41 -0
- data/lib/datadog/ai_guard/contrib/rails/patcher.rb +97 -0
- data/lib/datadog/ai_guard/evaluation.rb +1 -0
- data/lib/datadog/ai_guard/ext.rb +1 -0
- data/lib/datadog/ai_guard.rb +8 -0
- data/lib/datadog/appsec/component.rb +4 -1
- data/lib/datadog/appsec/compressed_json.rb +2 -2
- data/lib/datadog/appsec/contrib/aws_lambda/gateway/watcher.rb +75 -0
- data/lib/datadog/appsec/contrib/aws_lambda/integration.rb +39 -0
- data/lib/datadog/appsec/contrib/aws_lambda/patcher.rb +30 -0
- data/lib/datadog/appsec/contrib/aws_lambda/waf_addresses.rb +111 -0
- data/lib/datadog/appsec/contrib/rack/ext.rb +1 -1
- data/lib/datadog/appsec.rb +1 -0
- data/lib/datadog/core/configuration/components.rb +8 -1
- data/lib/datadog/core/configuration/settings.rb +16 -1
- data/lib/datadog/core/configuration/supported_configurations.rb +12 -0
- data/lib/datadog/core/environment/ext.rb +5 -0
- data/lib/datadog/core/environment/identity.rb +15 -1
- data/lib/datadog/core/environment/process.rb +48 -27
- data/lib/datadog/core/environment/socket.rb +13 -0
- data/lib/datadog/core/remote/client/capabilities.rb +11 -2
- data/lib/datadog/core/remote/transport/http/config.rb +5 -5
- data/lib/datadog/core/telemetry/request.rb +0 -2
- data/lib/datadog/core/transport/response.rb +1 -1
- data/lib/datadog/core/utils/{base64.rb → base64_codec.rb} +3 -2
- data/lib/datadog/core/utils/hash.rb +0 -23
- data/lib/datadog/core/utils/spawn_monkey_patch.rb +46 -16
- data/lib/datadog/data_streams/pathway_context.rb +3 -3
- data/lib/datadog/di/code_tracker.rb +43 -22
- data/lib/datadog/di/contrib/active_record.rb +6 -2
- data/lib/datadog/di/instrumenter.rb +24 -4
- data/lib/datadog/di/probe_notification_builder.rb +1 -1
- data/lib/datadog/di/remote.rb +4 -4
- data/lib/datadog/di/serializer.rb +5 -5
- data/lib/datadog/di/utils.rb +42 -14
- data/lib/datadog/opentelemetry/configuration/settings.rb +65 -0
- data/lib/datadog/opentelemetry/ext.rb +9 -0
- data/lib/datadog/opentelemetry/logs.rb +98 -0
- data/lib/datadog/opentelemetry/metrics.rb +10 -37
- data/lib/datadog/opentelemetry/sdk/configurator.rb +40 -0
- data/lib/datadog/opentelemetry/sdk/id_generator.rb +16 -10
- data/lib/datadog/opentelemetry/sdk/logs_exporter.rb +37 -0
- data/lib/datadog/opentelemetry/signal_configuration.rb +53 -0
- data/lib/datadog/opentelemetry.rb +1 -0
- data/lib/datadog/profiling/component.rb +0 -1
- data/lib/datadog/profiling/stack_recorder.rb +0 -4
- data/lib/datadog/symbol_database/component.rb +409 -0
- data/lib/datadog/symbol_database/configuration.rb +2 -2
- data/lib/datadog/symbol_database/extractor.rb +45 -26
- data/lib/datadog/symbol_database/remote.rb +175 -0
- data/lib/datadog/symbol_database/scope.rb +16 -12
- data/lib/datadog/symbol_database/scope_batcher.rb +288 -0
- data/lib/datadog/symbol_database/service_version.rb +15 -6
- data/lib/datadog/symbol_database/symbol.rb +6 -3
- data/lib/datadog/symbol_database/uploader.rb +65 -8
- data/lib/datadog/tracing/contrib/action_pack/action_dispatch/instrumentation.rb +8 -0
- data/lib/datadog/tracing/contrib/active_record/events/sql.rb +0 -4
- data/lib/datadog/tracing/contrib/active_support/cache/events/cache.rb +0 -4
- data/lib/datadog/tracing/contrib/active_support/cache/instrumentation.rb +0 -4
- data/lib/datadog/tracing/contrib/aws/instrumentation.rb +0 -5
- data/lib/datadog/tracing/contrib/dalli/instrumentation.rb +0 -5
- data/lib/datadog/tracing/contrib/elasticsearch/patcher.rb +0 -5
- data/lib/datadog/tracing/contrib/ethon/easy_patch.rb +0 -5
- data/lib/datadog/tracing/contrib/ethon/multi_patch.rb +0 -8
- data/lib/datadog/tracing/contrib/excon/middleware.rb +0 -5
- data/lib/datadog/tracing/contrib/ext.rb +2 -3
- data/lib/datadog/tracing/contrib/faraday/middleware.rb +0 -5
- data/lib/datadog/tracing/contrib/grpc/datadog_interceptor/client.rb +0 -5
- data/lib/datadog/tracing/contrib/grpc/datadog_interceptor/server.rb +0 -5
- data/lib/datadog/tracing/contrib/http/instrumentation.rb +0 -5
- data/lib/datadog/tracing/contrib/httpclient/instrumentation.rb +0 -5
- data/lib/datadog/tracing/contrib/httprb/instrumentation.rb +0 -5
- data/lib/datadog/tracing/contrib/mongodb/subscribers.rb +0 -5
- data/lib/datadog/tracing/contrib/mysql2/instrumentation.rb +0 -5
- data/lib/datadog/tracing/contrib/opensearch/patcher.rb +0 -5
- data/lib/datadog/tracing/contrib/pg/instrumentation.rb +0 -5
- data/lib/datadog/tracing/contrib/presto/instrumentation.rb +0 -5
- data/lib/datadog/tracing/contrib/racecar/event.rb +0 -5
- data/lib/datadog/tracing/contrib/rack/configuration/settings.rb +6 -0
- data/lib/datadog/tracing/contrib/rack/ext.rb +27 -0
- data/lib/datadog/tracing/contrib/rack/trace_proxy_middleware.rb +117 -1
- data/lib/datadog/tracing/contrib/redis/tags.rb +0 -5
- data/lib/datadog/tracing/contrib/rest_client/request_patch.rb +0 -5
- data/lib/datadog/tracing/contrib/sequel/utils.rb +0 -5
- data/lib/datadog/tracing/contrib/trilogy/instrumentation.rb +0 -5
- data/lib/datadog/tracing/distributed/datadog_tags_codec.rb +0 -13
- data/lib/datadog/tracing/distributed/trace_context.rb +0 -28
- data/lib/datadog/tracing/metadata/ext.rb +3 -0
- data/lib/datadog/tracing/span_operation.rb +13 -0
- data/lib/datadog/tracing/trace_operation.rb +22 -0
- data/lib/datadog/tracing/tracer.rb +7 -3
- data/lib/datadog/version.rb +1 -1
- metadata +27 -8
- data/ext/datadog_profiling_native_extension/clock_id_noop.c +0 -21
|
@@ -10,18 +10,17 @@ module Datadog
|
|
|
10
10
|
#
|
|
11
11
|
# @api private
|
|
12
12
|
module Process
|
|
13
|
-
#
|
|
14
|
-
#
|
|
13
|
+
# Returns a comma-separated string of normalized key:value pairs.
|
|
14
|
+
# Includes svc.user or svc.auto based on whether the service was explicitly configured.
|
|
15
|
+
# @return [String]
|
|
15
16
|
def self.serialized
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
@serialized = tags.join(',').freeze
|
|
17
|
+
tags.join(',').freeze
|
|
19
18
|
end
|
|
20
19
|
|
|
21
|
-
#
|
|
22
|
-
#
|
|
20
|
+
# Returns an array of normalized key:value pair strings.
|
|
21
|
+
# Includes svc.user or svc.auto based on whether the service was explicitly configured.
|
|
22
|
+
# @return [Array<String>]
|
|
23
23
|
def self.tags
|
|
24
|
-
return @tags if defined?(@tags)
|
|
25
24
|
tags = []
|
|
26
25
|
|
|
27
26
|
workdir = TagNormalizer.normalize_process_value(entrypoint_workdir.to_s)
|
|
@@ -35,17 +34,44 @@ module Datadog
|
|
|
35
34
|
|
|
36
35
|
tags << "#{Environment::Ext::TAG_ENTRYPOINT_TYPE}:#{TagNormalizer.normalize(entrypoint_type, remove_digit_start_char: false)}"
|
|
37
36
|
|
|
38
|
-
|
|
39
|
-
tags << "#{Environment::Ext::TAG_RAILS_APPLICATION}:#{
|
|
37
|
+
rails_name = TagNormalizer.normalize_process_value(@rails_application_name.to_s)
|
|
38
|
+
tags << "#{Environment::Ext::TAG_RAILS_APPLICATION}:#{rails_name}" unless rails_name.empty?
|
|
39
|
+
|
|
40
|
+
if defined?(@service_user_configured)
|
|
41
|
+
if @service_user_configured
|
|
42
|
+
tags << "#{Environment::Ext::TAG_SVC_USER}:true"
|
|
43
|
+
else
|
|
44
|
+
svc = TagNormalizer.normalize_process_value(@service_name.to_s)
|
|
45
|
+
tags << "#{Environment::Ext::TAG_SVC_AUTO}:#{svc}" unless svc.empty?
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
tags.freeze
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# Called via after_set on option :service in settings.rb whenever the service value changes.
|
|
53
|
+
# @param name [String] the service name
|
|
54
|
+
# @param user_configured [Boolean] whether the service was explicitly set by the user
|
|
55
|
+
# @return [void]
|
|
56
|
+
def self.set_service(name, user_configured:)
|
|
57
|
+
@service_name = name
|
|
58
|
+
@service_user_configured = user_configured
|
|
59
|
+
end
|
|
40
60
|
|
|
41
|
-
|
|
61
|
+
# Sets the rails application name from other places in code
|
|
62
|
+
# @param name [String] the rails application name
|
|
63
|
+
# @return [void]
|
|
64
|
+
def self.rails_application_name=(name)
|
|
65
|
+
@rails_application_name = name
|
|
42
66
|
end
|
|
43
67
|
|
|
44
68
|
# Returns the last segment of the working directory of the process
|
|
45
69
|
# Example: /app/myapp -> myapp
|
|
46
70
|
# @return [String] the last segment of the working directory
|
|
47
71
|
def self.entrypoint_workdir
|
|
48
|
-
|
|
72
|
+
return @entrypoint_workdir if defined?(@entrypoint_workdir)
|
|
73
|
+
|
|
74
|
+
@entrypoint_workdir = File.basename(Dir.pwd)
|
|
49
75
|
end
|
|
50
76
|
|
|
51
77
|
# Returns the entrypoint type of the process
|
|
@@ -55,10 +81,10 @@ module Datadog
|
|
|
55
81
|
Environment::Ext::PROCESS_TYPE
|
|
56
82
|
end
|
|
57
83
|
|
|
58
|
-
# Returns the
|
|
84
|
+
# Returns the basename of the script being run
|
|
59
85
|
# Example 1: /bin/mybin -> mybin
|
|
60
|
-
# Example 2: ruby /test/myapp.rb -> myapp
|
|
61
|
-
# @return [String] the
|
|
86
|
+
# Example 2: ruby /test/myapp.rb -> myapp.rb
|
|
87
|
+
# @return [String] the basename of the script
|
|
62
88
|
#
|
|
63
89
|
# @note Determining true entrypoint name is rather complicated. This method
|
|
64
90
|
# is the initial implementation but it does not produce optimal output in all cases.
|
|
@@ -66,12 +92,14 @@ module Datadog
|
|
|
66
92
|
# as their entrypoint name.
|
|
67
93
|
# We might improve the behavior in the future if there is customer demand for it.
|
|
68
94
|
def self.entrypoint_name
|
|
69
|
-
|
|
95
|
+
return @entrypoint_name if defined?(@entrypoint_name)
|
|
96
|
+
|
|
97
|
+
@entrypoint_name = File.basename($0)
|
|
70
98
|
end
|
|
71
99
|
|
|
72
|
-
# Returns the last segment of the
|
|
100
|
+
# Returns the last segment of the directory containing the script
|
|
73
101
|
# Example 1: /bin/mybin -> bin
|
|
74
|
-
# Example 2: ruby /test/myapp.
|
|
102
|
+
# Example 2: ruby /test/myapp.rb -> test
|
|
75
103
|
# @return [String] the last segment of the base directory of the script
|
|
76
104
|
#
|
|
77
105
|
# @note As with entrypoint name, determining true entrypoint directory is complicated.
|
|
@@ -80,16 +108,9 @@ module Datadog
|
|
|
80
108
|
# the entrypoint basedir is `bin` which is not very helpful.
|
|
81
109
|
# We might improve this in the future if there is customer demand.
|
|
82
110
|
def self.entrypoint_basedir
|
|
83
|
-
|
|
84
|
-
end
|
|
111
|
+
return @entrypoint_basedir if defined?(@entrypoint_basedir)
|
|
85
112
|
|
|
86
|
-
|
|
87
|
-
# @param name [String] the rails application name
|
|
88
|
-
# @return [void]
|
|
89
|
-
def self.rails_application_name=(name)
|
|
90
|
-
@rails_application_name = name
|
|
91
|
-
remove_instance_variable(:@tags) if instance_variable_defined?(:@tags)
|
|
92
|
-
remove_instance_variable(:@serialized) if instance_variable_defined?(:@serialized)
|
|
113
|
+
@entrypoint_basedir = File.basename(File.expand_path(File.dirname($0)))
|
|
93
114
|
end
|
|
94
115
|
|
|
95
116
|
private_class_method :entrypoint_workdir, :entrypoint_type, :entrypoint_name, :entrypoint_basedir
|
|
@@ -18,6 +18,19 @@ module Datadog
|
|
|
18
18
|
|
|
19
19
|
@hostname ||= ::Socket.gethostname.freeze
|
|
20
20
|
end
|
|
21
|
+
|
|
22
|
+
# Returns the resolved hostname when `report_hostname` is enabled:
|
|
23
|
+
# the configured DD_HOSTNAME if set, otherwise the system hostname.
|
|
24
|
+
# Returns nil when `report_hostname` is disabled or no hostname is available.
|
|
25
|
+
def resolved_hostname(settings)
|
|
26
|
+
return nil unless settings.tracing.report_hostname
|
|
27
|
+
|
|
28
|
+
configured = settings.hostname
|
|
29
|
+
return configured if configured && !configured.empty?
|
|
30
|
+
|
|
31
|
+
resolved_hostname = hostname
|
|
32
|
+
resolved_hostname if resolved_hostname && !resolved_hostname.empty?
|
|
33
|
+
end
|
|
21
34
|
end
|
|
22
35
|
end
|
|
23
36
|
end
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require_relative '../../utils/
|
|
3
|
+
require_relative '../../utils/base64_codec'
|
|
4
4
|
require_relative '../../../appsec/remote'
|
|
5
5
|
require_relative '../../../tracing/remote'
|
|
6
|
+
require_relative '../../../di/remote'
|
|
7
|
+
require_relative '../../../symbol_database/remote'
|
|
6
8
|
require_relative '../../../open_feature/remote'
|
|
7
9
|
|
|
8
10
|
module Datadog
|
|
@@ -37,6 +39,13 @@ module Datadog
|
|
|
37
39
|
register_capabilities(Datadog::DI::Remote.capabilities)
|
|
38
40
|
register_products(Datadog::DI::Remote.products)
|
|
39
41
|
register_receivers(Datadog::DI::Remote.receivers(@telemetry))
|
|
42
|
+
|
|
43
|
+
# Symbol Database
|
|
44
|
+
if settings.respond_to?(:symbol_database) && settings.symbol_database.enabled
|
|
45
|
+
register_capabilities(Datadog::SymbolDatabase::Remote.capabilities)
|
|
46
|
+
register_products(Datadog::SymbolDatabase::Remote.products)
|
|
47
|
+
register_receivers(Datadog::SymbolDatabase::Remote.receivers(@telemetry))
|
|
48
|
+
end
|
|
40
49
|
end
|
|
41
50
|
|
|
42
51
|
if settings.respond_to?(:open_feature) && settings.open_feature.enabled
|
|
@@ -68,7 +77,7 @@ module Datadog
|
|
|
68
77
|
cap_to_hexs = capabilities.reduce(:|).to_s(16).tap { |s| s.size.odd? && s.prepend('0') }.scan(/\h\h/)
|
|
69
78
|
binary = cap_to_hexs.each_with_object([]) { |hex, acc| acc << hex }.map { |e| e.to_i(16) }.pack('C*')
|
|
70
79
|
|
|
71
|
-
Datadog::Core::Utils::
|
|
80
|
+
Datadog::Core::Utils::Base64Codec.strict_encode64(binary)
|
|
72
81
|
end
|
|
73
82
|
end
|
|
74
83
|
end
|
|
@@ -4,7 +4,7 @@ require 'json'
|
|
|
4
4
|
|
|
5
5
|
require_relative '../../../transport/http/api/endpoint'
|
|
6
6
|
require_relative '../../../transport/http/response'
|
|
7
|
-
require_relative '../../../utils/
|
|
7
|
+
require_relative '../../../utils/base64_codec'
|
|
8
8
|
require_relative '../../../utils/truncation'
|
|
9
9
|
|
|
10
10
|
module Datadog
|
|
@@ -35,7 +35,7 @@ module Datadog
|
|
|
35
35
|
|
|
36
36
|
# TODO: these fallbacks should be improved
|
|
37
37
|
roots = payload[:roots] || []
|
|
38
|
-
targets = payload[:targets] || Datadog::Core::Utils::
|
|
38
|
+
targets = payload[:targets] || Datadog::Core::Utils::Base64Codec.strict_encode64('{}')
|
|
39
39
|
target_files = payload[:target_files] || []
|
|
40
40
|
client_configs = payload[:client_configs] || []
|
|
41
41
|
|
|
@@ -45,7 +45,7 @@ module Datadog
|
|
|
45
45
|
raise TypeError.new(String, root) unless root.is_a?(String)
|
|
46
46
|
|
|
47
47
|
decoded = begin
|
|
48
|
-
Datadog::Core::Utils::
|
|
48
|
+
Datadog::Core::Utils::Base64Codec.strict_decode64(root) # TODO: unprocessed, don't symbolize_names
|
|
49
49
|
rescue ArgumentError
|
|
50
50
|
raise DecodeError.new(:roots, root)
|
|
51
51
|
end
|
|
@@ -65,7 +65,7 @@ module Datadog
|
|
|
65
65
|
|
|
66
66
|
@targets = begin
|
|
67
67
|
decoded = begin
|
|
68
|
-
Datadog::Core::Utils::
|
|
68
|
+
Datadog::Core::Utils::Base64Codec.strict_decode64(targets)
|
|
69
69
|
rescue ArgumentError
|
|
70
70
|
raise DecodeError.new(:targets, targets)
|
|
71
71
|
end
|
|
@@ -93,7 +93,7 @@ module Datadog
|
|
|
93
93
|
raise TypeError.new(String, raw) unless raw.is_a?(String)
|
|
94
94
|
|
|
95
95
|
content = begin
|
|
96
|
-
Datadog::Core::Utils::
|
|
96
|
+
Datadog::Core::Utils::Base64Codec.strict_decode64(raw)
|
|
97
97
|
rescue ArgumentError
|
|
98
98
|
raise DecodeError.new(:target_files, raw)
|
|
99
99
|
end
|
|
@@ -3,8 +3,9 @@
|
|
|
3
3
|
module Datadog
|
|
4
4
|
module Core
|
|
5
5
|
module Utils
|
|
6
|
-
#
|
|
7
|
-
|
|
6
|
+
# Base64 encoding/decoding without using the `base64` gem,
|
|
7
|
+
# which is no longer a default gem since Ruby 3.4.
|
|
8
|
+
module Base64Codec
|
|
8
9
|
def self.encode64(bin)
|
|
9
10
|
[bin].pack('m')
|
|
10
11
|
end
|
|
@@ -3,30 +3,7 @@
|
|
|
3
3
|
module Datadog
|
|
4
4
|
module Core
|
|
5
5
|
module Utils
|
|
6
|
-
# Refinements for {Hash}.
|
|
7
6
|
module Hash
|
|
8
|
-
# This refinement ensures modern rubies are allowed to use newer,
|
|
9
|
-
# simpler, and more performant APIs.
|
|
10
|
-
module Refinement
|
|
11
|
-
# Introduced in Ruby 2.4
|
|
12
|
-
unless ::Hash.method_defined?(:compact)
|
|
13
|
-
refine ::Hash do
|
|
14
|
-
def compact
|
|
15
|
-
reject { |_k, v| v.nil? }
|
|
16
|
-
end
|
|
17
|
-
end
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
# Introduced in Ruby 2.4
|
|
21
|
-
unless ::Hash.method_defined?(:compact!)
|
|
22
|
-
refine ::Hash do
|
|
23
|
-
def compact!
|
|
24
|
-
reject! { |_k, v| v.nil? }
|
|
25
|
-
end
|
|
26
|
-
end
|
|
27
|
-
end
|
|
28
|
-
end
|
|
29
|
-
|
|
30
7
|
# A minimal {Hash} wrapper that provides case-insensitive access
|
|
31
8
|
# to hash keys, without the overhead of copying the original hash.
|
|
32
9
|
#
|
|
@@ -3,32 +3,62 @@
|
|
|
3
3
|
module Datadog
|
|
4
4
|
module Core
|
|
5
5
|
module Utils
|
|
6
|
+
# Applies the Process.spawn wrapper used to merge additional environment variables
|
|
7
|
+
# into child processes.
|
|
6
8
|
module SpawnMonkeyPatch
|
|
7
|
-
# @param
|
|
8
|
-
def self.apply!(
|
|
9
|
-
@
|
|
9
|
+
# @param env_provider [#call] returns a Hash of env vars to merge into the child process
|
|
10
|
+
def self.apply!(env_provider:)
|
|
11
|
+
@env_provider = env_provider
|
|
12
|
+
|
|
13
|
+
# Idempotent: tests, reloads, or repeated Components init must not stack prepends.
|
|
14
|
+
return if ::Process.singleton_class.ancestors.include?(ProcessSpawnPatch)
|
|
15
|
+
|
|
10
16
|
::Process.singleton_class.prepend(ProcessSpawnPatch)
|
|
11
|
-
true
|
|
12
17
|
end
|
|
13
18
|
|
|
19
|
+
# Prepends `Process.spawn` to merge `env_provider` output into the child's environment hash.
|
|
14
20
|
module ProcessSpawnPatch
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
21
|
+
# The One and Only Correct Delegation Pattern
|
|
22
|
+
if RUBY_VERSION >= '3'
|
|
23
|
+
def spawn(*args, **kwargs) # steep:ignore DifferentMethodParameterKind
|
|
24
|
+
super(*SpawnMonkeyPatch.inject_envs(args), **kwargs)
|
|
25
|
+
end
|
|
26
|
+
else
|
|
27
|
+
def spawn(*args)
|
|
28
|
+
super(*SpawnMonkeyPatch.inject_envs(args))
|
|
29
|
+
end
|
|
30
|
+
ruby2_keywords :spawn if respond_to?(:ruby2_keywords, true)
|
|
18
31
|
end
|
|
19
32
|
end
|
|
20
33
|
|
|
21
|
-
#
|
|
22
|
-
#
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
34
|
+
# Merge the env vars from `env_provider` with the optional env `Hash` from {Process.spawn}.
|
|
35
|
+
#
|
|
36
|
+
# `env` is the first argument when it is a {Hash}; see MRI `spawn([env, ] *args, options)`:
|
|
37
|
+
# https://docs.ruby-lang.org/en/master/Process.html#method-c-spawn
|
|
38
|
+
#
|
|
39
|
+
# When there is **no** leading env Hash, MRI inherits the parent's `ENV`; we prepend only the
|
|
40
|
+
# `env_provider` hash so spawned children see parent env plus injections.
|
|
41
|
+
#
|
|
42
|
+
# When callers pass `unsetenv_others: true`, MRI only forwards the explicitly passed env Hash;
|
|
43
|
+
# replacing a missing hash with DATADOG_ENV.to_h would wrongly carry over parent variables.
|
|
44
|
+
# Prepending only the provider hash preserves `unsetenv_others` semantics.
|
|
45
|
+
#
|
|
46
|
+
# See https://docs.ruby-lang.org/en/master/Process.html#module-Process-label-Environment+Variables+-28-3Aunsetenv_others-29
|
|
47
|
+
#
|
|
48
|
+
# NOTE: `::Hash` (not bare `Hash`) is required because this module is nested under
|
|
49
|
+
# `Datadog::Core::Utils`, and `Datadog::Core::Utils::Hash` exists.
|
|
50
|
+
# Bare `Hash` resolves to that module via Module.nesting, making `Hash === some_hash`
|
|
51
|
+
# silently return `false`. See https://github.com/DataDog/dd-trace-rb/issues/5621.
|
|
52
|
+
def self.inject_envs(args)
|
|
53
|
+
provided_env = @env_provider.call
|
|
26
54
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
55
|
+
if ::Hash === args.first
|
|
56
|
+
args[0] = args.first.merge(provided_env)
|
|
57
|
+
else
|
|
58
|
+
args.unshift(provided_env)
|
|
59
|
+
end
|
|
30
60
|
|
|
31
|
-
|
|
61
|
+
args
|
|
32
62
|
end
|
|
33
63
|
end
|
|
34
64
|
end
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require 'stringio'
|
|
4
|
-
require_relative '../core/utils/
|
|
4
|
+
require_relative '../core/utils/base64_codec'
|
|
5
5
|
|
|
6
6
|
module Datadog
|
|
7
7
|
module DataStreams
|
|
@@ -34,7 +34,7 @@ module Datadog
|
|
|
34
34
|
end
|
|
35
35
|
|
|
36
36
|
def encode_b64
|
|
37
|
-
Core::Utils::
|
|
37
|
+
Core::Utils::Base64Codec.strict_encode64(encode)
|
|
38
38
|
end
|
|
39
39
|
|
|
40
40
|
# Decode pathway context from base64 encoded string
|
|
@@ -42,7 +42,7 @@ module Datadog
|
|
|
42
42
|
return nil unless encoded_ctx && !encoded_ctx.empty?
|
|
43
43
|
|
|
44
44
|
begin
|
|
45
|
-
binary_data = Core::Utils::
|
|
45
|
+
binary_data = Core::Utils::Base64Codec.strict_decode64(encoded_ctx)
|
|
46
46
|
decode(binary_data)
|
|
47
47
|
rescue ArgumentError => e
|
|
48
48
|
# Invalid base64 encoding - may indicate version mismatch or corruption
|
|
@@ -249,23 +249,34 @@ module Datadog
|
|
|
249
249
|
exact = registry[suffix]
|
|
250
250
|
return [suffix, exact] if exact
|
|
251
251
|
|
|
252
|
-
|
|
253
|
-
loop
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
252
|
+
# Normalize Windows-style backslash separators (DEBUG-5111) upfront
|
|
253
|
+
# so the suffix-shortening loop's "/+" regex can strip leading
|
|
254
|
+
# components on probes whose sourceFile uses backslashes.
|
|
255
|
+
suffix = Utils.normalize_windows_separators(suffix)
|
|
256
|
+
|
|
257
|
+
# Per the design comment in utils.rb, attempt case-sensitive
|
|
258
|
+
# matching first (steps 5-6) and only fall back to case-insensitive
|
|
259
|
+
# matching (steps 7-8) when no case-sensitive match is found.
|
|
260
|
+
[false, true].each do |case_insensitive|
|
|
261
|
+
working_suffix = suffix.dup
|
|
262
|
+
loop do
|
|
263
|
+
inexact = []
|
|
264
|
+
registry.each do |path, iseq|
|
|
265
|
+
if Utils.path_matches_suffix?(path, working_suffix, case_insensitive: case_insensitive)
|
|
266
|
+
inexact << [path, iseq]
|
|
267
|
+
end
|
|
258
268
|
end
|
|
269
|
+
if inexact.length > 1
|
|
270
|
+
raise Error::MultiplePathsMatch, "Multiple paths matched requested suffix"
|
|
271
|
+
end
|
|
272
|
+
if inexact.any?
|
|
273
|
+
return inexact.first
|
|
274
|
+
end
|
|
275
|
+
break unless working_suffix.include?('/')
|
|
276
|
+
working_suffix.sub!(%r{.*/+}, '')
|
|
259
277
|
end
|
|
260
|
-
if inexact.length > 1
|
|
261
|
-
raise Error::MultiplePathsMatch, "Multiple paths matched requested suffix"
|
|
262
|
-
end
|
|
263
|
-
if inexact.any?
|
|
264
|
-
return inexact.first
|
|
265
|
-
end
|
|
266
|
-
return nil unless suffix.include?('/')
|
|
267
|
-
suffix.sub!(%r{.*/+}, '')
|
|
268
278
|
end
|
|
279
|
+
nil
|
|
269
280
|
end
|
|
270
281
|
end
|
|
271
282
|
|
|
@@ -365,15 +376,25 @@ module Datadog
|
|
|
365
376
|
# Exact match.
|
|
366
377
|
return suffix if paths.include?(suffix)
|
|
367
378
|
|
|
368
|
-
#
|
|
369
|
-
suffix
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
379
|
+
# Normalize Windows-style backslash separators (DEBUG-5111) upfront
|
|
380
|
+
# so the suffix-shortening loop's "/+" regex can strip leading
|
|
381
|
+
# components on probes whose sourceFile uses backslashes.
|
|
382
|
+
suffix = Utils.normalize_windows_separators(suffix)
|
|
383
|
+
|
|
384
|
+
# Suffix match. Per the design comment in utils.rb, attempt
|
|
385
|
+
# case-sensitive matching first (steps 5-6) and only fall back to
|
|
386
|
+
# case-insensitive (steps 7-8) when no case-sensitive match is found.
|
|
387
|
+
[false, true].each do |case_insensitive|
|
|
388
|
+
working_suffix = suffix.dup
|
|
389
|
+
loop do
|
|
390
|
+
matches = paths.select { |p| Utils.path_matches_suffix?(p, working_suffix, case_insensitive: case_insensitive) }
|
|
391
|
+
raise Error::MultiplePathsMatch, "Multiple paths matched requested suffix" if matches.length > 1
|
|
392
|
+
return matches.first if matches.any?
|
|
393
|
+
break unless working_suffix.include?('/')
|
|
394
|
+
working_suffix.sub!(%r{.*/+}, '')
|
|
395
|
+
end
|
|
376
396
|
end
|
|
397
|
+
nil
|
|
377
398
|
end
|
|
378
399
|
end
|
|
379
400
|
end
|
|
@@ -23,7 +23,11 @@ Datadog::DI::Serializer.register(
|
|
|
23
23
|
#
|
|
24
24
|
# +depth+ is the remaining depth for serializing collections and objects.
|
|
25
25
|
# It should always be an integer.
|
|
26
|
-
#
|
|
26
|
+
# Pass it through to +serialize_value+ when the structure you produce
|
|
27
|
+
# represents +value+ directly (a transparent wrapper); +serialize_value+
|
|
28
|
+
# decrements depth itself when it recurses into Array/Hash/object entries.
|
|
29
|
+
# Decrement +depth+ only if your wrapper introduces real additional
|
|
30
|
+
# nesting levels in the output.
|
|
27
31
|
# This serializer could also potentially do its own depth limiting.
|
|
28
32
|
#
|
|
29
33
|
# Steep: steep thinks all of the arguments are nil here
|
|
@@ -33,5 +37,5 @@ Datadog::DI::Serializer.register(
|
|
|
33
37
|
attributes: value.attributes,
|
|
34
38
|
new_record: value.new_record?,
|
|
35
39
|
}
|
|
36
|
-
serializer.serialize_value(value_to_serialize, depth: depth
|
|
40
|
+
serializer.serialize_value(value_to_serialize, depth: depth, type: value.class)
|
|
37
41
|
end
|
|
@@ -106,7 +106,7 @@ module Datadog
|
|
|
106
106
|
serializer = self.serializer
|
|
107
107
|
method_name = probe.method_name
|
|
108
108
|
loc = begin
|
|
109
|
-
cls.instance_method(method_name).source_location
|
|
109
|
+
cls.instance_method(method_name).source_location # steep:ignore ArgumentTypeMismatch
|
|
110
110
|
rescue NameError
|
|
111
111
|
# The target method is not defined.
|
|
112
112
|
# This could be because it will be explicitly defined later
|
|
@@ -618,12 +618,32 @@ module Datadog
|
|
|
618
618
|
def raise_if_probe_in_loaded_features(probe, line_no, code_tracker)
|
|
619
619
|
return unless probe.file
|
|
620
620
|
|
|
621
|
-
# Find the loaded path matching the probe file.
|
|
621
|
+
# Find the loaded path matching the probe file. Case-sensitive
|
|
622
|
+
# matching is attempted first, with case-insensitive matching as a
|
|
623
|
+
# fallback (see the design comment in utils.rb, steps 5-8). Leading
|
|
624
|
+
# directory components are stripped so probes whose sourceFile carries
|
|
625
|
+
# a source-repo prefix that does not exist on disk still resolve to
|
|
626
|
+
# the loaded file — matching the behavior of
|
|
627
|
+
# CodeTracker#iseqs_for_path_suffix.
|
|
622
628
|
loaded_path = if $LOADED_FEATURES.include?(probe.file)
|
|
623
629
|
probe.file
|
|
624
630
|
else
|
|
625
631
|
# Expensive suffix check.
|
|
626
|
-
|
|
632
|
+
suffix = Utils.normalize_windows_separators(probe.file)
|
|
633
|
+
found = nil #: ::String?
|
|
634
|
+
[false, true].each do |case_insensitive|
|
|
635
|
+
working_suffix = suffix.dup
|
|
636
|
+
loop do
|
|
637
|
+
found = $LOADED_FEATURES.find do |path|
|
|
638
|
+
Utils.path_matches_suffix?(path, working_suffix, case_insensitive: case_insensitive)
|
|
639
|
+
end
|
|
640
|
+
break if found
|
|
641
|
+
break unless working_suffix.include?('/')
|
|
642
|
+
working_suffix.sub!(%r{.*/+}, '')
|
|
643
|
+
end
|
|
644
|
+
break if found
|
|
645
|
+
end
|
|
646
|
+
found
|
|
627
647
|
end
|
|
628
648
|
|
|
629
649
|
return unless loaded_path
|
|
@@ -648,7 +668,7 @@ module Datadog
|
|
|
648
668
|
|
|
649
669
|
# TODO test that this resolves qualified names e.g. A::B
|
|
650
670
|
def symbolize_class_name(cls_name)
|
|
651
|
-
Object.const_get(cls_name)
|
|
671
|
+
Object.const_get(cls_name) # steep:ignore ArgumentTypeMismatch
|
|
652
672
|
rescue NameError => exc
|
|
653
673
|
raise Error::DITargetNotDefined, "Class not defined: #{cls_name}: #{exc.class}: #{exc.message}"
|
|
654
674
|
end
|
data/lib/datadog/di/remote.rb
CHANGED
|
@@ -42,14 +42,14 @@ module Datadog
|
|
|
42
42
|
changes.each do |change|
|
|
43
43
|
case change.type
|
|
44
44
|
when :insert
|
|
45
|
-
add_probe(change.content, component)
|
|
45
|
+
add_probe(change.content, component) # steep:ignore NoMethod
|
|
46
46
|
when :update
|
|
47
47
|
# We do not implement updates at the moment, remove the
|
|
48
48
|
# probe and reinstall.
|
|
49
|
-
remove_probe(change.content, component)
|
|
50
|
-
add_probe(change.content, component)
|
|
49
|
+
remove_probe(change.content, component) # steep:ignore NoMethod
|
|
50
|
+
add_probe(change.content, component) # steep:ignore NoMethod
|
|
51
51
|
when :delete
|
|
52
|
-
remove_probe(change.previous, component)
|
|
52
|
+
remove_probe(change.previous, component) # steep:ignore NoMethod
|
|
53
53
|
else
|
|
54
54
|
# This really should never happen since we generate the
|
|
55
55
|
# change types in the library.
|
|
@@ -255,7 +255,7 @@ module Datadog
|
|
|
255
255
|
|
|
256
256
|
serialized.update(value: value)
|
|
257
257
|
when Array
|
|
258
|
-
if depth
|
|
258
|
+
if depth <= 0
|
|
259
259
|
serialized.update(notCapturedReason: "depth")
|
|
260
260
|
else
|
|
261
261
|
max = settings.dynamic_instrumentation.max_capture_collection_size
|
|
@@ -271,7 +271,7 @@ module Datadog
|
|
|
271
271
|
serialized.update(elements: entries)
|
|
272
272
|
end
|
|
273
273
|
when Hash
|
|
274
|
-
if depth
|
|
274
|
+
if depth <= 0
|
|
275
275
|
serialized.update(notCapturedReason: "depth")
|
|
276
276
|
else
|
|
277
277
|
max = settings.dynamic_instrumentation.max_capture_collection_size
|
|
@@ -288,7 +288,7 @@ module Datadog
|
|
|
288
288
|
serialized.update(entries: entries)
|
|
289
289
|
end
|
|
290
290
|
else
|
|
291
|
-
if depth
|
|
291
|
+
if depth <= 0
|
|
292
292
|
serialized.update(notCapturedReason: "depth")
|
|
293
293
|
else
|
|
294
294
|
fields = {}
|
|
@@ -369,7 +369,7 @@ module Datadog
|
|
|
369
369
|
when String
|
|
370
370
|
serialize_string_or_symbol_for_message(value)
|
|
371
371
|
when Symbol
|
|
372
|
-
':' + serialize_string_or_symbol_for_message(value)
|
|
372
|
+
':' + serialize_string_or_symbol_for_message(value) # steep:ignore ArgumentTypeMismatch
|
|
373
373
|
when Array
|
|
374
374
|
return '...' if depth <= 0
|
|
375
375
|
|
|
@@ -482,7 +482,7 @@ module Datadog
|
|
|
482
482
|
if max % 2 == 0
|
|
483
483
|
upper += 1
|
|
484
484
|
end
|
|
485
|
-
value[0...max / 2 - 1] + '...' + value[upper...length]
|
|
485
|
+
value[0...max / 2 - 1] + '...' + value[upper...length] # steep:ignore NoMethod
|
|
486
486
|
end
|
|
487
487
|
else
|
|
488
488
|
value
|