datadog 2.31.0 → 2.32.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/ext/datadog_profiling_native_extension/collectors_cpu_and_wall_time_worker.c +17 -7
- data/ext/datadog_profiling_native_extension/collectors_thread_context.c +11 -4
- data/ext/datadog_profiling_native_extension/collectors_thread_context.h +6 -0
- data/ext/datadog_profiling_native_extension/extconf.rb +5 -4
- data/ext/datadog_profiling_native_extension/http_transport.c +10 -5
- data/ext/libdatadog_api/di.c +48 -0
- data/ext/libdatadog_api/extconf.rb +7 -4
- data/ext/libdatadog_extconf_helpers.rb +37 -0
- data/lib/datadog/ai_guard/configuration.rb +105 -2
- data/lib/datadog/ai_guard/evaluation.rb +1 -0
- data/lib/datadog/ai_guard/ext.rb +1 -0
- data/lib/datadog/appsec/autoload.rb +1 -1
- data/lib/datadog/appsec/component.rb +1 -1
- data/lib/datadog/appsec/configuration.rb +414 -1
- data/lib/datadog/appsec/contrib/devise/patches/signin_tracking_patch.rb +2 -1
- data/lib/datadog/appsec/contrib/rack/gateway/request.rb +1 -1
- data/lib/datadog/appsec/contrib/rails/patcher.rb +2 -2
- data/lib/datadog/appsec/metrics/telemetry.rb +13 -1
- data/lib/datadog/appsec/security_engine/runner.rb +1 -1
- data/lib/datadog/appsec/trace_keeper.rb +18 -6
- data/lib/datadog/appsec/utils/http/url_encoded.rb +2 -2
- data/lib/datadog/core/configuration/components.rb +1 -1
- data/lib/datadog/core/configuration/settings.rb +3 -0
- data/lib/datadog/core/configuration/supported_configurations.rb +2 -0
- data/lib/datadog/core/configuration.rb +1 -1
- data/lib/datadog/core/contrib/rails/utils.rb +1 -1
- data/lib/datadog/core/crashtracking/component.rb +3 -3
- data/lib/datadog/core/diagnostics/environment_logger.rb +3 -1
- data/lib/datadog/core/environment/container.rb +2 -2
- data/lib/datadog/core/feature_flags.rb +1 -1
- data/lib/datadog/core/metrics/client.rb +5 -5
- data/lib/datadog/core/remote/client.rb +1 -1
- data/lib/datadog/core/remote/component.rb +2 -2
- data/lib/datadog/core/runtime/metrics.rb +1 -1
- data/lib/datadog/core/telemetry/emitter.rb +1 -1
- data/lib/datadog/core/telemetry/event/app_started.rb +2 -2
- data/lib/datadog/core/transport/http.rb +2 -0
- data/lib/datadog/core/utils.rb +1 -1
- data/lib/datadog/core/workers/async.rb +1 -1
- data/lib/datadog/core.rb +1 -1
- data/lib/datadog/data_streams/configuration.rb +40 -1
- data/lib/datadog/data_streams/pathway_context.rb +1 -1
- data/lib/datadog/data_streams/processor.rb +1 -1
- data/lib/datadog/data_streams.rb +1 -1
- data/lib/datadog/di/base.rb +8 -5
- data/lib/datadog/di/code_tracker.rb +179 -1
- data/lib/datadog/di/component.rb +1 -1
- data/lib/datadog/di/configuration.rb +235 -2
- data/lib/datadog/di/instrumenter.rb +46 -26
- data/lib/datadog/di/probe_builder.rb +1 -1
- data/lib/datadog/di/probe_file_loader.rb +2 -2
- data/lib/datadog/di/probe_manager.rb +6 -6
- data/lib/datadog/di/probe_notification_builder.rb +1 -1
- data/lib/datadog/di/probe_notifier_worker.rb +2 -2
- data/lib/datadog/di/remote.rb +6 -6
- data/lib/datadog/di/serializer.rb +1 -1
- data/lib/datadog/di/transport/input.rb +3 -3
- data/lib/datadog/error_tracking/configuration.rb +55 -2
- data/lib/datadog/kit/enable_core_dumps.rb +1 -1
- data/lib/datadog/open_feature/component.rb +18 -1
- data/lib/datadog/open_feature/evaluation_engine.rb +3 -3
- data/lib/datadog/open_feature/exposures/reporter.rb +1 -1
- data/lib/datadog/open_feature/exposures/worker.rb +1 -1
- data/lib/datadog/open_feature/hooks/flag_eval_hook.rb +49 -0
- data/lib/datadog/open_feature/metrics/flag_eval_metrics.rb +149 -0
- data/lib/datadog/open_feature/provider.rb +19 -1
- data/lib/datadog/open_feature/remote.rb +1 -1
- data/lib/datadog/open_feature/transport.rb +1 -1
- data/lib/datadog/opentelemetry/metrics.rb +3 -3
- data/lib/datadog/opentelemetry/sdk/configurator.rb +1 -1
- data/lib/datadog/opentelemetry/sdk/metrics_exporter.rb +1 -1
- data/lib/datadog/profiling/collectors/code_provenance.rb +35 -9
- data/lib/datadog/profiling/collectors/cpu_and_wall_time_worker.rb +31 -2
- data/lib/datadog/profiling/collectors/idle_sampling_helper.rb +8 -2
- data/lib/datadog/profiling/collectors/info.rb +16 -3
- data/lib/datadog/profiling/component.rb +3 -5
- data/lib/datadog/profiling/exporter.rb +37 -12
- data/lib/datadog/profiling/ext.rb +0 -2
- data/lib/datadog/profiling/flush.rb +21 -12
- data/lib/datadog/profiling/http_transport.rb +12 -1
- data/lib/datadog/profiling/load_native_extension.rb +1 -1
- data/lib/datadog/profiling/profiler.rb +13 -1
- data/lib/datadog/profiling/scheduler.rb +2 -2
- data/lib/datadog/profiling/tasks/exec.rb +8 -3
- data/lib/datadog/profiling/tasks/help.rb +1 -0
- data/lib/datadog/profiling/tasks/setup.rb +2 -2
- data/lib/datadog/single_step_instrument.rb +1 -1
- data/lib/datadog/symbol_database/configuration.rb +65 -0
- data/lib/datadog/symbol_database/extractor.rb +915 -0
- data/lib/datadog/symbol_database/file_hash.rb +46 -0
- data/lib/datadog/symbol_database/logger.rb +43 -0
- data/lib/datadog/symbol_database/scope.rb +98 -0
- data/lib/datadog/symbol_database/service_version.rb +57 -0
- data/lib/datadog/symbol_database/symbol.rb +66 -0
- data/lib/datadog/symbol_database/transport/http/endpoint.rb +28 -0
- data/lib/datadog/symbol_database/transport/http.rb +45 -0
- data/lib/datadog/symbol_database/transport.rb +54 -0
- data/lib/datadog/symbol_database/uploader.rb +166 -0
- data/lib/datadog/symbol_database.rb +49 -0
- data/lib/datadog/tracing/buffer.rb +3 -3
- data/lib/datadog/tracing/configuration/settings.rb +1 -1
- data/lib/datadog/tracing/contrib/action_pack/action_controller/instrumentation.rb +5 -3
- data/lib/datadog/tracing/contrib/action_view/events/render_template.rb +1 -1
- data/lib/datadog/tracing/contrib/active_job/events/discard.rb +1 -1
- data/lib/datadog/tracing/contrib/active_job/events/enqueue.rb +1 -1
- data/lib/datadog/tracing/contrib/active_job/events/enqueue_at.rb +1 -1
- data/lib/datadog/tracing/contrib/active_job/events/enqueue_retry.rb +1 -1
- data/lib/datadog/tracing/contrib/active_job/events/perform.rb +1 -1
- data/lib/datadog/tracing/contrib/active_job/events/retry_stopped.rb +1 -1
- data/lib/datadog/tracing/contrib/active_model_serializers/events/render.rb +1 -1
- data/lib/datadog/tracing/contrib/active_model_serializers/events/serialize.rb +1 -1
- data/lib/datadog/tracing/contrib/active_record/configuration/resolver.rb +2 -2
- data/lib/datadog/tracing/contrib/active_record/events/instantiation.rb +1 -1
- data/lib/datadog/tracing/contrib/active_record/events/sql.rb +1 -1
- data/lib/datadog/tracing/contrib/active_record/utils.rb +1 -1
- data/lib/datadog/tracing/contrib/active_support/cache/events/cache.rb +1 -1
- data/lib/datadog/tracing/contrib/active_support/notifications/subscription.rb +2 -2
- data/lib/datadog/tracing/contrib/aws/instrumentation.rb +1 -1
- data/lib/datadog/tracing/contrib/component.rb +1 -1
- data/lib/datadog/tracing/contrib/configuration/resolver.rb +7 -4
- data/lib/datadog/tracing/contrib/dalli/quantize.rb +1 -1
- data/lib/datadog/tracing/contrib/elasticsearch/patcher.rb +1 -1
- data/lib/datadog/tracing/contrib/excon/middleware.rb +2 -2
- data/lib/datadog/tracing/contrib/extensions.rb +9 -0
- data/lib/datadog/tracing/contrib/faraday/middleware.rb +2 -2
- data/lib/datadog/tracing/contrib/grape/endpoint.rb +5 -5
- data/lib/datadog/tracing/contrib/grpc/datadog_interceptor/client.rb +2 -2
- data/lib/datadog/tracing/contrib/grpc/datadog_interceptor/server.rb +2 -2
- data/lib/datadog/tracing/contrib/http/instrumentation.rb +2 -2
- data/lib/datadog/tracing/contrib/httpclient/instrumentation.rb +6 -2
- data/lib/datadog/tracing/contrib/httprb/instrumentation.rb +2 -2
- data/lib/datadog/tracing/contrib/kafka/instrumentation/consumer.rb +2 -2
- data/lib/datadog/tracing/contrib/kafka/instrumentation/producer.rb +2 -2
- data/lib/datadog/tracing/contrib/karafka/patcher.rb +1 -1
- data/lib/datadog/tracing/contrib/mongodb/subscribers.rb +3 -3
- data/lib/datadog/tracing/contrib/opensearch/patcher.rb +1 -1
- data/lib/datadog/tracing/contrib/presto/instrumentation.rb +3 -3
- data/lib/datadog/tracing/contrib/rack/patcher.rb +1 -1
- data/lib/datadog/tracing/contrib/rack/request_queue.rb +1 -1
- data/lib/datadog/tracing/contrib/rails/log_injection.rb +1 -1
- data/lib/datadog/tracing/contrib/rails/runner.rb +1 -1
- data/lib/datadog/tracing/contrib/rake/instrumentation.rb +2 -2
- data/lib/datadog/tracing/contrib/redis/quantize.rb +1 -1
- data/lib/datadog/tracing/contrib/redis/tags.rb +1 -1
- data/lib/datadog/tracing/contrib/sidekiq/utils.rb +1 -1
- data/lib/datadog/tracing/contrib/stripe/request.rb +1 -1
- data/lib/datadog/tracing/contrib.rb +8 -0
- data/lib/datadog/tracing/diagnostics/environment_logger.rb +3 -1
- data/lib/datadog/tracing/distributed/baggage.rb +59 -5
- data/lib/datadog/tracing/distributed/datadog.rb +11 -11
- data/lib/datadog/tracing/distributed/datadog_tags_codec.rb +1 -1
- data/lib/datadog/tracing/distributed/propagation.rb +2 -2
- data/lib/datadog/tracing/distributed/trace_context.rb +74 -32
- data/lib/datadog/tracing/event.rb +1 -1
- data/lib/datadog/tracing/metadata/tagging.rb +2 -2
- data/lib/datadog/tracing/pipeline.rb +1 -1
- data/lib/datadog/tracing/remote.rb +1 -1
- data/lib/datadog/tracing/sampling/rule.rb +1 -1
- data/lib/datadog/tracing/sampling/rule_sampler.rb +2 -2
- data/lib/datadog/tracing/sampling/span/rule_parser.rb +2 -2
- data/lib/datadog/tracing/span_operation.rb +3 -3
- data/lib/datadog/tracing/trace_operation.rb +4 -4
- data/lib/datadog/tracing/tracer.rb +5 -5
- data/lib/datadog/tracing/transport/io/client.rb +1 -1
- data/lib/datadog/tracing/workers.rb +2 -1
- data/lib/datadog/version.rb +1 -1
- metadata +18 -9
- data/lib/datadog/ai_guard/configuration/settings.rb +0 -113
- data/lib/datadog/appsec/configuration/settings.rb +0 -423
- data/lib/datadog/data_streams/configuration/settings.rb +0 -49
- data/lib/datadog/di/configuration/settings.rb +0 -243
- data/lib/datadog/error_tracking/configuration/settings.rb +0 -63
|
@@ -37,7 +37,7 @@ module Datadog
|
|
|
37
37
|
# moved into C extension
|
|
38
38
|
@value = json?(value) ? JSON.parse(value) : value
|
|
39
39
|
rescue JSON::ParserError => e
|
|
40
|
-
raise Error, "Failed to parse JSON value: #{e.class}: #{e}"
|
|
40
|
+
raise Error, "Failed to parse JSON value: #{e.class}: #{e.message}"
|
|
41
41
|
end
|
|
42
42
|
|
|
43
43
|
# Check if the resolution resulted in an error
|
|
@@ -101,7 +101,7 @@ module Datadog
|
|
|
101
101
|
statsd.count(stat, value, metric_options(options))
|
|
102
102
|
rescue => e
|
|
103
103
|
logger.error(
|
|
104
|
-
"Failed to send count stat. Cause: #{e.class}: #{e} Source: #{Array(e.backtrace).first}"
|
|
104
|
+
"Failed to send count stat. Cause: #{e.class}: #{e.message} Source: #{Array(e.backtrace).first}"
|
|
105
105
|
)
|
|
106
106
|
telemetry.report(e, description: 'Failed to send count stat')
|
|
107
107
|
end
|
|
@@ -115,7 +115,7 @@ module Datadog
|
|
|
115
115
|
statsd.distribution(stat, value, metric_options(options))
|
|
116
116
|
rescue => e
|
|
117
117
|
logger.error(
|
|
118
|
-
"Failed to send distribution stat. Cause: #{e.class}: #{e} Source: #{Array(e.backtrace).first}"
|
|
118
|
+
"Failed to send distribution stat. Cause: #{e.class}: #{e.message} Source: #{Array(e.backtrace).first}"
|
|
119
119
|
)
|
|
120
120
|
telemetry.report(e, description: 'Failed to send distribution stat')
|
|
121
121
|
end
|
|
@@ -128,7 +128,7 @@ module Datadog
|
|
|
128
128
|
statsd.increment(stat, metric_options(options))
|
|
129
129
|
rescue => e
|
|
130
130
|
logger.error(
|
|
131
|
-
"Failed to send increment stat. Cause: #{e.class}: #{e} Source: #{Array(e.backtrace).first}"
|
|
131
|
+
"Failed to send increment stat. Cause: #{e.class}: #{e.message} Source: #{Array(e.backtrace).first}"
|
|
132
132
|
)
|
|
133
133
|
telemetry.report(e, description: 'Failed to send increment stat')
|
|
134
134
|
end
|
|
@@ -142,7 +142,7 @@ module Datadog
|
|
|
142
142
|
statsd.gauge(stat, value, metric_options(options))
|
|
143
143
|
rescue => e
|
|
144
144
|
logger.error(
|
|
145
|
-
"Failed to send gauge stat. Cause: #{e.class}: #{e} Source: #{Array(e.backtrace).first}"
|
|
145
|
+
"Failed to send gauge stat. Cause: #{e.class}: #{e.message} Source: #{Array(e.backtrace).first}"
|
|
146
146
|
)
|
|
147
147
|
telemetry.report(e, description: 'Failed to send gauge stat')
|
|
148
148
|
end
|
|
@@ -162,7 +162,7 @@ module Datadog
|
|
|
162
162
|
rescue => e
|
|
163
163
|
# TODO: Likely to be redundant, since `distribution` handles its own errors.
|
|
164
164
|
logger.error(
|
|
165
|
-
"Failed to send time stat. Cause: #{e.class}: #{e} Source: #{Array(e.backtrace).first}"
|
|
165
|
+
"Failed to send time stat. Cause: #{e.class}: #{e.message} Source: #{Array(e.backtrace).first}"
|
|
166
166
|
)
|
|
167
167
|
telemetry.report(e, description: 'Failed to send time stat')
|
|
168
168
|
end
|
|
@@ -57,7 +57,7 @@ module Datadog
|
|
|
57
57
|
|
|
58
58
|
contents = Configuration::ContentList.parse(response.target_files)
|
|
59
59
|
rescue Remote::Configuration::Path::ParseError => e
|
|
60
|
-
raise SyncError, e.message
|
|
60
|
+
raise SyncError, "#{e.class}: #{e.message}"
|
|
61
61
|
end
|
|
62
62
|
|
|
63
63
|
# To make sure steep does not complain
|
|
@@ -45,7 +45,7 @@ module Datadog
|
|
|
45
45
|
rescue Client::SyncError => e
|
|
46
46
|
# Transient errors due to network or agent. Logged the error but not via telemetry
|
|
47
47
|
logger.error do
|
|
48
|
-
"remote worker client sync error: #{e.class}: #{e} location: #{Array(e.backtrace).first}. skipping sync"
|
|
48
|
+
"remote worker client sync error: #{e.class}: #{e.message} location: #{Array(e.backtrace).first}. skipping sync"
|
|
49
49
|
end
|
|
50
50
|
rescue => e
|
|
51
51
|
# In case of unexpected errors, reset the negotiation object
|
|
@@ -55,7 +55,7 @@ module Datadog
|
|
|
55
55
|
|
|
56
56
|
# Transient errors due to network or agent. Logged the error but not via telemetry
|
|
57
57
|
logger.error do
|
|
58
|
-
"remote worker error: #{e.class}: #{e} location: #{Array(e.backtrace).first}. " \
|
|
58
|
+
"remote worker error: #{e.class}: #{e.message} location: #{Array(e.backtrace).first}. " \
|
|
59
59
|
'resetting client state'
|
|
60
60
|
end
|
|
61
61
|
|
|
@@ -100,7 +100,7 @@ module Datadog
|
|
|
100
100
|
def try_flush
|
|
101
101
|
yield
|
|
102
102
|
rescue => e
|
|
103
|
-
Datadog.logger.warn("Error while sending runtime metric. Cause: #{e.class}: #{e}")
|
|
103
|
+
Datadog.logger.warn("Error while sending runtime metric. Cause: #{e.class}: #{e.message}")
|
|
104
104
|
end
|
|
105
105
|
|
|
106
106
|
def default_metric_options
|
|
@@ -39,7 +39,7 @@ module Datadog
|
|
|
39
39
|
res
|
|
40
40
|
rescue => e
|
|
41
41
|
logger.debug {
|
|
42
|
-
"Unable to send telemetry request for event `#{event.respond_to?(:type) ? event.type : event.to_s}`: #{e.class}: #{e}"
|
|
42
|
+
"Unable to send telemetry request for event `#{event.respond_to?(:type) ? event.type : event.to_s}`: #{e.class}: #{e.message}"
|
|
43
43
|
}
|
|
44
44
|
Core::Transport::InternalErrorResponse.new(e)
|
|
45
45
|
end
|
|
@@ -260,9 +260,9 @@ module Datadog
|
|
|
260
260
|
end
|
|
261
261
|
|
|
262
262
|
def collect_integration_configuration_options(tracing_settings)
|
|
263
|
-
return [] unless tracing_settings.respond_to?(:
|
|
263
|
+
return [] unless tracing_settings.respond_to?(:instrumented_built_in_integrations)
|
|
264
264
|
|
|
265
|
-
tracing_settings.
|
|
265
|
+
tracing_settings.instrumented_built_in_integrations.each_with_object([]) do |integration, entries|
|
|
266
266
|
integration.configurations.each_value do |configuration|
|
|
267
267
|
entries.concat(collect_configuration_options_from(configuration))
|
|
268
268
|
end
|
|
@@ -4,6 +4,8 @@ require_relative 'http/builder'
|
|
|
4
4
|
require_relative 'http/adapters/net'
|
|
5
5
|
require_relative 'http/adapters/unix_socket'
|
|
6
6
|
require_relative 'http/adapters/test'
|
|
7
|
+
require_relative '../environment/container'
|
|
8
|
+
require_relative '../environment/ext'
|
|
7
9
|
|
|
8
10
|
module Datadog
|
|
9
11
|
module Core
|
data/lib/datadog/core/utils.rb
CHANGED
|
@@ -168,7 +168,7 @@ module Datadog
|
|
|
168
168
|
rescue Exception => e
|
|
169
169
|
@error = e
|
|
170
170
|
Datadog.logger.debug(
|
|
171
|
-
"Worker thread error. Cause: #{e.class}: #{e} Location: #{Array(e.backtrace).first}"
|
|
171
|
+
"Worker thread error. Cause: #{e.class}: #{e.message} Location: #{Array(e.backtrace).first}"
|
|
172
172
|
)
|
|
173
173
|
raise
|
|
174
174
|
|
data/lib/datadog/core.rb
CHANGED
|
@@ -1,11 +1,50 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require_relative '
|
|
3
|
+
require_relative '../core/environment/variable_helpers'
|
|
4
|
+
require_relative 'ext'
|
|
4
5
|
|
|
5
6
|
module Datadog
|
|
6
7
|
module DataStreams
|
|
7
8
|
# Configuration for Data Streams Monitoring
|
|
8
9
|
module Configuration
|
|
10
|
+
# Configuration settings for Data Streams Monitoring.
|
|
11
|
+
module Settings
|
|
12
|
+
def self.extended(base)
|
|
13
|
+
base = base.singleton_class unless base.is_a?(Class)
|
|
14
|
+
add_settings!(base)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def self.add_settings!(base)
|
|
18
|
+
base.class_eval do
|
|
19
|
+
# Data Streams Monitoring configuration
|
|
20
|
+
# @public_api
|
|
21
|
+
settings :data_streams do
|
|
22
|
+
# Whether Data Streams Monitoring is enabled. When enabled, the library will
|
|
23
|
+
# collect and report data lineage information for messaging systems.
|
|
24
|
+
#
|
|
25
|
+
# @default `DD_DATA_STREAMS_ENABLED` environment variable, otherwise `false`.
|
|
26
|
+
# @return [Boolean]
|
|
27
|
+
option :enabled do |o|
|
|
28
|
+
o.type :bool
|
|
29
|
+
o.env Ext::ENV_ENABLED
|
|
30
|
+
o.default false
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# The interval (in seconds) at which Data Streams Monitoring stats are flushed.
|
|
34
|
+
#
|
|
35
|
+
# @default 10.0
|
|
36
|
+
# @env '_DD_TRACE_STATS_WRITER_INTERVAL'
|
|
37
|
+
# @return [Float]
|
|
38
|
+
# @!visibility private
|
|
39
|
+
option :interval do |o|
|
|
40
|
+
o.type :float
|
|
41
|
+
o.env '_DD_TRACE_STATS_WRITER_INTERVAL'
|
|
42
|
+
o.default 10.0
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
9
48
|
end
|
|
10
49
|
end
|
|
11
50
|
end
|
|
@@ -46,7 +46,7 @@ module Datadog
|
|
|
46
46
|
decode(binary_data)
|
|
47
47
|
rescue ArgumentError => e
|
|
48
48
|
# Invalid base64 encoding - may indicate version mismatch or corruption
|
|
49
|
-
Datadog.logger.debug { "Failed to decode DSM pathway context: #{e.class}: #{e}" }
|
|
49
|
+
Datadog.logger.debug { "Failed to decode DSM pathway context: #{e.class}: #{e.message}" }
|
|
50
50
|
nil
|
|
51
51
|
end
|
|
52
52
|
end
|
|
@@ -329,7 +329,7 @@ module Datadog
|
|
|
329
329
|
# Send to agent outside mutex to avoid blocking customer code if agent is slow/hung.
|
|
330
330
|
send_stats_to_agent(payload)
|
|
331
331
|
rescue => e
|
|
332
|
-
@logger.debug("Failed to flush DSM stats to agent: #{e.class}: #{e}")
|
|
332
|
+
@logger.debug("Failed to flush DSM stats to agent: #{e.class}: #{e.message}")
|
|
333
333
|
end
|
|
334
334
|
|
|
335
335
|
def get_current_pathway
|
data/lib/datadog/data_streams.rb
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
require_relative 'data_streams/processor'
|
|
4
4
|
require_relative 'data_streams/pathway_context'
|
|
5
|
-
require_relative 'data_streams/configuration
|
|
5
|
+
require_relative 'data_streams/configuration'
|
|
6
6
|
require_relative 'data_streams/extensions'
|
|
7
7
|
require_relative 'core/utils/time'
|
|
8
8
|
|
data/lib/datadog/di/base.rb
CHANGED
|
@@ -17,6 +17,10 @@ module Datadog
|
|
|
17
17
|
module DI
|
|
18
18
|
LOCK = Mutex.new
|
|
19
19
|
|
|
20
|
+
# Initialized eagerly to avoid "instance variable not initialized"
|
|
21
|
+
# warning on Ruby 2.6/2.7 and to simplify the type to non-nullable.
|
|
22
|
+
@current_components = []
|
|
23
|
+
|
|
20
24
|
class << self
|
|
21
25
|
attr_reader :code_tracker
|
|
22
26
|
|
|
@@ -48,12 +52,12 @@ module Datadog
|
|
|
48
52
|
Datadog::DI.activate_tracking!
|
|
49
53
|
rescue => exc
|
|
50
54
|
if defined?(Datadog.logger)
|
|
51
|
-
Datadog.logger.warn { "di: Failed to activate code tracking for DI: #{exc.class}: #{exc}" }
|
|
55
|
+
Datadog.logger.warn { "di: Failed to activate code tracking for DI: #{exc.class}: #{exc.message}" }
|
|
52
56
|
else
|
|
53
57
|
# We do not have Datadog logger potentially because DI code tracker is
|
|
54
58
|
# being loaded early in application boot process and the rest of datadog
|
|
55
59
|
# wasn't loaded yet. Output to standard error.
|
|
56
|
-
warn("datadog: di: Failed to activate code tracking for DI: #{exc.class}: #{exc}")
|
|
60
|
+
warn("datadog: di: Failed to activate code tracking for DI: #{exc.class}: #{exc.message}")
|
|
57
61
|
end
|
|
58
62
|
end
|
|
59
63
|
end
|
|
@@ -88,7 +92,7 @@ module Datadog
|
|
|
88
92
|
# Datadog.components from the code tracker.
|
|
89
93
|
def current_component
|
|
90
94
|
LOCK.synchronize do
|
|
91
|
-
@current_components
|
|
95
|
+
@current_components.last
|
|
92
96
|
end
|
|
93
97
|
end
|
|
94
98
|
|
|
@@ -100,14 +104,13 @@ module Datadog
|
|
|
100
104
|
# guaranteed to not end up with no component when one is running.
|
|
101
105
|
def add_current_component(component)
|
|
102
106
|
LOCK.synchronize do
|
|
103
|
-
@current_components ||= []
|
|
104
107
|
@current_components << component
|
|
105
108
|
end
|
|
106
109
|
end
|
|
107
110
|
|
|
108
111
|
def remove_current_component(component)
|
|
109
112
|
LOCK.synchronize do
|
|
110
|
-
@current_components
|
|
113
|
+
@current_components.delete(component)
|
|
111
114
|
end
|
|
112
115
|
end
|
|
113
116
|
end
|
|
@@ -22,11 +22,114 @@ module Datadog
|
|
|
22
22
|
class CodeTracker
|
|
23
23
|
def initialize
|
|
24
24
|
@registry = {}
|
|
25
|
+
@per_method_registry = {}
|
|
25
26
|
@trace_point_lock = Mutex.new
|
|
26
27
|
@registry_lock = Mutex.new
|
|
27
28
|
@compiled_trace_point = nil
|
|
28
29
|
end
|
|
29
30
|
|
|
31
|
+
# Populates the registry with iseqs for files that were loaded
|
|
32
|
+
# before code tracking started.
|
|
33
|
+
#
|
|
34
|
+
# Uses the all_iseqs C extension to walk the Ruby object space and
|
|
35
|
+
# find instruction sequences for already-loaded code. Whole-file
|
|
36
|
+
# iseqs are stored in the main registry; per-method/block/class
|
|
37
|
+
# iseqs are stored in per_method_registry as fallback for files
|
|
38
|
+
# whose whole-file iseq was GC'd.
|
|
39
|
+
#
|
|
40
|
+
# See docs/DynamicInstrumentationDevelopment.md "Iseq Lifecycle and GC"
|
|
41
|
+
# for which iseq types survive GC and implications for backfill.
|
|
42
|
+
#
|
|
43
|
+
# Whole-file detection uses two strategies:
|
|
44
|
+
# - Ruby 3.1+: DI.iseq_type (wraps rb_iseq_type) returns :top for
|
|
45
|
+
# require/load and :main for the entry script. This is precise.
|
|
46
|
+
# - Ruby < 3.1: falls back to first_lineno == 0, which is true for
|
|
47
|
+
# whole-file iseqs from require/load (INT2FIX(0) in Ruby's
|
|
48
|
+
# rb_iseq_new_top and rb_iseq_new_main) and false for
|
|
49
|
+
# method/block/class definitions (first_lineno >= 1).
|
|
50
|
+
# InstructionSequence.compile passes first_lineno = 1 by default,
|
|
51
|
+
# so eval'd code is not matched. Both strategies produce the same
|
|
52
|
+
# result in practice.
|
|
53
|
+
#
|
|
54
|
+
# Does not overwrite iseqs already in the registry (from
|
|
55
|
+
# :script_compiled), since those are guaranteed to be whole-file
|
|
56
|
+
# iseqs and are authoritative.
|
|
57
|
+
#
|
|
58
|
+
# @return [void]
|
|
59
|
+
def backfill_registry
|
|
60
|
+
iseqs = DI.file_iseqs
|
|
61
|
+
have_iseq_type = DI.respond_to?(:iseq_type)
|
|
62
|
+
registry_lock.synchronize do
|
|
63
|
+
iseqs.each do |iseq|
|
|
64
|
+
path = iseq.absolute_path
|
|
65
|
+
next unless path
|
|
66
|
+
|
|
67
|
+
whole_file = if have_iseq_type
|
|
68
|
+
type = DI.iseq_type(iseq)
|
|
69
|
+
# Require first_lineno == 0 to exclude compile_file/compile
|
|
70
|
+
# iseqs. These are :top type but have first_lineno == 1 and
|
|
71
|
+
# produce iseq objects distinct from require-produced iseqs.
|
|
72
|
+
# Targeted TracePoints are bound to the specific iseq object
|
|
73
|
+
# — a probe on a compile_file iseq silently never fires when
|
|
74
|
+
# the require-produced code runs.
|
|
75
|
+
(type == :top || type == :main) && iseq.first_lineno == 0
|
|
76
|
+
else
|
|
77
|
+
iseq.first_lineno == 0
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
if whole_file
|
|
81
|
+
# Ruby 3.2.9+ creates dummy profiler iseqs during require/load
|
|
82
|
+
# (rb_iseq_alloc_with_dummy_path in iseq.c). These have type
|
|
83
|
+
# :top, first_lineno == 0, and the same absolute_path as the
|
|
84
|
+
# real iseq — but iseq_size == 0 (no bytecode). A targeted
|
|
85
|
+
# TracePoint on a dummy iseq can't find child iseqs and raises
|
|
86
|
+
# ArgumentError "can not enable any hooks". Filter them out:
|
|
87
|
+
# a real top-level iseq always has at least one trace event.
|
|
88
|
+
next if iseq.trace_points.empty?
|
|
89
|
+
|
|
90
|
+
# Do not overwrite entries from :script_compiled — those are
|
|
91
|
+
# captured at load time and are authoritative.
|
|
92
|
+
next if registry.key?(path)
|
|
93
|
+
|
|
94
|
+
registry[path] = iseq
|
|
95
|
+
else
|
|
96
|
+
# Skip top-level script iseqs (:top/:main) produced by
|
|
97
|
+
# RubyVM::InstructionSequence.compile_file and .compile
|
|
98
|
+
# (compile source to bytecode without executing it).
|
|
99
|
+
# These represent the file body,
|
|
100
|
+
# not a method or block. They pass the first_lineno check
|
|
101
|
+
# (lineno != 0) but a targeted TracePoint bound to one
|
|
102
|
+
# of these never fires for method-level code — the
|
|
103
|
+
# user's probe silently produces no snapshots.
|
|
104
|
+
#
|
|
105
|
+
# On Ruby < 3.1 (no iseq_type), we cannot distinguish
|
|
106
|
+
# these from method iseqs, so they leak into
|
|
107
|
+
# per_method_registry. If iseq_for_line selects a leaked
|
|
108
|
+
# top-level iseq instead of the real method iseq, the
|
|
109
|
+
# probe installs but silently never fires — same failure
|
|
110
|
+
# as above. This requires the application to call
|
|
111
|
+
# compile_file and hold the result, which is rare outside
|
|
112
|
+
# tooling like bootsnap (which discards it).
|
|
113
|
+
next if have_iseq_type && (type == :top || type == :main)
|
|
114
|
+
|
|
115
|
+
# Store per-method/block/class iseqs as fallback for files
|
|
116
|
+
# whose whole-file iseq was GC'd. These can be used to
|
|
117
|
+
# target line probes on lines within their range.
|
|
118
|
+
(per_method_registry[path] ||= []) << iseq
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
nil
|
|
123
|
+
rescue => exc
|
|
124
|
+
# Backfill is best-effort — if it fails, line probes on
|
|
125
|
+
# pre-loaded code won't work but everything else is unaffected.
|
|
126
|
+
if component = DI.current_component
|
|
127
|
+
component.logger.debug { "di: backfill_registry failed: #{exc.class}: #{exc.message}" }
|
|
128
|
+
component.telemetry&.report(exc, description: "backfill_registry failed")
|
|
129
|
+
end
|
|
130
|
+
nil
|
|
131
|
+
end
|
|
132
|
+
|
|
30
133
|
# Starts tracking loaded code.
|
|
31
134
|
#
|
|
32
135
|
# This method should generally be called early in application boot
|
|
@@ -94,7 +197,7 @@ module Datadog
|
|
|
94
197
|
# but we will have DI.current_component (set to nil).
|
|
95
198
|
if component = DI.current_component
|
|
96
199
|
raise if component.settings.dynamic_instrumentation.internal.propagate_all_exceptions
|
|
97
|
-
component.logger.debug { "di: unhandled exception in script_compiled trace point: #{exc.class}: #{exc}" }
|
|
200
|
+
component.logger.debug { "di: unhandled exception in script_compiled trace point: #{exc.class}: #{exc.message}" }
|
|
98
201
|
component.telemetry&.report(exc, description: "Unhandled exception in script_compiled trace point")
|
|
99
202
|
# TODO test this path
|
|
100
203
|
else
|
|
@@ -104,6 +207,12 @@ module Datadog
|
|
|
104
207
|
# TODO test this path
|
|
105
208
|
end
|
|
106
209
|
end
|
|
210
|
+
|
|
211
|
+
# Backfill the registry with iseqs for files that were loaded
|
|
212
|
+
# before tracking started. This must happen after the trace
|
|
213
|
+
# point is enabled so that any files loaded concurrently are
|
|
214
|
+
# captured by the trace point (backfill won't overwrite them).
|
|
215
|
+
backfill_registry
|
|
107
216
|
end
|
|
108
217
|
end
|
|
109
218
|
|
|
@@ -160,6 +269,51 @@ module Datadog
|
|
|
160
269
|
end
|
|
161
270
|
end
|
|
162
271
|
|
|
272
|
+
# Returns a [path, iseq] pair for a line probe target, or nil.
|
|
273
|
+
#
|
|
274
|
+
# First checks the whole-file iseq registry (via iseqs_for_path_suffix).
|
|
275
|
+
# If no whole-file iseq exists, searches the per-method iseq registry
|
|
276
|
+
# for an iseq whose trace_points include the target line.
|
|
277
|
+
#
|
|
278
|
+
# @param suffix [String] file path or suffix to match
|
|
279
|
+
# @param line [Integer] target line number
|
|
280
|
+
# @return [Array(String, RubyVM::InstructionSequence), nil]
|
|
281
|
+
def iseq_for_line(suffix, line)
|
|
282
|
+
# Try whole-file iseq first — it always covers all lines.
|
|
283
|
+
result = iseqs_for_path_suffix(suffix)
|
|
284
|
+
return result if result
|
|
285
|
+
|
|
286
|
+
# Fall back to per-method iseqs.
|
|
287
|
+
registry_lock.synchronize do
|
|
288
|
+
# Resolve the path using the per-method registry keys.
|
|
289
|
+
path = resolve_path_suffix(suffix, per_method_registry.keys)
|
|
290
|
+
return nil unless path
|
|
291
|
+
|
|
292
|
+
iseqs = per_method_registry[path]
|
|
293
|
+
return nil unless iseqs
|
|
294
|
+
|
|
295
|
+
# Only match event types the instrumenter subscribes to
|
|
296
|
+
# (:line, :return, :b_return — see hook_line). Lines that
|
|
297
|
+
# only carry :call (e.g. a `def` line within the defined
|
|
298
|
+
# method's own iseq, not the enclosing scope) have no
|
|
299
|
+
# subscribed event at that position; TracePoint#enable
|
|
300
|
+
# raises because it cannot bind an enabled event there.
|
|
301
|
+
matches = iseqs.select do |iseq|
|
|
302
|
+
iseq.trace_points.any? do |tp_line, event|
|
|
303
|
+
tp_line == line && (event == :line || event == :return || event == :b_return)
|
|
304
|
+
end
|
|
305
|
+
end
|
|
306
|
+
# When multiple iseqs contain the target line (e.g. a method
|
|
307
|
+
# and an inline block sharing the same line), picking one
|
|
308
|
+
# would silently miss executions in the other context.
|
|
309
|
+
# Raise so the probe is recorded as failed with a clear error.
|
|
310
|
+
if matches.length > 1
|
|
311
|
+
raise Error::MultiplePathsMatch, "Multiple code locations match line #{line}"
|
|
312
|
+
end
|
|
313
|
+
matches.first ? [path, matches.first] : nil
|
|
314
|
+
end
|
|
315
|
+
end
|
|
316
|
+
|
|
163
317
|
# Stops tracking code that is being loaded.
|
|
164
318
|
#
|
|
165
319
|
# This method should ordinarily never be called - if a file is loaded
|
|
@@ -186,6 +340,7 @@ module Datadog
|
|
|
186
340
|
def clear
|
|
187
341
|
registry_lock.synchronize do
|
|
188
342
|
registry.clear
|
|
343
|
+
per_method_registry.clear
|
|
189
344
|
end
|
|
190
345
|
end
|
|
191
346
|
|
|
@@ -195,8 +350,31 @@ module Datadog
|
|
|
195
350
|
# objects representing compiled code of those files.
|
|
196
351
|
attr_reader :registry
|
|
197
352
|
|
|
353
|
+
# Mapping from paths to arrays of per-method/block/class iseqs.
|
|
354
|
+
# Used as fallback when the whole-file iseq has been GC'd.
|
|
355
|
+
attr_reader :per_method_registry
|
|
356
|
+
|
|
198
357
|
attr_reader :trace_point_lock
|
|
199
358
|
attr_reader :registry_lock
|
|
359
|
+
|
|
360
|
+
# Resolves a path suffix against a set of known paths.
|
|
361
|
+
# Returns the matching path or nil.
|
|
362
|
+
#
|
|
363
|
+
# Must be called within registry_lock.
|
|
364
|
+
def resolve_path_suffix(suffix, paths)
|
|
365
|
+
# Exact match.
|
|
366
|
+
return suffix if paths.include?(suffix)
|
|
367
|
+
|
|
368
|
+
# Suffix match.
|
|
369
|
+
suffix = suffix.dup
|
|
370
|
+
loop do
|
|
371
|
+
matches = paths.select { |p| Utils.path_matches_suffix?(p, suffix) }
|
|
372
|
+
raise Error::MultiplePathsMatch, "Multiple paths matched requested suffix" if matches.length > 1
|
|
373
|
+
return matches.first if matches.any?
|
|
374
|
+
return nil unless suffix.include?('/')
|
|
375
|
+
suffix.sub!(%r{.*/+}, '')
|
|
376
|
+
end
|
|
377
|
+
end
|
|
200
378
|
end
|
|
201
379
|
end
|
|
202
380
|
end
|
data/lib/datadog/di/component.rb
CHANGED
|
@@ -122,7 +122,7 @@ module Datadog
|
|
|
122
122
|
payload = probe_notification_builder.build_errored(probe, exc)
|
|
123
123
|
probe_notifier_worker.add_status(payload)
|
|
124
124
|
rescue => nested_exc
|
|
125
|
-
logger.debug { "di: failed to build error notification: #{nested_exc.class}: #{nested_exc}" }
|
|
125
|
+
logger.debug { "di: failed to build error notification: #{nested_exc.class}: #{nested_exc.message}" }
|
|
126
126
|
telemetry&.report(nested_exc, description: 'Error building probe error notification')
|
|
127
127
|
raise
|
|
128
128
|
end
|