datadog 2.1.0 → 2.3.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 +101 -1
- data/ext/datadog_profiling_loader/extconf.rb +15 -15
- data/ext/datadog_profiling_native_extension/clock_id.h +1 -0
- data/ext/datadog_profiling_native_extension/clock_id_from_pthread.c +1 -2
- data/ext/datadog_profiling_native_extension/clock_id_noop.c +1 -2
- data/ext/datadog_profiling_native_extension/collectors_cpu_and_wall_time_worker.c +132 -44
- data/ext/datadog_profiling_native_extension/collectors_discrete_dynamic_sampler.c +49 -26
- data/ext/datadog_profiling_native_extension/collectors_discrete_dynamic_sampler.h +34 -4
- data/ext/datadog_profiling_native_extension/collectors_idle_sampling_helper.c +4 -0
- data/ext/datadog_profiling_native_extension/collectors_stack.c +90 -37
- data/ext/datadog_profiling_native_extension/collectors_stack.h +2 -2
- data/ext/datadog_profiling_native_extension/collectors_thread_context.c +81 -19
- data/ext/datadog_profiling_native_extension/collectors_thread_context.h +1 -0
- data/ext/datadog_profiling_native_extension/datadog_ruby_common.c +110 -0
- data/ext/datadog_profiling_native_extension/datadog_ruby_common.h +57 -0
- data/ext/datadog_profiling_native_extension/extconf.rb +69 -62
- data/ext/datadog_profiling_native_extension/heap_recorder.c +34 -6
- data/ext/datadog_profiling_native_extension/heap_recorder.h +3 -1
- data/ext/datadog_profiling_native_extension/helpers.h +6 -17
- data/ext/datadog_profiling_native_extension/http_transport.c +3 -3
- data/ext/datadog_profiling_native_extension/libdatadog_helpers.c +0 -86
- data/ext/datadog_profiling_native_extension/libdatadog_helpers.h +2 -23
- data/ext/datadog_profiling_native_extension/native_extension_helpers.rb +61 -126
- data/ext/datadog_profiling_native_extension/private_vm_api_access.c +64 -138
- data/ext/datadog_profiling_native_extension/private_vm_api_access.h +17 -11
- data/ext/datadog_profiling_native_extension/profiling.c +0 -2
- data/ext/datadog_profiling_native_extension/ruby_helpers.c +0 -33
- data/ext/datadog_profiling_native_extension/ruby_helpers.h +1 -26
- data/ext/datadog_profiling_native_extension/setup_signal_handler.c +1 -1
- data/ext/datadog_profiling_native_extension/setup_signal_handler.h +1 -0
- data/ext/datadog_profiling_native_extension/stack_recorder.c +27 -8
- data/ext/datadog_profiling_native_extension/stack_recorder.h +2 -0
- data/ext/datadog_profiling_native_extension/time_helpers.c +0 -15
- data/ext/datadog_profiling_native_extension/time_helpers.h +36 -6
- data/ext/{datadog_profiling_native_extension → libdatadog_api}/crashtracker.c +20 -7
- data/ext/libdatadog_api/datadog_ruby_common.c +110 -0
- data/ext/libdatadog_api/datadog_ruby_common.h +57 -0
- data/ext/libdatadog_api/extconf.rb +108 -0
- data/ext/libdatadog_api/macos_development.md +26 -0
- data/ext/libdatadog_extconf_helpers.rb +130 -0
- data/lib/datadog/appsec/contrib/graphql/appsec_trace.rb +49 -0
- data/lib/datadog/appsec/contrib/graphql/gateway/multiplex.rb +73 -0
- data/lib/datadog/appsec/contrib/graphql/gateway/watcher.rb +68 -0
- data/lib/datadog/appsec/contrib/graphql/integration.rb +41 -0
- data/lib/datadog/appsec/contrib/graphql/patcher.rb +37 -0
- data/lib/datadog/appsec/contrib/graphql/reactive/multiplex.rb +59 -0
- data/lib/datadog/appsec/contrib/rack/gateway/request.rb +1 -1
- data/lib/datadog/appsec/contrib/sinatra/patcher.rb +1 -1
- data/lib/datadog/appsec/extensions.rb +1 -0
- data/lib/datadog/appsec/processor/actions.rb +1 -1
- data/lib/datadog/appsec/response.rb +15 -1
- data/lib/datadog/appsec.rb +1 -0
- data/lib/datadog/core/configuration/components.rb +17 -12
- data/lib/datadog/core/configuration/settings.rb +93 -7
- data/lib/datadog/core/configuration.rb +3 -17
- data/lib/datadog/core/crashtracking/agent_base_url.rb +21 -0
- data/lib/datadog/core/crashtracking/component.rb +111 -0
- data/lib/datadog/core/crashtracking/tag_builder.rb +39 -0
- data/lib/datadog/core/deprecations.rb +58 -0
- data/lib/datadog/core/diagnostics/environment_logger.rb +8 -11
- data/lib/datadog/core/environment/yjit.rb +5 -0
- data/lib/datadog/core/runtime/ext.rb +1 -0
- data/lib/datadog/core/runtime/metrics.rb +6 -0
- data/lib/datadog/core/telemetry/component.rb +154 -0
- data/lib/datadog/core/telemetry/emitter.rb +9 -11
- data/lib/datadog/core/telemetry/event.rb +132 -26
- data/lib/datadog/core/telemetry/ext.rb +3 -0
- data/lib/datadog/core/telemetry/http/adapters/net.rb +11 -13
- data/lib/datadog/core/telemetry/http/ext.rb +3 -0
- data/lib/datadog/core/telemetry/http/transport.rb +38 -9
- data/lib/datadog/core/telemetry/logging.rb +35 -0
- data/lib/datadog/core/telemetry/metric.rb +167 -0
- data/lib/datadog/core/telemetry/metrics_collection.rb +81 -0
- data/lib/datadog/core/telemetry/metrics_manager.rb +81 -0
- data/lib/datadog/core/telemetry/request.rb +1 -1
- data/lib/datadog/core/telemetry/worker.rb +173 -0
- data/lib/datadog/core/utils/at_fork_monkey_patch.rb +102 -0
- data/lib/datadog/core/utils/only_once_successful.rb +76 -0
- data/lib/datadog/core.rb +2 -19
- data/lib/datadog/kit/appsec/events.rb +2 -4
- data/lib/datadog/opentelemetry/sdk/propagator.rb +5 -10
- data/lib/datadog/opentelemetry/sdk/span_processor.rb +15 -2
- data/lib/datadog/opentelemetry/sdk/trace/span.rb +23 -0
- data/lib/datadog/profiling/collectors/code_provenance.rb +24 -11
- data/lib/datadog/profiling/collectors/cpu_and_wall_time_worker.rb +17 -17
- data/lib/datadog/profiling/collectors/idle_sampling_helper.rb +11 -13
- data/lib/datadog/profiling/collectors/info.rb +3 -3
- data/lib/datadog/profiling/collectors/thread_context.rb +4 -2
- data/lib/datadog/profiling/component.rb +85 -90
- data/lib/datadog/profiling/exporter.rb +3 -3
- data/lib/datadog/profiling/ext/dir_monkey_patches.rb +410 -0
- data/lib/datadog/profiling/ext.rb +21 -21
- data/lib/datadog/profiling/flush.rb +1 -1
- data/lib/datadog/profiling/http_transport.rb +8 -6
- data/lib/datadog/profiling/load_native_extension.rb +5 -5
- data/lib/datadog/profiling/preload.rb +1 -1
- data/lib/datadog/profiling/profiler.rb +5 -8
- data/lib/datadog/profiling/scheduler.rb +31 -25
- data/lib/datadog/profiling/tag_builder.rb +2 -2
- data/lib/datadog/profiling/tasks/exec.rb +5 -5
- data/lib/datadog/profiling/tasks/setup.rb +16 -35
- data/lib/datadog/profiling.rb +5 -5
- data/lib/datadog/tracing/contrib/action_cable/event.rb +1 -1
- data/lib/datadog/tracing/contrib/action_cable/events/broadcast.rb +1 -1
- data/lib/datadog/tracing/contrib/action_cable/events/perform_action.rb +1 -1
- data/lib/datadog/tracing/contrib/action_cable/events/transmit.rb +1 -1
- data/lib/datadog/tracing/contrib/action_mailer/event.rb +4 -6
- data/lib/datadog/tracing/contrib/action_mailer/events/deliver.rb +9 -4
- data/lib/datadog/tracing/contrib/action_mailer/events/process.rb +3 -2
- data/lib/datadog/tracing/contrib/action_view/events/render_partial.rb +1 -5
- 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/events/instantiation.rb +1 -1
- data/lib/datadog/tracing/contrib/active_record/events/sql.rb +2 -1
- data/lib/datadog/tracing/contrib/active_support/cache/event.rb +32 -0
- data/lib/datadog/tracing/contrib/active_support/cache/events/cache.rb +156 -0
- data/lib/datadog/tracing/contrib/active_support/cache/events.rb +34 -0
- data/lib/datadog/tracing/contrib/active_support/cache/instrumentation.rb +45 -41
- data/lib/datadog/tracing/contrib/active_support/cache/patcher.rb +17 -40
- data/lib/datadog/tracing/contrib/active_support/cache/redis.rb +4 -1
- data/lib/datadog/tracing/contrib/active_support/notifications/event.rb +29 -6
- data/lib/datadog/tracing/contrib/active_support/notifications/subscriber.rb +16 -4
- data/lib/datadog/tracing/contrib/active_support/notifications/subscription.rb +33 -29
- data/lib/datadog/tracing/contrib/analytics.rb +5 -0
- data/lib/datadog/tracing/contrib/ext.rb +14 -0
- data/lib/datadog/tracing/contrib/graphql/configuration/settings.rb +5 -0
- data/lib/datadog/tracing/contrib/graphql/patcher.rb +8 -2
- data/lib/datadog/tracing/contrib/graphql/unified_trace.rb +166 -0
- data/lib/datadog/tracing/contrib/graphql/unified_trace_patcher.rb +28 -0
- data/lib/datadog/tracing/contrib/kafka/consumer_event.rb +1 -1
- data/lib/datadog/tracing/contrib/kafka/consumer_group_event.rb +1 -1
- data/lib/datadog/tracing/contrib/kafka/event.rb +1 -1
- data/lib/datadog/tracing/contrib/kafka/events/connection/request.rb +3 -3
- data/lib/datadog/tracing/contrib/kafka/events/consumer/process_batch.rb +3 -3
- data/lib/datadog/tracing/contrib/kafka/events/consumer/process_message.rb +3 -3
- data/lib/datadog/tracing/contrib/kafka/events/consumer_group/heartbeat.rb +3 -3
- data/lib/datadog/tracing/contrib/kafka/events/produce_operation/send_messages.rb +3 -3
- data/lib/datadog/tracing/contrib/kafka/events/producer/deliver_messages.rb +3 -3
- data/lib/datadog/tracing/contrib/lograge/patcher.rb +16 -0
- data/lib/datadog/tracing/contrib/mysql2/configuration/settings.rb +5 -0
- data/lib/datadog/tracing/contrib/mysql2/instrumentation.rb +17 -13
- data/lib/datadog/tracing/contrib/pg/configuration/settings.rb +5 -0
- data/lib/datadog/tracing/contrib/pg/instrumentation.rb +4 -1
- data/lib/datadog/tracing/contrib/propagation/sql_comment/ext.rb +28 -0
- data/lib/datadog/tracing/contrib/propagation/sql_comment/mode.rb +5 -1
- data/lib/datadog/tracing/contrib/propagation/sql_comment.rb +22 -10
- data/lib/datadog/tracing/contrib/racecar/event.rb +2 -2
- data/lib/datadog/tracing/contrib/rails/ext.rb +9 -0
- data/lib/datadog/tracing/contrib/rails/patcher.rb +7 -0
- data/lib/datadog/tracing/contrib/rails/runner.rb +95 -0
- data/lib/datadog/tracing/contrib/trilogy/configuration/settings.rb +5 -0
- data/lib/datadog/tracing/contrib/trilogy/instrumentation.rb +4 -1
- data/lib/datadog/tracing/diagnostics/environment_logger.rb +14 -16
- data/lib/datadog/tracing/distributed/b3_multi.rb +1 -1
- data/lib/datadog/tracing/distributed/b3_single.rb +3 -1
- data/lib/datadog/tracing/distributed/datadog.rb +2 -2
- data/lib/datadog/tracing/distributed/propagation.rb +9 -2
- data/lib/datadog/tracing/distributed/trace_context.rb +3 -2
- data/lib/datadog/tracing/metadata/errors.rb +9 -1
- data/lib/datadog/tracing/metadata/ext.rb +4 -0
- data/lib/datadog/tracing/pipeline/span_filter.rb +2 -2
- data/lib/datadog/tracing/span.rb +9 -2
- data/lib/datadog/tracing/span_event.rb +41 -0
- data/lib/datadog/tracing/span_operation.rb +9 -4
- data/lib/datadog/tracing/trace_operation.rb +7 -3
- data/lib/datadog/tracing/trace_segment.rb +4 -1
- data/lib/datadog/tracing/tracer.rb +9 -2
- data/lib/datadog/tracing/transport/serializable_trace.rb +3 -0
- data/lib/datadog/tracing.rb +5 -1
- data/lib/datadog/version.rb +2 -2
- metadata +43 -12
- data/lib/datadog/core/telemetry/client.rb +0 -95
- data/lib/datadog/core/telemetry/heartbeat.rb +0 -33
- data/lib/datadog/profiling/crashtracker.rb +0 -91
- data/lib/datadog/profiling/ext/forking.rb +0 -98
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
3
|
+
require "set"
|
4
|
+
require "json"
|
5
5
|
|
6
6
|
module Datadog
|
7
7
|
module Profiling
|
@@ -14,7 +14,7 @@ module Datadog
|
|
14
14
|
#
|
15
15
|
# This class acts both as a collector (collecting data) as well as a recorder (records/serializes it)
|
16
16
|
class CodeProvenance
|
17
|
-
def initialize(standard_library_path: RbConfig::CONFIG.fetch(
|
17
|
+
def initialize(standard_library_path: RbConfig::CONFIG.fetch("rubylibdir"))
|
18
18
|
@libraries_by_name = {}
|
19
19
|
@libraries_by_path = {}
|
20
20
|
@seen_files = Set.new
|
@@ -22,8 +22,8 @@ module Datadog
|
|
22
22
|
|
23
23
|
record_library(
|
24
24
|
Library.new(
|
25
|
-
kind:
|
26
|
-
name:
|
25
|
+
kind: "standard library",
|
26
|
+
name: "stdlib",
|
27
27
|
version: RUBY_VERSION,
|
28
28
|
path: standard_library_path,
|
29
29
|
)
|
@@ -79,7 +79,7 @@ module Datadog
|
|
79
79
|
loaded_specs.each do |spec|
|
80
80
|
next if libraries_by_name.key?(spec.name)
|
81
81
|
|
82
|
-
record_library(Library.new(kind:
|
82
|
+
record_library(Library.new(kind: "library", name: spec.name, version: spec.version, path: spec.gem_dir))
|
83
83
|
recorded_library = true
|
84
84
|
end
|
85
85
|
|
@@ -92,25 +92,38 @@ module Datadog
|
|
92
92
|
|
93
93
|
seen_files << file_path
|
94
94
|
|
95
|
-
|
96
|
-
|
95
|
+
# NOTE: Don't use .find, it allocates a lot more memory (see commit that added this note for details)
|
96
|
+
libraries_by_path.any? do |library_path, library|
|
97
|
+
seen_libraries << library if file_path.start_with?(library_path)
|
98
|
+
end
|
97
99
|
end
|
98
100
|
end
|
99
101
|
|
100
102
|
# Represents metadata we have for a ruby gem
|
103
|
+
#
|
104
|
+
# Important note: This class gets encoded to JSON with the built-in JSON gem. But, we've found that in some
|
105
|
+
# buggy cases, some Ruby gems monkey patch the built-in JSON gem and forget to call #to_json, and instead
|
106
|
+
# encode this class instance-field-by-instance-field.
|
107
|
+
#
|
108
|
+
# Thus, this class was setup to match the JSON output. Take this into consideration if you are adding new
|
109
|
+
# fields. (Also, we have a spec for this)
|
101
110
|
class Library
|
102
|
-
attr_reader :kind, :name, :version
|
111
|
+
attr_reader :kind, :name, :version
|
103
112
|
|
104
113
|
def initialize(kind:, name:, version:, path:)
|
105
114
|
@kind = kind.freeze
|
106
115
|
@name = name.dup.freeze
|
107
116
|
@version = version.to_s.dup.freeze
|
108
|
-
@
|
117
|
+
@paths = [path.dup.freeze].freeze
|
109
118
|
freeze
|
110
119
|
end
|
111
120
|
|
112
121
|
def to_json(arg = nil)
|
113
|
-
{
|
122
|
+
{kind: @kind, name: @name, version: @version, paths: @paths}.to_json(arg)
|
123
|
+
end
|
124
|
+
|
125
|
+
def path
|
126
|
+
@paths.first
|
114
127
|
end
|
115
128
|
end
|
116
129
|
end
|
@@ -21,6 +21,7 @@ module Datadog
|
|
21
21
|
thread_context_collector:,
|
22
22
|
dynamic_sampling_rate_overhead_target_percentage:,
|
23
23
|
allocation_profiling_enabled:,
|
24
|
+
allocation_counting_enabled:,
|
24
25
|
# **NOTE**: This should only be used for testing; disabling the dynamic sampling rate will increase the
|
25
26
|
# profiler overhead!
|
26
27
|
dynamic_sampling_rate_enabled: true,
|
@@ -29,7 +30,7 @@ module Datadog
|
|
29
30
|
)
|
30
31
|
unless dynamic_sampling_rate_enabled
|
31
32
|
Datadog.logger.warn(
|
32
|
-
|
33
|
+
"Profiling dynamic sampling rate disabled. This should only be used for testing, and will increase overhead!"
|
33
34
|
)
|
34
35
|
end
|
35
36
|
|
@@ -42,6 +43,7 @@ module Datadog
|
|
42
43
|
dynamic_sampling_rate_enabled,
|
43
44
|
dynamic_sampling_rate_overhead_target_percentage,
|
44
45
|
allocation_profiling_enabled,
|
46
|
+
allocation_counting_enabled,
|
45
47
|
skip_idle_samples_for_testing,
|
46
48
|
)
|
47
49
|
@worker_thread = nil
|
@@ -54,27 +56,25 @@ module Datadog
|
|
54
56
|
|
55
57
|
def start(on_failure_proc: nil)
|
56
58
|
@start_stop_mutex.synchronize do
|
57
|
-
return if @worker_thread
|
59
|
+
return if @worker_thread&.alive?
|
58
60
|
|
59
61
|
Datadog.logger.debug { "Starting thread for: #{self}" }
|
60
62
|
|
61
63
|
@idle_sampling_helper.start
|
62
64
|
|
63
65
|
@worker_thread = Thread.new do
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
on_failure_proc&.call
|
77
|
-
end
|
66
|
+
Thread.current.name = self.class.name
|
67
|
+
|
68
|
+
self.class._native_sampling_loop(self)
|
69
|
+
|
70
|
+
Datadog.logger.debug("CpuAndWallTimeWorker thread stopping cleanly")
|
71
|
+
rescue Exception => e # rubocop:disable Lint/RescueException
|
72
|
+
@failure_exception = e
|
73
|
+
Datadog.logger.warn(
|
74
|
+
"CpuAndWallTimeWorker thread error. " \
|
75
|
+
"Cause: #{e.class.name} #{e.message} Location: #{Array(e.backtrace).first}"
|
76
|
+
)
|
77
|
+
on_failure_proc&.call
|
78
78
|
end
|
79
79
|
@worker_thread.name = self.class.name # Repeated from above to make sure thread gets named asap
|
80
80
|
@worker_thread.thread_variable_set(:fork_safe, true)
|
@@ -85,7 +85,7 @@ module Datadog
|
|
85
85
|
|
86
86
|
def stop
|
87
87
|
@start_stop_mutex.synchronize do
|
88
|
-
Datadog.logger.debug(
|
88
|
+
Datadog.logger.debug("Requesting CpuAndWallTimeWorker thread shut down")
|
89
89
|
|
90
90
|
@idle_sampling_helper.stop
|
91
91
|
|
@@ -21,7 +21,7 @@ module Datadog
|
|
21
21
|
|
22
22
|
def start
|
23
23
|
@start_stop_mutex.synchronize do
|
24
|
-
return if @worker_thread
|
24
|
+
return if @worker_thread&.alive?
|
25
25
|
|
26
26
|
Datadog.logger.debug { "Starting thread for: #{self}" }
|
27
27
|
|
@@ -30,19 +30,17 @@ module Datadog
|
|
30
30
|
self.class._native_reset(self)
|
31
31
|
|
32
32
|
@worker_thread = Thread.new do
|
33
|
-
|
34
|
-
Thread.current.name = self.class.name
|
33
|
+
Thread.current.name = self.class.name
|
35
34
|
|
36
|
-
|
35
|
+
self.class._native_idle_sampling_loop(self)
|
37
36
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
end
|
37
|
+
Datadog.logger.debug("IdleSamplingHelper thread stopping cleanly")
|
38
|
+
rescue Exception => e # rubocop:disable Lint/RescueException
|
39
|
+
@failure_exception = e
|
40
|
+
Datadog.logger.warn(
|
41
|
+
"IdleSamplingHelper thread error. " \
|
42
|
+
"Cause: #{e.class.name} #{e.message} Location: #{Array(e.backtrace).first}"
|
43
|
+
)
|
46
44
|
end
|
47
45
|
@worker_thread.name = self.class.name # Repeated from above to make sure thread gets named asap
|
48
46
|
@worker_thread.thread_variable_set(:fork_safe, true)
|
@@ -53,7 +51,7 @@ module Datadog
|
|
53
51
|
|
54
52
|
def stop
|
55
53
|
@start_stop_mutex.synchronize do
|
56
|
-
Datadog.logger.debug(
|
54
|
+
Datadog.logger.debug("Requesting IdleSamplingHelper thread shut down")
|
57
55
|
|
58
56
|
return unless @worker_thread
|
59
57
|
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
3
|
+
require "set"
|
4
|
+
require "time"
|
5
5
|
|
6
6
|
module Datadog
|
7
7
|
module Profiling
|
@@ -61,7 +61,7 @@ module Datadog
|
|
61
61
|
|
62
62
|
def collect_profiler_info(settings)
|
63
63
|
unless @profiler_info
|
64
|
-
lib_datadog_gem = ::Gem.loaded_specs[
|
64
|
+
lib_datadog_gem = ::Gem.loaded_specs["libdatadog"]
|
65
65
|
@profiler_info = {
|
66
66
|
# TODO: If profiling is extracted and its version diverges from the datadog gem, this is inaccurate.
|
67
67
|
# Update if this ever occurs.
|
@@ -48,12 +48,14 @@ module Datadog
|
|
48
48
|
private
|
49
49
|
|
50
50
|
def safely_extract_context_key_from(tracer)
|
51
|
-
|
51
|
+
return unless tracer
|
52
|
+
|
53
|
+
provider = tracer.respond_to?(:provider) && tracer.provider
|
52
54
|
|
53
55
|
return unless provider
|
54
56
|
|
55
57
|
context = provider.instance_variable_get(:@context)
|
56
|
-
context
|
58
|
+
context&.instance_variable_get(:@key)
|
57
59
|
end
|
58
60
|
end
|
59
61
|
end
|
@@ -8,7 +8,7 @@ module Datadog
|
|
8
8
|
# * Code Hotspots panel in the trace viewer, as well as scoping a profile down to a span
|
9
9
|
# * Endpoint aggregation in the profiler UX, including normalization (resource per endpoint call)
|
10
10
|
def self.build_profiler_component(settings:, agent_settings:, optional_tracer:) # rubocop:disable Metrics/MethodLength
|
11
|
-
return [nil, {
|
11
|
+
return [nil, {profiling_enabled: false}] unless settings.profiling.enabled
|
12
12
|
|
13
13
|
# Workaround for weird dependency direction: the Core::Configuration::Components class currently has a
|
14
14
|
# dependency on individual products, in this case the Profiler.
|
@@ -27,9 +27,9 @@ module Datadog
|
|
27
27
|
# On the other hand, if datadog/core is loaded by a different product and no general `require 'datadog'` is
|
28
28
|
# done, then profiling may not be loaded, and thus to avoid this issue we do a require here (which is a
|
29
29
|
# no-op if profiling is already loaded).
|
30
|
-
require_relative
|
30
|
+
require_relative "../profiling"
|
31
31
|
|
32
|
-
return [nil, {
|
32
|
+
return [nil, {profiling_enabled: false}] unless Profiling.supported?
|
33
33
|
|
34
34
|
# Activate forking extensions
|
35
35
|
Profiling::Tasks::Setup.new.run
|
@@ -47,7 +47,7 @@ module Datadog
|
|
47
47
|
upload_period_seconds = [60, settings.profiling.advanced.upload_period_seconds].max
|
48
48
|
|
49
49
|
recorder = Datadog::Profiling::StackRecorder.new(
|
50
|
-
cpu_time_enabled: RUBY_PLATFORM.include?(
|
50
|
+
cpu_time_enabled: RUBY_PLATFORM.include?("linux"), # Only supported on Linux currently
|
51
51
|
alloc_samples_enabled: allocation_profiling_enabled,
|
52
52
|
heap_samples_enabled: heap_profiling_enabled,
|
53
53
|
heap_size_enabled: heap_size_profiling_enabled,
|
@@ -61,6 +61,7 @@ module Datadog
|
|
61
61
|
thread_context_collector: thread_context_collector,
|
62
62
|
dynamic_sampling_rate_overhead_target_percentage: overhead_target_percentage,
|
63
63
|
allocation_profiling_enabled: allocation_profiling_enabled,
|
64
|
+
allocation_counting_enabled: settings.profiling.advanced.allocation_counting_enabled,
|
64
65
|
)
|
65
66
|
|
66
67
|
internal_metadata = {
|
@@ -72,10 +73,13 @@ module Datadog
|
|
72
73
|
exporter = build_profiler_exporter(settings, recorder, worker, internal_metadata: internal_metadata)
|
73
74
|
transport = build_profiler_transport(settings, agent_settings)
|
74
75
|
scheduler = Profiling::Scheduler.new(exporter: exporter, transport: transport, interval: upload_period_seconds)
|
75
|
-
|
76
|
-
profiler = Profiling::Profiler.new(worker: worker, scheduler: scheduler, optional_crashtracker: crashtracker)
|
76
|
+
profiler = Profiling::Profiler.new(worker: worker, scheduler: scheduler)
|
77
77
|
|
78
|
-
|
78
|
+
if dir_interruption_workaround_enabled?(settings, no_signals_workaround_enabled)
|
79
|
+
Datadog::Profiling::Ext::DirMonkeyPatches.apply!
|
80
|
+
end
|
81
|
+
|
82
|
+
[profiler, {profiling_enabled: true}]
|
79
83
|
end
|
80
84
|
|
81
85
|
private_class_method def self.build_thread_context_collector(settings, recorder, optional_tracer, timeline_enabled)
|
@@ -112,28 +116,6 @@ module Datadog
|
|
112
116
|
)
|
113
117
|
end
|
114
118
|
|
115
|
-
private_class_method def self.build_crashtracker(settings, transport)
|
116
|
-
return unless settings.profiling.advanced.experimental_crash_tracking_enabled
|
117
|
-
|
118
|
-
# By default, the transport is an instance of HttpTransport, which validates the configuration and makes
|
119
|
-
# it available for us to use here.
|
120
|
-
# But we support overriding the transport with a user-specific one, which may e.g. write stuff to a file,
|
121
|
-
# and thus can't really provide a valid configuration to talk to a Datadog agent. Thus, in this situation,
|
122
|
-
# we can't use the crashtracker, even if enabled.
|
123
|
-
unless transport.respond_to?(:exporter_configuration)
|
124
|
-
Datadog.logger.warn(
|
125
|
-
'Cannot enable profiling crash tracking as a custom settings.profiling.exporter.transport is configured'
|
126
|
-
)
|
127
|
-
return
|
128
|
-
end
|
129
|
-
|
130
|
-
Datadog::Profiling::Crashtracker.new(
|
131
|
-
exporter_configuration: transport.exporter_configuration,
|
132
|
-
tags: Datadog::Profiling::TagBuilder.call(settings: settings),
|
133
|
-
upload_timeout_seconds: settings.profiling.upload.timeout_seconds,
|
134
|
-
)
|
135
|
-
end
|
136
|
-
|
137
119
|
private_class_method def self.enable_gc_profiling?(settings)
|
138
120
|
return false unless settings.profiling.advanced.gc_enabled
|
139
121
|
|
@@ -142,19 +124,19 @@ module Datadog
|
|
142
124
|
# that causes a segmentation fault during garbage collection of Ractors
|
143
125
|
# (https://bugs.ruby-lang.org/issues/18464). We don't allow enabling gc profiling on such Rubies.
|
144
126
|
# This bug is fixed on Ruby versions 3.1.4, 3.2.3 and 3.3.0.
|
145
|
-
if RUBY_VERSION.start_with?(
|
146
|
-
(RUBY_VERSION.start_with?(
|
147
|
-
(RUBY_VERSION.start_with?(
|
127
|
+
if RUBY_VERSION.start_with?("3.0.") ||
|
128
|
+
(RUBY_VERSION.start_with?("3.1.") && RUBY_VERSION < "3.1.4") ||
|
129
|
+
(RUBY_VERSION.start_with?("3.2.") && RUBY_VERSION < "3.2.3")
|
148
130
|
Datadog.logger.warn(
|
149
|
-
"Current Ruby version (#{RUBY_VERSION}) has a VM bug where enabling GC profiling would cause "\
|
150
|
-
|
131
|
+
"Current Ruby version (#{RUBY_VERSION}) has a VM bug where enabling GC profiling would cause " \
|
132
|
+
"crashes (https://bugs.ruby-lang.org/issues/18464). GC profiling has been disabled."
|
151
133
|
)
|
152
134
|
return false
|
153
|
-
elsif RUBY_VERSION.start_with?(
|
135
|
+
elsif RUBY_VERSION.start_with?("3.")
|
154
136
|
Datadog.logger.debug(
|
155
|
-
|
156
|
-
|
157
|
-
|
137
|
+
"In all known versions of Ruby 3.x, using Ractors may result in GC profiling unexpectedly " \
|
138
|
+
"stopping (https://bugs.ruby-lang.org/issues/19112). Note that this stop has no impact in your " \
|
139
|
+
"application stability or performance. This does not happen if Ractors are not used."
|
158
140
|
)
|
159
141
|
end
|
160
142
|
|
@@ -178,11 +160,11 @@ module Datadog
|
|
178
160
|
# Ruby 3.2.0 to 3.2.2 have a bug in the newobj tracepoint (https://bugs.ruby-lang.org/issues/19482,
|
179
161
|
# https://github.com/ruby/ruby/pull/7464) that makes this crash in any configuration. This bug is
|
180
162
|
# fixed on Ruby versions 3.2.3 and 3.3.0.
|
181
|
-
if RUBY_VERSION.start_with?(
|
163
|
+
if RUBY_VERSION.start_with?("3.2.") && RUBY_VERSION < "3.2.3"
|
182
164
|
Datadog.logger.warn(
|
183
|
-
|
184
|
-
|
185
|
-
|
165
|
+
"Allocation profiling is not supported in Ruby versions 3.2.0, 3.2.1 and 3.2.2 and will be forcibly " \
|
166
|
+
"disabled. This is due to a VM bug that can lead to crashes (https://bugs.ruby-lang.org/issues/19482). " \
|
167
|
+
"Other Ruby versions do not suffer from this issue."
|
186
168
|
)
|
187
169
|
return false
|
188
170
|
end
|
@@ -192,26 +174,26 @@ module Datadog
|
|
192
174
|
# that causes a segmentation fault during garbage collection of Ractors
|
193
175
|
# (https://bugs.ruby-lang.org/issues/18464). We don't recommend using this feature on such Rubies.
|
194
176
|
# This bug is fixed on Ruby versions 3.1.4, 3.2.3 and 3.3.0.
|
195
|
-
if RUBY_VERSION.start_with?(
|
196
|
-
(RUBY_VERSION.start_with?(
|
197
|
-
(RUBY_VERSION.start_with?(
|
177
|
+
if RUBY_VERSION.start_with?("3.0.") ||
|
178
|
+
(RUBY_VERSION.start_with?("3.1.") && RUBY_VERSION < "3.1.4") ||
|
179
|
+
(RUBY_VERSION.start_with?("3.2.") && RUBY_VERSION < "3.2.3")
|
198
180
|
Datadog.logger.warn(
|
199
|
-
"Current Ruby version (#{RUBY_VERSION}) has a VM bug where enabling allocation profiling while using "\
|
200
|
-
|
201
|
-
|
181
|
+
"Current Ruby version (#{RUBY_VERSION}) has a VM bug where enabling allocation profiling while using " \
|
182
|
+
"Ractors may cause unexpected issues, including crashes (https://bugs.ruby-lang.org/issues/18464). " \
|
183
|
+
"This does not happen if Ractors are not used."
|
202
184
|
)
|
203
185
|
# ANNOYANCE - Only with Ractors
|
204
186
|
# On all known versions of Ruby 3.x, due to https://bugs.ruby-lang.org/issues/19112, when a ractor gets
|
205
187
|
# garbage collected, Ruby will disable all active tracepoints, which this feature internally relies on.
|
206
|
-
elsif RUBY_VERSION.start_with?(
|
188
|
+
elsif RUBY_VERSION.start_with?("3.")
|
207
189
|
Datadog.logger.warn(
|
208
|
-
|
209
|
-
|
210
|
-
|
190
|
+
"In all known versions of Ruby 3.x, using Ractors may result in allocation profiling unexpectedly " \
|
191
|
+
"stopping (https://bugs.ruby-lang.org/issues/19112). Note that this stop has no impact in your " \
|
192
|
+
"application stability or performance. This does not happen if Ractors are not used."
|
211
193
|
)
|
212
194
|
end
|
213
195
|
|
214
|
-
Datadog.logger.debug(
|
196
|
+
Datadog.logger.debug("Enabled allocation profiling")
|
215
197
|
|
216
198
|
true
|
217
199
|
end
|
@@ -221,33 +203,33 @@ module Datadog
|
|
221
203
|
|
222
204
|
return false unless heap_profiling_enabled
|
223
205
|
|
224
|
-
if RUBY_VERSION.start_with?(
|
206
|
+
if RUBY_VERSION.start_with?("2.") && RUBY_VERSION < "2.7"
|
225
207
|
Datadog.logger.warn(
|
226
|
-
|
227
|
-
|
208
|
+
"Heap profiling currently relies on features introduced in Ruby 2.7 and will be forcibly disabled. " \
|
209
|
+
"Please upgrade to Ruby >= 2.7 in order to use this feature."
|
228
210
|
)
|
229
211
|
return false
|
230
212
|
end
|
231
213
|
|
232
|
-
if RUBY_VERSION <
|
214
|
+
if RUBY_VERSION < "3.1"
|
233
215
|
Datadog.logger.debug(
|
234
216
|
"Current Ruby version (#{RUBY_VERSION}) supports forced object recycling which has a bug that the " \
|
235
|
-
|
217
|
+
"heap profiler is forced to work around to remain accurate. This workaround requires force-setting " \
|
236
218
|
"the SEEN_OBJ_ID flag on objects that should have it but don't. Full details can be found in " \
|
237
|
-
|
238
|
-
|
239
|
-
|
219
|
+
"https://github.com/DataDog/dd-trace-rb/pull/3360. This workaround should be safe but can be " \
|
220
|
+
"bypassed by disabling the heap profiler or upgrading to Ruby >= 3.1 where forced object recycling " \
|
221
|
+
"was completely removed (https://bugs.ruby-lang.org/issues/18290)."
|
240
222
|
)
|
241
223
|
end
|
242
224
|
|
243
225
|
unless allocation_profiling_enabled
|
244
226
|
raise ArgumentError,
|
245
|
-
|
227
|
+
"Heap profiling requires allocation profiling to be enabled"
|
246
228
|
end
|
247
229
|
|
248
230
|
Datadog.logger.warn(
|
249
231
|
"Enabled experimental heap profiling: heap_sample_rate=#{heap_sample_rate}. This is experimental, not " \
|
250
|
-
|
232
|
+
"recommended, and will increase overhead!"
|
251
233
|
)
|
252
234
|
|
253
235
|
true
|
@@ -259,7 +241,7 @@ module Datadog
|
|
259
241
|
return false unless heap_profiling_enabled && heap_size_profiling_enabled
|
260
242
|
|
261
243
|
Datadog.logger.warn(
|
262
|
-
|
244
|
+
"Enabled experimental heap size profiling. This is experimental, not recommended, and will increase overhead!"
|
263
245
|
)
|
264
246
|
|
265
247
|
true
|
@@ -267,12 +249,12 @@ module Datadog
|
|
267
249
|
|
268
250
|
private_class_method def self.no_signals_workaround_enabled?(settings) # rubocop:disable Metrics/MethodLength
|
269
251
|
setting_value = settings.profiling.advanced.no_signals_workaround_enabled
|
270
|
-
legacy_ruby_that_should_use_workaround = RUBY_VERSION.start_with?(
|
252
|
+
legacy_ruby_that_should_use_workaround = RUBY_VERSION.start_with?("2.5.")
|
271
253
|
|
272
254
|
unless [true, false, :auto].include?(setting_value)
|
273
255
|
Datadog.logger.error(
|
274
256
|
"Ignoring invalid value for profiling no_signals_workaround_enabled setting: #{setting_value.inspect}. " \
|
275
|
-
|
257
|
+
"Valid options are `true`, `false` or (default) `:auto`."
|
276
258
|
)
|
277
259
|
|
278
260
|
setting_value = :auto
|
@@ -282,10 +264,10 @@ module Datadog
|
|
282
264
|
if legacy_ruby_that_should_use_workaround
|
283
265
|
Datadog.logger.warn(
|
284
266
|
'The profiling "no signals" workaround has been disabled via configuration on a legacy Ruby version ' \
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
267
|
+
"(< 2.6). This is not recommended " \
|
268
|
+
"in production environments, as due to limitations in Ruby APIs, we suspect it may lead to crashes " \
|
269
|
+
"in very rare situations. Please report any issues you run into to Datadog support or " \
|
270
|
+
"via <https://github.com/datadog/dd-trace-rb/issues/new>!"
|
289
271
|
)
|
290
272
|
else
|
291
273
|
Datadog.logger.warn('Profiling "no signals" workaround disabled via configuration')
|
@@ -307,30 +289,30 @@ module Datadog
|
|
307
289
|
# We don't warn users in this situation because "upgrade your Ruby" is not a great warning
|
308
290
|
return true if legacy_ruby_that_should_use_workaround
|
309
291
|
|
310
|
-
if Gem.loaded_specs[
|
292
|
+
if Gem.loaded_specs["mysql2"] && incompatible_libmysqlclient_version?(settings)
|
311
293
|
Datadog.logger.warn(
|
312
294
|
'Enabling the profiling "no signals" workaround because an incompatible version of the mysql2 gem is ' \
|
313
|
-
|
314
|
-
|
295
|
+
"installed. Profiling data will have lower quality. " \
|
296
|
+
"To fix this, upgrade the libmysqlclient in your OS image to version 8.0.0 or above."
|
315
297
|
)
|
316
298
|
return true
|
317
299
|
end
|
318
300
|
|
319
|
-
if Gem.loaded_specs[
|
301
|
+
if Gem.loaded_specs["rugged"]
|
320
302
|
Datadog.logger.warn(
|
321
303
|
'Enabling the profiling "no signals" workaround because the rugged gem is installed. ' \
|
322
|
-
|
323
|
-
|
324
|
-
|
304
|
+
"This is needed because some operations on this gem are currently incompatible with the normal working mode " \
|
305
|
+
"of the profiler, as detailed in <https://github.com/datadog/dd-trace-rb/issues/2721>. " \
|
306
|
+
"Profiling data will have lower quality."
|
325
307
|
)
|
326
308
|
return true
|
327
309
|
end
|
328
310
|
|
329
|
-
if (defined?(::PhusionPassenger) || Gem.loaded_specs[
|
311
|
+
if (defined?(::PhusionPassenger) || Gem.loaded_specs["passenger"]) && incompatible_passenger_version?
|
330
312
|
Datadog.logger.warn(
|
331
313
|
'Enabling the profiling "no signals" workaround because an incompatible version of the passenger gem is ' \
|
332
|
-
|
333
|
-
|
314
|
+
"installed. Profiling data will have lower quality." \
|
315
|
+
"To fix this, upgrade the passenger gem to version 6.0.19 or above."
|
334
316
|
)
|
335
317
|
return true
|
336
318
|
end
|
@@ -351,11 +333,11 @@ module Datadog
|
|
351
333
|
return true if settings.profiling.advanced.skip_mysql2_check
|
352
334
|
|
353
335
|
Datadog.logger.debug(
|
354
|
-
|
336
|
+
"Requiring `mysql2` to check if the `libmysqlclient` version it uses is compatible with profiling"
|
355
337
|
)
|
356
338
|
|
357
339
|
begin
|
358
|
-
require
|
340
|
+
require "mysql2"
|
359
341
|
|
360
342
|
# The mysql2-aurora gem likes to monkey patch itself in replacement of Mysql2::Client, and uses
|
361
343
|
# `method_missing` to delegate to the original BUT unfortunately does not implement `respond_to_missing?` and
|
@@ -376,18 +358,18 @@ module Datadog
|
|
376
358
|
libmysqlclient_version = Gem::Version.new(info[:version])
|
377
359
|
|
378
360
|
compatible =
|
379
|
-
libmysqlclient_version >= Gem::Version.new(
|
361
|
+
libmysqlclient_version >= Gem::Version.new("8.0.0") ||
|
380
362
|
looks_like_mariadb?(info, libmysqlclient_version)
|
381
363
|
|
382
364
|
Datadog.logger.debug(
|
383
|
-
"The `mysql2` gem is using #{compatible ?
|
365
|
+
"The `mysql2` gem is using #{compatible ? "a compatible" : "an incompatible"} version of " \
|
384
366
|
"the `libmysqlclient` library (#{libmysqlclient_version})"
|
385
367
|
)
|
386
368
|
|
387
369
|
!compatible
|
388
370
|
rescue StandardError, LoadError => e
|
389
371
|
Datadog.logger.warn(
|
390
|
-
|
372
|
+
"Failed to probe `mysql2` gem information. " \
|
391
373
|
"Cause: #{e.class.name} #{e.message} Location: #{Array(e.backtrace).first}"
|
392
374
|
)
|
393
375
|
|
@@ -397,8 +379,12 @@ module Datadog
|
|
397
379
|
|
398
380
|
# See https://github.com/datadog/dd-trace-rb/issues/2976 for details.
|
399
381
|
private_class_method def self.incompatible_passenger_version?
|
400
|
-
|
401
|
-
|
382
|
+
first_compatible_version = Gem::Version.new("6.0.19")
|
383
|
+
|
384
|
+
if Gem.loaded_specs["passenger"]
|
385
|
+
Gem.loaded_specs["passenger"].version < first_compatible_version
|
386
|
+
elsif defined?(PhusionPassenger::VERSION_STRING)
|
387
|
+
Gem::Version.new(PhusionPassenger::VERSION_STRING) < first_compatible_version
|
402
388
|
else
|
403
389
|
true
|
404
390
|
end
|
@@ -409,7 +395,7 @@ module Datadog
|
|
409
395
|
overhead_target_percentage
|
410
396
|
else
|
411
397
|
Datadog.logger.error(
|
412
|
-
|
398
|
+
"Ignoring invalid value for profiling overhead_target_percentage setting: " \
|
413
399
|
"#{overhead_target_percentage.inspect}. Falling back to default value."
|
414
400
|
)
|
415
401
|
|
@@ -442,8 +428,17 @@ module Datadog
|
|
442
428
|
header_version = Gem::Version.new(info[:header_version]) if info[:header_version]
|
443
429
|
|
444
430
|
!!(header_version &&
|
445
|
-
libmysqlclient_version < Gem::Version.new(
|
446
|
-
header_version >= Gem::Version.new(
|
431
|
+
libmysqlclient_version < Gem::Version.new("5.0.0") &&
|
432
|
+
header_version >= Gem::Version.new("10.0.0"))
|
433
|
+
end
|
434
|
+
|
435
|
+
private_class_method def self.dir_interruption_workaround_enabled?(settings, no_signals_workaround_enabled)
|
436
|
+
return false if no_signals_workaround_enabled
|
437
|
+
|
438
|
+
# NOTE: In the future this method will evolve to check for Ruby versions affected and not apply the workaround
|
439
|
+
# when it's not needed but currently all known Ruby versions are affected.
|
440
|
+
|
441
|
+
settings.profiling.advanced.dir_interruption_workaround_enabled
|
447
442
|
end
|
448
443
|
end
|
449
444
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative
|
4
|
-
require_relative
|
3
|
+
require_relative "ext"
|
4
|
+
require_relative "tag_builder"
|
5
5
|
|
6
6
|
module Datadog
|
7
7
|
module Profiling
|
@@ -61,7 +61,7 @@ module Datadog
|
|
61
61
|
@last_flush_finish_at = finish
|
62
62
|
|
63
63
|
if duration_below_threshold?(start, finish)
|
64
|
-
Datadog.logger.debug(
|
64
|
+
Datadog.logger.debug("Skipped exporting profiling events as profile duration is below minimum")
|
65
65
|
return
|
66
66
|
end
|
67
67
|
|