datadog 2.40.0 → 2.41.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 +85 -58
- data/ext/datadog_profiling_native_extension/collectors_stack.c +2 -2
- data/ext/datadog_profiling_native_extension/native_extension_helpers.rb +3 -3
- data/ext/datadog_profiling_native_extension/private_vm_api_access.c +26 -12
- data/ext/libdatadog_api/trace_exporter.c +409 -71
- data/ext/libdatadog_extconf_helpers.rb +1 -1
- data/lib/datadog/ai_guard/api_client.rb +1 -1
- data/lib/datadog/ai_guard/evaluation/request.rb +8 -8
- data/lib/datadog/ai_guard/evaluation.rb +10 -3
- data/lib/datadog/ai_guard/ext.rb +1 -1
- data/lib/datadog/appsec/actions_handler/serializable_backtrace.rb +21 -42
- data/lib/datadog/appsec/api_security/endpoint_collection/grape_route_serializer.rb +1 -1
- data/lib/datadog/appsec/api_security/endpoint_collection/rails_route_serializer.rb +1 -1
- data/lib/datadog/appsec/api_security/endpoint_collection/sinatra_route_serializer.rb +1 -1
- data/lib/datadog/appsec/configuration.rb +2 -2
- data/lib/datadog/appsec/context.rb +1 -1
- data/lib/datadog/appsec/contrib/active_record/instrumentation.rb +1 -1
- data/lib/datadog/appsec/contrib/aws_lambda/waf_addresses.rb +2 -2
- data/lib/datadog/appsec/contrib/devise/configuration.rb +1 -1
- data/lib/datadog/appsec/contrib/excon/ssrf_detection_middleware.rb +2 -2
- data/lib/datadog/appsec/contrib/faraday/ssrf_detection_middleware.rb +2 -2
- data/lib/datadog/appsec/contrib/graphql/gateway/watcher.rb +1 -1
- data/lib/datadog/appsec/contrib/rack/ext.rb +2 -2
- data/lib/datadog/appsec/contrib/rack/gateway/watcher.rb +2 -2
- data/lib/datadog/appsec/contrib/rails/gateway/watcher.rb +2 -2
- data/lib/datadog/appsec/contrib/rest_client/request_ssrf_detection_patch.rb +2 -2
- data/lib/datadog/appsec/contrib/sinatra/gateway/watcher.rb +2 -2
- data/lib/datadog/appsec/processor/rule_loader.rb +12 -12
- data/lib/datadog/appsec/response.rb +1 -1
- data/lib/datadog/appsec/route_normalizer/route_pattern.rb +3 -3
- data/lib/datadog/appsec/security_engine/engine.rb +3 -3
- data/lib/datadog/core/configuration/components.rb +2 -2
- data/lib/datadog/core/configuration/option_definition.rb +1 -1
- data/lib/datadog/core/configuration/options.rb +1 -1
- data/lib/datadog/core/diagnostics/environment_logger.rb +36 -1
- data/lib/datadog/core/metrics/helpers.rb +1 -1
- data/lib/datadog/core/metrics/options.rb +2 -2
- data/lib/datadog/core/process_discovery.rb +1 -1
- data/lib/datadog/core/remote/client.rb +1 -1
- data/lib/datadog/core/remote/configuration/repository.rb +2 -2
- data/lib/datadog/core/telemetry/configuration_value.rb +38 -0
- data/lib/datadog/core/telemetry/event/app_client_configuration_change.rb +3 -1
- data/lib/datadog/core/telemetry/event/app_endpoints_loaded.rb +1 -1
- data/lib/datadog/core/telemetry/event/app_started.rb +5 -24
- data/lib/datadog/core/telemetry/event/generate_metrics.rb +1 -1
- data/lib/datadog/core/telemetry/event/log.rb +2 -2
- data/lib/datadog/core/telemetry/metric.rb +2 -2
- data/lib/datadog/core/telemetry/request.rb +2 -2
- data/lib/datadog/core/transport/http.rb +1 -1
- data/lib/datadog/core/transport/transport.rb +1 -1
- data/lib/datadog/core/utils/at_fork_monkey_patch.rb +127 -43
- data/lib/datadog/data_streams/processor.rb +14 -14
- data/lib/datadog/di/el/compiler.rb +23 -0
- data/lib/datadog/di/el/expression.rb +8 -5
- data/lib/datadog/di/instrumenter.rb +5 -4
- data/lib/datadog/di/probe_builder.rb +5 -4
- data/lib/datadog/di/probe_notification_builder.rb +2 -2
- data/lib/datadog/di/serializer.rb +29 -4
- data/lib/datadog/error_tracking/component.rb +1 -1
- data/lib/datadog/kit/appsec/events/v2.rb +2 -2
- data/lib/datadog/open_feature/exposures/batch_builder.rb +1 -1
- data/lib/datadog/open_feature/exposures/event.rb +5 -5
- data/lib/datadog/profiling/collectors/info.rb +1 -1
- data/lib/datadog/profiling/tasks/exec.rb +1 -1
- data/lib/datadog/symbol_database/extractor.rb +6 -6
- data/lib/datadog/tracing/configuration/dynamic/option.rb +4 -0
- data/lib/datadog/tracing/configuration/dynamic.rb +5 -3
- data/lib/datadog/tracing/contrib/action_cable/events.rb +1 -1
- data/lib/datadog/tracing/contrib/action_mailer/events.rb +1 -1
- data/lib/datadog/tracing/contrib/action_pack/action_controller/instrumentation.rb +2 -2
- data/lib/datadog/tracing/contrib/action_view/events.rb +1 -1
- data/lib/datadog/tracing/contrib/active_model_serializers/events.rb +1 -1
- data/lib/datadog/tracing/contrib/active_record/configuration/resolver.rb +1 -1
- data/lib/datadog/tracing/contrib/active_record/events.rb +1 -1
- data/lib/datadog/tracing/contrib/active_support/cache/events/cache.rb +2 -2
- data/lib/datadog/tracing/contrib/aws/ext.rb +1 -1
- data/lib/datadog/tracing/contrib/aws/services.rb +1 -1
- data/lib/datadog/tracing/contrib/elasticsearch/quantize.rb +1 -1
- data/lib/datadog/tracing/contrib/ext.rb +3 -3
- data/lib/datadog/tracing/contrib/grpc/datadog_interceptor/client.rb +1 -1
- data/lib/datadog/tracing/contrib/grpc/datadog_interceptor/server.rb +1 -1
- data/lib/datadog/tracing/contrib/grpc/distributed/propagation.rb +1 -1
- data/lib/datadog/tracing/contrib/kafka/events.rb +1 -1
- data/lib/datadog/tracing/contrib/karafka/distributed/propagation.rb +1 -1
- data/lib/datadog/tracing/contrib/mongodb/parsers.rb +1 -1
- data/lib/datadog/tracing/contrib/opensearch/ext.rb +1 -1
- data/lib/datadog/tracing/contrib/opensearch/quantize.rb +1 -1
- data/lib/datadog/tracing/contrib/patchable.rb +1 -1
- data/lib/datadog/tracing/contrib/patcher.rb +1 -1
- data/lib/datadog/tracing/contrib/que/tracer.rb +1 -1
- data/lib/datadog/tracing/contrib/racecar/events.rb +1 -1
- data/lib/datadog/tracing/contrib/rack/configuration/settings.rb +1 -1
- data/lib/datadog/tracing/contrib/rack/header_tagging.rb +1 -1
- data/lib/datadog/tracing/contrib/rack/patcher.rb +1 -1
- data/lib/datadog/tracing/contrib/rack/trace_proxy_middleware.rb +1 -1
- data/lib/datadog/tracing/contrib/redis/configuration/resolver.rb +1 -1
- data/lib/datadog/tracing/contrib/redis/quantize.rb +36 -2
- data/lib/datadog/tracing/contrib/redis/trace_middleware.rb +9 -3
- data/lib/datadog/tracing/contrib/sequel/utils.rb +1 -1
- data/lib/datadog/tracing/contrib/sidekiq/distributed/propagation.rb +1 -1
- data/lib/datadog/tracing/contrib/sinatra/configuration/settings.rb +1 -1
- data/lib/datadog/tracing/contrib/sneakers/tracer.rb +1 -1
- data/lib/datadog/tracing/contrib/utils/quantization/hash_formatter.rb +1 -1
- data/lib/datadog/tracing/contrib/waterdrop/distributed/propagation.rb +1 -1
- data/lib/datadog/tracing/correlation.rb +2 -2
- data/lib/datadog/tracing/diagnostics/environment_logger.rb +2 -2
- data/lib/datadog/tracing/distributed/baggage.rb +1 -2
- data/lib/datadog/tracing/metadata/tagging.rb +1 -1
- data/lib/datadog/tracing/remote.rb +2 -2
- data/lib/datadog/tracing/span.rb +1 -1
- data/lib/datadog/tracing/span_operation.rb +1 -1
- data/lib/datadog/tracing/transport/io/traces.rb +1 -1
- data/lib/datadog/tracing/transport/native.rb +78 -54
- data/lib/datadog/tracing/writer.rb +1 -1
- data/lib/datadog/version.rb +1 -1
- metadata +6 -5
|
@@ -27,7 +27,7 @@ module Datadog
|
|
|
27
27
|
options = {
|
|
28
28
|
service: configuration[:web_service_name],
|
|
29
29
|
start_time: start_time,
|
|
30
|
-
type: Tracing::Metadata::Ext::HTTP::TYPE_PROXY
|
|
30
|
+
type: Tracing::Metadata::Ext::HTTP::TYPE_PROXY,
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
request_span = Tracing.trace(Ext::SPAN_HTTP_PROXY_REQUEST, **options)
|
|
@@ -15,6 +15,9 @@ module Datadog
|
|
|
15
15
|
|
|
16
16
|
AUTH_COMMANDS = %w[AUTH auth].freeze
|
|
17
17
|
|
|
18
|
+
CONNECTION_SETUP_COMMANDS = Set.new(%w[HELLO]).freeze
|
|
19
|
+
CLIENT_CONNECTION_SETUP_SUBCOMMANDS = Set.new(%w[SETINFO SETNAME]).freeze
|
|
20
|
+
|
|
18
21
|
MULTI_VERB_COMMANDS = Set.new(
|
|
19
22
|
%w[
|
|
20
23
|
ACL
|
|
@@ -40,7 +43,7 @@ module Datadog
|
|
|
40
43
|
|
|
41
44
|
def format_command_args(command_args)
|
|
42
45
|
command_args = resolve_command_args(command_args)
|
|
43
|
-
return "AUTH ?" if auth_command?(command_args)
|
|
46
|
+
return "AUTH ?" if auth_command?(command_args) || hello_auth_command?(command_args)
|
|
44
47
|
|
|
45
48
|
verb, *args = command_args.map { |x| format_arg(x) }
|
|
46
49
|
Core::Utils.truncate("#{verb.upcase} #{args.join(" ")}", CMD_MAX_LEN, TOO_LONG_MARK)
|
|
@@ -51,6 +54,8 @@ module Datadog
|
|
|
51
54
|
|
|
52
55
|
return get_verb(command_args.first) if command_args.first.is_a?(Array)
|
|
53
56
|
|
|
57
|
+
return "AUTH" if hello_auth_command?(command_args)
|
|
58
|
+
|
|
54
59
|
verb = command_args.first.to_s.upcase
|
|
55
60
|
return verb unless MULTI_VERB_COMMANDS.include?(verb) && command_args[1]
|
|
56
61
|
|
|
@@ -64,6 +69,35 @@ module Datadog
|
|
|
64
69
|
AUTH_COMMANDS.include?(verb)
|
|
65
70
|
end
|
|
66
71
|
|
|
72
|
+
# Identifies a RESP3 `HELLO ... AUTH user pass` handshake command, which embeds
|
|
73
|
+
# credentials the same way a standalone `AUTH` command does and must be redacted
|
|
74
|
+
# (and kept visible as its own span) rather than treated as a silent connection
|
|
75
|
+
# bootstrap command.
|
|
76
|
+
def hello_auth_command?(command_args)
|
|
77
|
+
return false unless command_args.is_a?(Array) && !command_args.empty?
|
|
78
|
+
|
|
79
|
+
# `redis-client` always emits this as `["HELLO", "3", "AUTH", username, password]` — check
|
|
80
|
+
# the fixed "AUTH" keyword position only, never the username/password values themselves,
|
|
81
|
+
# since those are untrusted, possibly-binary bulk strings that `#upcase` can raise on.
|
|
82
|
+
return false if command_args.length < 3
|
|
83
|
+
command_args[0].to_s.upcase == "HELLO" && command_args[2].to_s.upcase == "AUTH"
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# Identifies protocol-level connection bootstrap commands (`HELLO`, `CLIENT SETINFO`,
|
|
87
|
+
# `CLIENT SETNAME`) that `redis-client` sends as part of its per-connection handshake,
|
|
88
|
+
# so they can be excluded from pipeline resource naming. A `HELLO` carrying `AUTH`
|
|
89
|
+
# credentials is excluded from this so authentication remains visible as its own span.
|
|
90
|
+
def connection_setup_command?(command_args)
|
|
91
|
+
command_args = resolve_command_args(command_args)
|
|
92
|
+
return false unless command_args.is_a?(Array) && !command_args.empty?
|
|
93
|
+
return false if hello_auth_command?(command_args)
|
|
94
|
+
|
|
95
|
+
verb = command_args.first.to_s.upcase
|
|
96
|
+
return true if CONNECTION_SETUP_COMMANDS.include?(verb)
|
|
97
|
+
|
|
98
|
+
verb == "CLIENT" && CLIENT_CONNECTION_SETUP_SUBCOMMANDS.include?(command_args[1].to_s.upcase)
|
|
99
|
+
end
|
|
100
|
+
|
|
67
101
|
# Unwraps command array when Redis is called with the following syntax:
|
|
68
102
|
# redis.call([:cmd, 'arg1', ...])
|
|
69
103
|
def resolve_command_args(command_args)
|
|
@@ -72,7 +106,7 @@ module Datadog
|
|
|
72
106
|
command_args
|
|
73
107
|
end
|
|
74
108
|
|
|
75
|
-
private_class_method :auth_command?, :resolve_command_args
|
|
109
|
+
private_class_method :auth_command?, :hello_auth_command?, :resolve_command_args
|
|
76
110
|
end
|
|
77
111
|
end
|
|
78
112
|
end
|
|
@@ -37,12 +37,18 @@ module Datadog
|
|
|
37
37
|
end
|
|
38
38
|
|
|
39
39
|
def call_pipelined(client, commands, service_name, command_args)
|
|
40
|
+
# `redis-client` sends its per-connection handshake (`HELLO`, `CLIENT SETINFO`/`SETNAME`)
|
|
41
|
+
# as a pipeline through this same code path. Excluding those from resource naming keeps
|
|
42
|
+
# the resource focused on application-issued commands (e.g. a lone `SELECT` prelude).
|
|
43
|
+
traced_commands = commands.reject { |c| Contrib::Redis::Quantize.connection_setup_command?(c) }
|
|
44
|
+
return yield if traced_commands.empty? && !commands.empty?
|
|
45
|
+
|
|
40
46
|
Tracing.trace(Redis::Ext::SPAN_COMMAND, type: Redis::Ext::TYPE, service: service_name) do |span|
|
|
41
47
|
span.set_tag(Tracing::Metadata::Ext::TAG_SVC_SRC, Redis::Ext::TAG_COMPONENT)
|
|
42
|
-
raw_command = get_pipeline_commands(
|
|
43
|
-
span.resource = command_args ? raw_command : get_pipeline_commands(
|
|
48
|
+
raw_command = get_pipeline_commands(traced_commands, true)
|
|
49
|
+
span.resource = command_args ? raw_command : get_pipeline_commands(traced_commands, false)
|
|
44
50
|
|
|
45
|
-
span.set_metric Contrib::Redis::Ext::METRIC_PIPELINE_LEN,
|
|
51
|
+
span.set_metric Contrib::Redis::Ext::METRIC_PIPELINE_LEN, traced_commands.length
|
|
46
52
|
|
|
47
53
|
Contrib::Redis::Tags.set_common_tags(client, span, raw_command)
|
|
48
54
|
|
|
@@ -35,7 +35,7 @@ module Datadog
|
|
|
35
35
|
Tracing::Distributed::TraceContext.new(fetcher: Tracing::Distributed::Fetcher),
|
|
36
36
|
Tracing::Configuration::Ext::Distributed::PROPAGATION_STYLE_BAGGAGE =>
|
|
37
37
|
Tracing::Distributed::Baggage.new(fetcher: Tracing::Distributed::Fetcher),
|
|
38
|
-
Tracing::Configuration::Ext::Distributed::PROPAGATION_STYLE_NONE => Tracing::Distributed::None.new
|
|
38
|
+
Tracing::Configuration::Ext::Distributed::PROPAGATION_STYLE_NONE => Tracing::Distributed::None.new,
|
|
39
39
|
},
|
|
40
40
|
propagation_style_inject: propagation_style_inject,
|
|
41
41
|
propagation_style_extract: propagation_style_extract,
|
|
@@ -18,7 +18,7 @@ module Datadog
|
|
|
18
18
|
trace_options = {
|
|
19
19
|
service: configuration[:service_name],
|
|
20
20
|
type: Tracing::Metadata::Ext::AppTypes::TYPE_WORKER,
|
|
21
|
-
on_error: configuration[:on_error]
|
|
21
|
+
on_error: configuration[:on_error],
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
Tracing.trace(Ext::SPAN_JOB, **trace_options) do |request_span|
|
|
@@ -34,7 +34,7 @@ module Datadog
|
|
|
34
34
|
Tracing::Distributed::TraceContext.new(fetcher: Tracing::Distributed::Fetcher),
|
|
35
35
|
Tracing::Configuration::Ext::Distributed::PROPAGATION_STYLE_BAGGAGE =>
|
|
36
36
|
Tracing::Distributed::Baggage.new(fetcher: Tracing::Distributed::Fetcher),
|
|
37
|
-
Tracing::Configuration::Ext::Distributed::PROPAGATION_STYLE_NONE => Tracing::Distributed::None.new
|
|
37
|
+
Tracing::Configuration::Ext::Distributed::PROPAGATION_STYLE_NONE => Tracing::Distributed::None.new,
|
|
38
38
|
},
|
|
39
39
|
propagation_style_inject: propagation_style_inject,
|
|
40
40
|
propagation_style_extract: propagation_style_extract,
|
|
@@ -51,9 +51,9 @@ module Datadog
|
|
|
51
51
|
service: service.to_s,
|
|
52
52
|
version: version.to_s,
|
|
53
53
|
trace_id: trace_id.to_s,
|
|
54
|
-
span_id: span_id.to_s
|
|
54
|
+
span_id: span_id.to_s,
|
|
55
55
|
},
|
|
56
|
-
ddsource: Core::Logging::Ext::DD_SOURCE
|
|
56
|
+
ddsource: Core::Logging::Ext::DD_SOURCE,
|
|
57
57
|
}
|
|
58
58
|
end
|
|
59
59
|
|
|
@@ -47,7 +47,7 @@ module Datadog
|
|
|
47
47
|
|
|
48
48
|
def collect_errors!(responses)
|
|
49
49
|
{
|
|
50
|
-
agent_error: agent_error(responses)
|
|
50
|
+
agent_error: agent_error(responses),
|
|
51
51
|
}
|
|
52
52
|
end
|
|
53
53
|
|
|
@@ -114,7 +114,7 @@ module Datadog
|
|
|
114
114
|
{
|
|
115
115
|
name: rule.matcher.name,
|
|
116
116
|
service: rule.matcher.service,
|
|
117
|
-
sample_rate: rule.sampler.sample_rate(nil)
|
|
117
|
+
sample_rate: rule.sampler.sample_rate(nil),
|
|
118
118
|
}
|
|
119
119
|
end.compact
|
|
120
120
|
end
|
|
@@ -231,8 +231,7 @@ module Datadog
|
|
|
231
231
|
tags = {}
|
|
232
232
|
|
|
233
233
|
baggage_tag_keys.each do |key, _|
|
|
234
|
-
|
|
235
|
-
value = baggage[key] # steep:ignore ArgumentTypeMismatch
|
|
234
|
+
value = baggage[key]
|
|
236
235
|
next if value.nil? || value.empty?
|
|
237
236
|
|
|
238
237
|
tags["baggage.#{key}"] = value
|
|
@@ -21,7 +21,7 @@ module Datadog
|
|
|
21
21
|
Ext::Distributed::TAG_ORIGIN => true,
|
|
22
22
|
Core::Environment::Ext::TAG_VERSION => true,
|
|
23
23
|
Ext::HTTP::TAG_STATUS_CODE => true,
|
|
24
|
-
Ext::NET::TAG_HOSTNAME => true
|
|
24
|
+
Ext::NET::TAG_HOSTNAME => true,
|
|
25
25
|
}.freeze
|
|
26
26
|
|
|
27
27
|
# Return the tag with the given key, nil if it doesn't exist.
|
|
@@ -37,9 +37,9 @@ module Datadog
|
|
|
37
37
|
# Guard for RBS/Steep
|
|
38
38
|
raise "option is a #{option.class}, expected Option" unless option.is_a?(Configuration::Dynamic::Option)
|
|
39
39
|
|
|
40
|
-
option.call(value)
|
|
40
|
+
telemetry_value = option.call(value)
|
|
41
41
|
|
|
42
|
-
[env_var,
|
|
42
|
+
[env_var, telemetry_value]
|
|
43
43
|
end
|
|
44
44
|
|
|
45
45
|
if (di_enabled = lib_config["dynamic_instrumentation_enabled"]) != nil # rubocop:disable Style/NonNilCheck
|
data/lib/datadog/tracing/span.rb
CHANGED
|
@@ -65,6 +65,10 @@ module Datadog
|
|
|
65
65
|
# fork-safety note below.
|
|
66
66
|
@send_mutex = Mutex.new
|
|
67
67
|
|
|
68
|
+
# Serializes concurrent fork-hook lifecycles. Unlike @send_mutex,
|
|
69
|
+
# this is held across the fork through the matching completion hook.
|
|
70
|
+
@fork_mutex = Mutex.new
|
|
71
|
+
|
|
68
72
|
url = agent_settings.url
|
|
69
73
|
tracer_version = tracer_version_string
|
|
70
74
|
language = Core::Environment::Ext::LANG
|
|
@@ -106,8 +110,15 @@ module Datadog
|
|
|
106
110
|
# also tears down and replaces the runtime, so it must not run while
|
|
107
111
|
# a send is still using that runtime.
|
|
108
112
|
#
|
|
109
|
-
# `@
|
|
110
|
-
#
|
|
113
|
+
# `@fork_mutex` serializes concurrent forks for this exporter. The
|
|
114
|
+
# `:before` hook locks it first, then calls `_native_before_fork`,
|
|
115
|
+
# and finally locks `@send_mutex`, which serializes sends and is
|
|
116
|
+
# held across the fork. Sends and #close only acquire @send_mutex,
|
|
117
|
+
# so there is no lock-order inversion.
|
|
118
|
+
#
|
|
119
|
+
# `_native_before_fork` must run before locking `@send_mutex` to
|
|
120
|
+
# pause the runtime before waiting for an in-flight send to drain.
|
|
121
|
+
# The hook first calls
|
|
111
122
|
# `_native_before_fork` to pause the runtime, THEN locks the mutex.
|
|
112
123
|
# This ordering minimizes the serialized section and is safe to run
|
|
113
124
|
# concurrently with an in-flight send: `block_on` (used by
|
|
@@ -136,25 +147,29 @@ module Datadog
|
|
|
136
147
|
# hooks when it goes away (see #close and the finalizer): otherwise
|
|
137
148
|
# the closures keep the exporter -- and its runtime threads -- alive
|
|
138
149
|
# forever, and every later fork runs them against every
|
|
139
|
-
# historically-created exporter. The closures intentionally
|
|
140
|
-
# only
|
|
141
|
-
#
|
|
142
|
-
# #close was not called explicitly.
|
|
150
|
+
# historically-created exporter. The closures intentionally close
|
|
151
|
+
# over only locals (NOT `self`), so the Transport stays GC-eligible and
|
|
152
|
+
# its finalizer can fire even when #close was not called explicitly.
|
|
143
153
|
send_mutex = @send_mutex
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
154
|
+
fork_mutex = @fork_mutex
|
|
155
|
+
before_hook = proc do
|
|
156
|
+
fork_mutex.lock
|
|
157
|
+
|
|
158
|
+
begin
|
|
159
|
+
# Pause the runtime first (safe to run concurrently with an
|
|
160
|
+
# in-flight send), then wait for it to drain by acquiring the
|
|
161
|
+
# mutex. The lock must happen even if `_native_before_fork` raises, so the
|
|
162
|
+
# in-flight send has returned before the fork. Held across the
|
|
163
|
+
# fork; released in :parent/:child.
|
|
164
|
+
exporter._native_before_fork
|
|
165
|
+
rescue => e
|
|
166
|
+
Datadog.logger.warn { "Native transport before-fork preparation failed; traces may not be sent to Datadog: #{e.class}: #{e.message}" }
|
|
167
|
+
ensure
|
|
168
|
+
send_mutex.lock
|
|
169
|
+
end
|
|
155
170
|
end
|
|
156
|
-
parent_hook =
|
|
157
|
-
exporter._native_after_fork_in_parent
|
|
171
|
+
parent_hook = proc do
|
|
172
|
+
exporter._native_after_fork_in_parent if fork_mutex.owned?
|
|
158
173
|
rescue => e
|
|
159
174
|
Datadog.logger.warn { "Native transport after-fork reset failed; traces may not be sent to Datadog: #{e.class}: #{e.message}" }
|
|
160
175
|
ensure
|
|
@@ -164,9 +179,10 @@ module Datadog
|
|
|
164
179
|
# between `_native_before_fork` and the lock). Released even if the
|
|
165
180
|
# native call raised, so a failure can't leave the mutex locked.
|
|
166
181
|
send_mutex.unlock if send_mutex.owned?
|
|
182
|
+
fork_mutex.unlock if fork_mutex.owned?
|
|
167
183
|
end
|
|
168
|
-
child_hook =
|
|
169
|
-
exporter._native_after_fork_in_child
|
|
184
|
+
child_hook = proc do
|
|
185
|
+
exporter._native_after_fork_in_child if fork_mutex.owned?
|
|
170
186
|
rescue => e
|
|
171
187
|
Datadog.logger.warn { "Native transport after-fork reset failed; traces may not be sent to Datadog: #{e.class}: #{e.message}" }
|
|
172
188
|
ensure
|
|
@@ -174,61 +190,70 @@ module Datadog
|
|
|
174
190
|
# lone survivor in the child); the guard only covers `:before`
|
|
175
191
|
# being interrupted mid-lock.
|
|
176
192
|
send_mutex.unlock if send_mutex.owned?
|
|
193
|
+
fork_mutex.unlock if fork_mutex.owned?
|
|
177
194
|
end
|
|
178
195
|
|
|
179
|
-
@fork_hooks =
|
|
196
|
+
@fork_hooks = Core::Utils::AtForkMonkeyPatch.at_fork_blocks(
|
|
197
|
+
before: before_hook,
|
|
198
|
+
parent: parent_hook,
|
|
199
|
+
child: child_hook
|
|
200
|
+
)
|
|
201
|
+
remove_fork_hooks = self.class.send(:fork_hooks_remover, @fork_hooks)
|
|
180
202
|
|
|
181
203
|
# Fallback so a dropped (un-#close'd) transport doesn't leak its
|
|
182
204
|
# global fork hooks (and, through them, the exporter/runtime). The
|
|
183
|
-
#
|
|
205
|
+
# removal proc is built by a class method capturing ONLY the
|
|
184
206
|
# stage->block handles, never `self` -- a finalizer that closed over
|
|
185
207
|
# the object it is attached to would keep that object reachable and
|
|
186
|
-
# never run.
|
|
187
|
-
|
|
208
|
+
# never run. A fork that already copied these callbacks still owns
|
|
209
|
+
# them through its matching completion stage.
|
|
210
|
+
ObjectSpace.define_finalizer(
|
|
211
|
+
self,
|
|
212
|
+
remove_fork_hooks
|
|
213
|
+
)
|
|
188
214
|
end
|
|
189
215
|
|
|
190
216
|
# Deregister this transport's process-global fork hooks and release the
|
|
191
217
|
# native exporter so its runtime can shut down. Idempotent: safe to
|
|
192
218
|
# call multiple times and safe to call after the finalizer has run.
|
|
193
219
|
def close
|
|
194
|
-
fork_hooks = @
|
|
195
|
-
|
|
196
|
-
|
|
220
|
+
fork_hooks = @send_mutex.synchronize do
|
|
221
|
+
hooks = @fork_hooks
|
|
222
|
+
return if hooks.nil?
|
|
223
|
+
|
|
224
|
+
@fork_hooks = nil
|
|
225
|
+
@exporter = nil
|
|
226
|
+
hooks
|
|
227
|
+
end
|
|
197
228
|
|
|
198
229
|
fork_hooks.each do |stage, block|
|
|
199
230
|
Core::Utils::AtForkMonkeyPatch.remove_at_fork(stage, block)
|
|
200
231
|
end
|
|
201
232
|
|
|
202
|
-
# Drop our reference to the exporter so that, once the hooks above no
|
|
203
|
-
# longer pin it, it can be collected and its runtime shut down
|
|
204
|
-
# cleanly in this (parent) process.
|
|
205
|
-
@exporter = nil
|
|
206
|
-
|
|
207
233
|
# The finalizer only exists to deregister the hooks for a transport
|
|
208
234
|
# dropped without #close. We have just done that, so remove it;
|
|
209
|
-
# otherwise its
|
|
210
|
-
#
|
|
211
|
-
# itself collected.
|
|
235
|
+
# otherwise its closed-over hook blocks keep the exporter alive until
|
|
236
|
+
# this transport is itself collected.
|
|
212
237
|
ObjectSpace.undefine_finalizer(self)
|
|
213
238
|
|
|
214
239
|
nil
|
|
215
240
|
end
|
|
216
241
|
|
|
217
|
-
# Builds the
|
|
242
|
+
# Builds the proc that deregisters a transport's fork hooks.
|
|
218
243
|
#
|
|
219
244
|
# Defined as a class method so the proc closes over ONLY the
|
|
220
245
|
# stage->block handles passed in and never over a Transport instance
|
|
221
246
|
# (which would keep the instance reachable and prevent the finalizer
|
|
222
247
|
# from ever running). Removing the hooks unpins the exporter captured
|
|
223
248
|
# by those closures, allowing it (and its runtime) to be freed.
|
|
224
|
-
def self.
|
|
249
|
+
def self.fork_hooks_remover(fork_hooks)
|
|
225
250
|
proc do
|
|
226
251
|
fork_hooks.each do |stage, block|
|
|
227
252
|
Core::Utils::AtForkMonkeyPatch.remove_at_fork(stage, block)
|
|
228
253
|
end
|
|
229
254
|
end
|
|
230
255
|
end
|
|
231
|
-
private_class_method :
|
|
256
|
+
private_class_method :fork_hooks_remover
|
|
232
257
|
|
|
233
258
|
# Send a list of traces to the agent.
|
|
234
259
|
#
|
|
@@ -240,12 +265,6 @@ module Datadog
|
|
|
240
265
|
def send_traces(traces)
|
|
241
266
|
return [] if traces.empty?
|
|
242
267
|
|
|
243
|
-
# A closed transport has released its exporter; there is nothing to
|
|
244
|
-
# send through. Raising here is caught below and surfaced as an
|
|
245
|
-
# InternalErrorResponse, matching the other failure paths.
|
|
246
|
-
exporter = @exporter
|
|
247
|
-
raise "Native transport has been closed" if exporter.nil?
|
|
248
|
-
|
|
249
268
|
# Apply trace-level tags to root spans (same as the HTTP transport)
|
|
250
269
|
traces.each { |trace| TraceFormatter.format!(trace) }
|
|
251
270
|
|
|
@@ -253,9 +272,8 @@ module Datadog
|
|
|
253
272
|
# Each trace segment becomes one inner array (one trace chunk).
|
|
254
273
|
chunks = traces.map(&:spans)
|
|
255
274
|
|
|
256
|
-
#
|
|
257
|
-
#
|
|
258
|
-
# converted and would be dropped. Warn (once) so the loss is visible.
|
|
275
|
+
# Span events and span links are not yet converted and would be
|
|
276
|
+
# dropped. Warn (once) so the loss is visible.
|
|
259
277
|
warn_unsupported_fields!(chunks)
|
|
260
278
|
|
|
261
279
|
# Serialize the native send and hold the mutex across it so a
|
|
@@ -263,7 +281,14 @@ module Datadog
|
|
|
263
281
|
# (and `_native_before_fork` cannot tear down the runtime mid-send).
|
|
264
282
|
# `Mutex#synchronize` releases on exception / `rb_jump_tag` via its
|
|
265
283
|
# ensure, so interrupt propagation stays correct.
|
|
266
|
-
responses = @send_mutex.synchronize
|
|
284
|
+
responses = @send_mutex.synchronize do
|
|
285
|
+
# Resolve the exporter under the same lock used by #close, so
|
|
286
|
+
# close either drains this send or prevents it from starting.
|
|
287
|
+
exporter = @exporter
|
|
288
|
+
raise "Native transport has been closed" if exporter.nil?
|
|
289
|
+
|
|
290
|
+
exporter._native_send_traces(chunks)
|
|
291
|
+
end
|
|
267
292
|
|
|
268
293
|
# Update statistics from the response
|
|
269
294
|
responses.each { |response| update_stats_from_response!(response) }
|
|
@@ -278,10 +303,10 @@ module Datadog
|
|
|
278
303
|
private
|
|
279
304
|
|
|
280
305
|
# Warn, at most once per transport, when a batch contains span fields
|
|
281
|
-
# the native exporter does not yet convert (span events
|
|
282
|
-
#
|
|
283
|
-
#
|
|
284
|
-
#
|
|
306
|
+
# the native exporter does not yet convert (span events and span
|
|
307
|
+
# links). These are silently dropped by the native path; full support
|
|
308
|
+
# is tracked separately. The check is cheap: the fields are already-
|
|
309
|
+
# materialized collections on each Span.
|
|
285
310
|
def warn_unsupported_fields!(chunks)
|
|
286
311
|
return if @unsupported_fields_warned
|
|
287
312
|
|
|
@@ -290,7 +315,6 @@ module Datadog
|
|
|
290
315
|
spans.each do |span|
|
|
291
316
|
unsupported << "span events" if span.events.any?
|
|
292
317
|
unsupported << "span links" if span.links.any?
|
|
293
|
-
unsupported << "meta_struct" unless span.metastruct.to_h.empty?
|
|
294
318
|
end
|
|
295
319
|
end
|
|
296
320
|
return if unsupported.empty?
|
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.41.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Datadog, Inc.
|
|
@@ -63,14 +63,14 @@ dependencies:
|
|
|
63
63
|
requirements:
|
|
64
64
|
- - "~>"
|
|
65
65
|
- !ruby/object:Gem::Version
|
|
66
|
-
version:
|
|
66
|
+
version: 40.0.0.1.0
|
|
67
67
|
type: :runtime
|
|
68
68
|
prerelease: false
|
|
69
69
|
version_requirements: !ruby/object:Gem::Requirement
|
|
70
70
|
requirements:
|
|
71
71
|
- - "~>"
|
|
72
72
|
- !ruby/object:Gem::Version
|
|
73
|
-
version:
|
|
73
|
+
version: 40.0.0.1.0
|
|
74
74
|
- !ruby/object:Gem::Dependency
|
|
75
75
|
name: logger
|
|
76
76
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -432,6 +432,7 @@ files:
|
|
|
432
432
|
- lib/datadog/core/tag_builder.rb
|
|
433
433
|
- lib/datadog/core/tag_normalizer.rb
|
|
434
434
|
- lib/datadog/core/telemetry/component.rb
|
|
435
|
+
- lib/datadog/core/telemetry/configuration_value.rb
|
|
435
436
|
- lib/datadog/core/telemetry/emitter.rb
|
|
436
437
|
- lib/datadog/core/telemetry/event.rb
|
|
437
438
|
- lib/datadog/core/telemetry/event/app_client_configuration_change.rb
|
|
@@ -1165,8 +1166,8 @@ licenses:
|
|
|
1165
1166
|
- Apache-2.0
|
|
1166
1167
|
metadata:
|
|
1167
1168
|
allowed_push_host: https://rubygems.org
|
|
1168
|
-
changelog_uri: https://github.com/DataDog/dd-trace-rb/blob/v2.
|
|
1169
|
-
source_code_uri: https://github.com/DataDog/dd-trace-rb/tree/v2.
|
|
1169
|
+
changelog_uri: https://github.com/DataDog/dd-trace-rb/blob/v2.41.0/CHANGELOG.md
|
|
1170
|
+
source_code_uri: https://github.com/DataDog/dd-trace-rb/tree/v2.41.0
|
|
1170
1171
|
post_install_message: 'JRuby support in the datadog gem is deprecated. Details: https://dtdg.co/jruby-deprecation'
|
|
1171
1172
|
rdoc_options: []
|
|
1172
1173
|
require_paths:
|