datadog 2.2.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 +51 -2
- 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 +113 -43
- 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 +49 -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 +65 -60
- 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 -172
- 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.h +1 -0
- data/ext/datadog_profiling_native_extension/stack_recorder.c +14 -2
- data/ext/datadog_profiling_native_extension/stack_recorder.h +1 -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 +19 -6
- 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/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 +14 -12
- data/lib/datadog/core/configuration/settings.rb +54 -7
- 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/diagnostics/environment_logger.rb +8 -11
- data/lib/datadog/core/telemetry/component.rb +49 -2
- data/lib/datadog/core/telemetry/emitter.rb +9 -11
- data/lib/datadog/core/telemetry/event.rb +32 -1
- data/lib/datadog/core/telemetry/ext.rb +1 -0
- data/lib/datadog/core/telemetry/http/adapters/net.rb +10 -12
- 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/utils/at_fork_monkey_patch.rb +102 -0
- data/lib/datadog/kit/appsec/events.rb +2 -4
- data/lib/datadog/opentelemetry/sdk/span_processor.rb +10 -0
- data/lib/datadog/opentelemetry/sdk/trace/span.rb +23 -0
- data/lib/datadog/profiling/collectors/code_provenance.rb +7 -7
- 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 +69 -91
- data/lib/datadog/profiling/exporter.rb +3 -3
- data/lib/datadog/profiling/ext/dir_monkey_patches.rb +3 -3
- 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 +4 -5
- data/lib/datadog/tracing/contrib/active_record/events/sql.rb +1 -0
- data/lib/datadog/tracing/contrib/ext.rb +14 -0
- data/lib/datadog/tracing/contrib/graphql/unified_trace.rb +1 -1
- data/lib/datadog/tracing/contrib/graphql/unified_trace_patcher.rb +4 -1
- 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/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/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 +6 -2
- data/lib/datadog/tracing/transport/serializable_trace.rb +3 -0
- data/lib/datadog/version.rb +1 -1
- metadata +28 -10
- data/lib/datadog/profiling/crashtracker.rb +0 -91
- data/lib/datadog/profiling/ext/forking.rb +0 -98
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
require_relative 'trace/span'
|
4
4
|
require_relative '../../tracing/span_link'
|
5
|
+
require_relative '../../tracing/span_event'
|
5
6
|
require_relative '../../tracing/trace_digest'
|
6
7
|
|
7
8
|
module Datadog
|
@@ -31,6 +32,15 @@ module Datadog
|
|
31
32
|
#
|
32
33
|
# @param [Span] span the {Span} that just ended.
|
33
34
|
def on_finish(span)
|
35
|
+
unless span.events.nil?
|
36
|
+
span.datadog_span.span_events = span.events.map do |event|
|
37
|
+
Datadog::Tracing::SpanEvent.new(
|
38
|
+
event.name,
|
39
|
+
attributes: event.attributes,
|
40
|
+
time_unix_nano: event.timestamp
|
41
|
+
)
|
42
|
+
end
|
43
|
+
end
|
34
44
|
span.datadog_span.finish(ns_to_time(span.end_timestamp))
|
35
45
|
end
|
36
46
|
|
@@ -15,6 +15,29 @@ module Datadog
|
|
15
15
|
res
|
16
16
|
end
|
17
17
|
|
18
|
+
# Record an exception during the execution of this span. Multiple exceptions
|
19
|
+
# can be recorded on a span.
|
20
|
+
#
|
21
|
+
# @param [Exception] exception The exception to recorded
|
22
|
+
# @param [optional Hash{String => String, Numeric, Boolean, Array<String, Numeric, Boolean>}]
|
23
|
+
# attributes One or more key:value pairs, where the keys must be
|
24
|
+
# strings and the values may be (array of) string, boolean or numeric
|
25
|
+
# type.
|
26
|
+
#
|
27
|
+
# @return [void]
|
28
|
+
def record_exception(exception, attributes: nil)
|
29
|
+
res = super
|
30
|
+
if (span = datadog_span)
|
31
|
+
# Sets the exception attributes as span error tags. The values in the attribute hash MUST
|
32
|
+
# take precedence over the type, message and stacktrace inferred from the exception object
|
33
|
+
type = attributes&.[]('exception.type') || exception.class.to_s
|
34
|
+
message = attributes&.[]('exception.message') || exception.message
|
35
|
+
stacktrace = attributes&.[]('exception.stacktrace') || exception.full_message(highlight: false, order: :top)
|
36
|
+
span.set_error_tags([type, message, stacktrace])
|
37
|
+
end
|
38
|
+
res
|
39
|
+
end
|
40
|
+
|
18
41
|
# `alias` performed to match {OpenTelemetry::SDK::Trace::Span} aliasing upstream
|
19
42
|
alias []= set_attribute
|
20
43
|
|
@@ -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
|
|
@@ -119,7 +119,7 @@ module Datadog
|
|
119
119
|
end
|
120
120
|
|
121
121
|
def to_json(arg = nil)
|
122
|
-
{
|
122
|
+
{kind: @kind, name: @name, version: @version, paths: @paths}.to_json(arg)
|
123
123
|
end
|
124
124
|
|
125
125
|
def path
|
@@ -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,14 +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
79
|
Datadog::Profiling::Ext::DirMonkeyPatches.apply!
|
80
80
|
end
|
81
81
|
|
82
|
-
[profiler, {
|
82
|
+
[profiler, {profiling_enabled: true}]
|
83
83
|
end
|
84
84
|
|
85
85
|
private_class_method def self.build_thread_context_collector(settings, recorder, optional_tracer, timeline_enabled)
|
@@ -116,28 +116,6 @@ module Datadog
|
|
116
116
|
)
|
117
117
|
end
|
118
118
|
|
119
|
-
private_class_method def self.build_crashtracker(settings, transport)
|
120
|
-
return unless settings.profiling.advanced.experimental_crash_tracking_enabled
|
121
|
-
|
122
|
-
# By default, the transport is an instance of HttpTransport, which validates the configuration and makes
|
123
|
-
# it available for us to use here.
|
124
|
-
# But we support overriding the transport with a user-specific one, which may e.g. write stuff to a file,
|
125
|
-
# and thus can't really provide a valid configuration to talk to a Datadog agent. Thus, in this situation,
|
126
|
-
# we can't use the crashtracker, even if enabled.
|
127
|
-
unless transport.respond_to?(:exporter_configuration)
|
128
|
-
Datadog.logger.warn(
|
129
|
-
'Cannot enable profiling crash tracking as a custom settings.profiling.exporter.transport is configured'
|
130
|
-
)
|
131
|
-
return
|
132
|
-
end
|
133
|
-
|
134
|
-
Datadog::Profiling::Crashtracker.new(
|
135
|
-
exporter_configuration: transport.exporter_configuration,
|
136
|
-
tags: Datadog::Profiling::TagBuilder.call(settings: settings),
|
137
|
-
upload_timeout_seconds: settings.profiling.upload.timeout_seconds,
|
138
|
-
)
|
139
|
-
end
|
140
|
-
|
141
119
|
private_class_method def self.enable_gc_profiling?(settings)
|
142
120
|
return false unless settings.profiling.advanced.gc_enabled
|
143
121
|
|
@@ -146,19 +124,19 @@ module Datadog
|
|
146
124
|
# that causes a segmentation fault during garbage collection of Ractors
|
147
125
|
# (https://bugs.ruby-lang.org/issues/18464). We don't allow enabling gc profiling on such Rubies.
|
148
126
|
# This bug is fixed on Ruby versions 3.1.4, 3.2.3 and 3.3.0.
|
149
|
-
if RUBY_VERSION.start_with?(
|
150
|
-
(RUBY_VERSION.start_with?(
|
151
|
-
(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")
|
152
130
|
Datadog.logger.warn(
|
153
|
-
"Current Ruby version (#{RUBY_VERSION}) has a VM bug where enabling GC profiling would cause "\
|
154
|
-
|
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."
|
155
133
|
)
|
156
134
|
return false
|
157
|
-
elsif RUBY_VERSION.start_with?(
|
135
|
+
elsif RUBY_VERSION.start_with?("3.")
|
158
136
|
Datadog.logger.debug(
|
159
|
-
|
160
|
-
|
161
|
-
|
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."
|
162
140
|
)
|
163
141
|
end
|
164
142
|
|
@@ -182,11 +160,11 @@ module Datadog
|
|
182
160
|
# Ruby 3.2.0 to 3.2.2 have a bug in the newobj tracepoint (https://bugs.ruby-lang.org/issues/19482,
|
183
161
|
# https://github.com/ruby/ruby/pull/7464) that makes this crash in any configuration. This bug is
|
184
162
|
# fixed on Ruby versions 3.2.3 and 3.3.0.
|
185
|
-
if RUBY_VERSION.start_with?(
|
163
|
+
if RUBY_VERSION.start_with?("3.2.") && RUBY_VERSION < "3.2.3"
|
186
164
|
Datadog.logger.warn(
|
187
|
-
|
188
|
-
|
189
|
-
|
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."
|
190
168
|
)
|
191
169
|
return false
|
192
170
|
end
|
@@ -196,26 +174,26 @@ module Datadog
|
|
196
174
|
# that causes a segmentation fault during garbage collection of Ractors
|
197
175
|
# (https://bugs.ruby-lang.org/issues/18464). We don't recommend using this feature on such Rubies.
|
198
176
|
# This bug is fixed on Ruby versions 3.1.4, 3.2.3 and 3.3.0.
|
199
|
-
if RUBY_VERSION.start_with?(
|
200
|
-
(RUBY_VERSION.start_with?(
|
201
|
-
(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")
|
202
180
|
Datadog.logger.warn(
|
203
|
-
"Current Ruby version (#{RUBY_VERSION}) has a VM bug where enabling allocation profiling while using "\
|
204
|
-
|
205
|
-
|
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."
|
206
184
|
)
|
207
185
|
# ANNOYANCE - Only with Ractors
|
208
186
|
# On all known versions of Ruby 3.x, due to https://bugs.ruby-lang.org/issues/19112, when a ractor gets
|
209
187
|
# garbage collected, Ruby will disable all active tracepoints, which this feature internally relies on.
|
210
|
-
elsif RUBY_VERSION.start_with?(
|
188
|
+
elsif RUBY_VERSION.start_with?("3.")
|
211
189
|
Datadog.logger.warn(
|
212
|
-
|
213
|
-
|
214
|
-
|
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."
|
215
193
|
)
|
216
194
|
end
|
217
195
|
|
218
|
-
Datadog.logger.debug(
|
196
|
+
Datadog.logger.debug("Enabled allocation profiling")
|
219
197
|
|
220
198
|
true
|
221
199
|
end
|
@@ -225,33 +203,33 @@ module Datadog
|
|
225
203
|
|
226
204
|
return false unless heap_profiling_enabled
|
227
205
|
|
228
|
-
if RUBY_VERSION.start_with?(
|
206
|
+
if RUBY_VERSION.start_with?("2.") && RUBY_VERSION < "2.7"
|
229
207
|
Datadog.logger.warn(
|
230
|
-
|
231
|
-
|
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."
|
232
210
|
)
|
233
211
|
return false
|
234
212
|
end
|
235
213
|
|
236
|
-
if RUBY_VERSION <
|
214
|
+
if RUBY_VERSION < "3.1"
|
237
215
|
Datadog.logger.debug(
|
238
216
|
"Current Ruby version (#{RUBY_VERSION}) supports forced object recycling which has a bug that the " \
|
239
|
-
|
217
|
+
"heap profiler is forced to work around to remain accurate. This workaround requires force-setting " \
|
240
218
|
"the SEEN_OBJ_ID flag on objects that should have it but don't. Full details can be found in " \
|
241
|
-
|
242
|
-
|
243
|
-
|
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)."
|
244
222
|
)
|
245
223
|
end
|
246
224
|
|
247
225
|
unless allocation_profiling_enabled
|
248
226
|
raise ArgumentError,
|
249
|
-
|
227
|
+
"Heap profiling requires allocation profiling to be enabled"
|
250
228
|
end
|
251
229
|
|
252
230
|
Datadog.logger.warn(
|
253
231
|
"Enabled experimental heap profiling: heap_sample_rate=#{heap_sample_rate}. This is experimental, not " \
|
254
|
-
|
232
|
+
"recommended, and will increase overhead!"
|
255
233
|
)
|
256
234
|
|
257
235
|
true
|
@@ -263,7 +241,7 @@ module Datadog
|
|
263
241
|
return false unless heap_profiling_enabled && heap_size_profiling_enabled
|
264
242
|
|
265
243
|
Datadog.logger.warn(
|
266
|
-
|
244
|
+
"Enabled experimental heap size profiling. This is experimental, not recommended, and will increase overhead!"
|
267
245
|
)
|
268
246
|
|
269
247
|
true
|
@@ -271,12 +249,12 @@ module Datadog
|
|
271
249
|
|
272
250
|
private_class_method def self.no_signals_workaround_enabled?(settings) # rubocop:disable Metrics/MethodLength
|
273
251
|
setting_value = settings.profiling.advanced.no_signals_workaround_enabled
|
274
|
-
legacy_ruby_that_should_use_workaround = RUBY_VERSION.start_with?(
|
252
|
+
legacy_ruby_that_should_use_workaround = RUBY_VERSION.start_with?("2.5.")
|
275
253
|
|
276
254
|
unless [true, false, :auto].include?(setting_value)
|
277
255
|
Datadog.logger.error(
|
278
256
|
"Ignoring invalid value for profiling no_signals_workaround_enabled setting: #{setting_value.inspect}. " \
|
279
|
-
|
257
|
+
"Valid options are `true`, `false` or (default) `:auto`."
|
280
258
|
)
|
281
259
|
|
282
260
|
setting_value = :auto
|
@@ -286,10 +264,10 @@ module Datadog
|
|
286
264
|
if legacy_ruby_that_should_use_workaround
|
287
265
|
Datadog.logger.warn(
|
288
266
|
'The profiling "no signals" workaround has been disabled via configuration on a legacy Ruby version ' \
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
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>!"
|
293
271
|
)
|
294
272
|
else
|
295
273
|
Datadog.logger.warn('Profiling "no signals" workaround disabled via configuration')
|
@@ -311,30 +289,30 @@ module Datadog
|
|
311
289
|
# We don't warn users in this situation because "upgrade your Ruby" is not a great warning
|
312
290
|
return true if legacy_ruby_that_should_use_workaround
|
313
291
|
|
314
|
-
if Gem.loaded_specs[
|
292
|
+
if Gem.loaded_specs["mysql2"] && incompatible_libmysqlclient_version?(settings)
|
315
293
|
Datadog.logger.warn(
|
316
294
|
'Enabling the profiling "no signals" workaround because an incompatible version of the mysql2 gem is ' \
|
317
|
-
|
318
|
-
|
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."
|
319
297
|
)
|
320
298
|
return true
|
321
299
|
end
|
322
300
|
|
323
|
-
if Gem.loaded_specs[
|
301
|
+
if Gem.loaded_specs["rugged"]
|
324
302
|
Datadog.logger.warn(
|
325
303
|
'Enabling the profiling "no signals" workaround because the rugged gem is installed. ' \
|
326
|
-
|
327
|
-
|
328
|
-
|
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."
|
329
307
|
)
|
330
308
|
return true
|
331
309
|
end
|
332
310
|
|
333
|
-
if (defined?(::PhusionPassenger) || Gem.loaded_specs[
|
311
|
+
if (defined?(::PhusionPassenger) || Gem.loaded_specs["passenger"]) && incompatible_passenger_version?
|
334
312
|
Datadog.logger.warn(
|
335
313
|
'Enabling the profiling "no signals" workaround because an incompatible version of the passenger gem is ' \
|
336
|
-
|
337
|
-
|
314
|
+
"installed. Profiling data will have lower quality." \
|
315
|
+
"To fix this, upgrade the passenger gem to version 6.0.19 or above."
|
338
316
|
)
|
339
317
|
return true
|
340
318
|
end
|
@@ -355,11 +333,11 @@ module Datadog
|
|
355
333
|
return true if settings.profiling.advanced.skip_mysql2_check
|
356
334
|
|
357
335
|
Datadog.logger.debug(
|
358
|
-
|
336
|
+
"Requiring `mysql2` to check if the `libmysqlclient` version it uses is compatible with profiling"
|
359
337
|
)
|
360
338
|
|
361
339
|
begin
|
362
|
-
require
|
340
|
+
require "mysql2"
|
363
341
|
|
364
342
|
# The mysql2-aurora gem likes to monkey patch itself in replacement of Mysql2::Client, and uses
|
365
343
|
# `method_missing` to delegate to the original BUT unfortunately does not implement `respond_to_missing?` and
|
@@ -380,18 +358,18 @@ module Datadog
|
|
380
358
|
libmysqlclient_version = Gem::Version.new(info[:version])
|
381
359
|
|
382
360
|
compatible =
|
383
|
-
libmysqlclient_version >= Gem::Version.new(
|
361
|
+
libmysqlclient_version >= Gem::Version.new("8.0.0") ||
|
384
362
|
looks_like_mariadb?(info, libmysqlclient_version)
|
385
363
|
|
386
364
|
Datadog.logger.debug(
|
387
|
-
"The `mysql2` gem is using #{compatible ?
|
365
|
+
"The `mysql2` gem is using #{compatible ? "a compatible" : "an incompatible"} version of " \
|
388
366
|
"the `libmysqlclient` library (#{libmysqlclient_version})"
|
389
367
|
)
|
390
368
|
|
391
369
|
!compatible
|
392
370
|
rescue StandardError, LoadError => e
|
393
371
|
Datadog.logger.warn(
|
394
|
-
|
372
|
+
"Failed to probe `mysql2` gem information. " \
|
395
373
|
"Cause: #{e.class.name} #{e.message} Location: #{Array(e.backtrace).first}"
|
396
374
|
)
|
397
375
|
|
@@ -401,10 +379,10 @@ module Datadog
|
|
401
379
|
|
402
380
|
# See https://github.com/datadog/dd-trace-rb/issues/2976 for details.
|
403
381
|
private_class_method def self.incompatible_passenger_version?
|
404
|
-
first_compatible_version = Gem::Version.new(
|
382
|
+
first_compatible_version = Gem::Version.new("6.0.19")
|
405
383
|
|
406
|
-
if Gem.loaded_specs[
|
407
|
-
Gem.loaded_specs[
|
384
|
+
if Gem.loaded_specs["passenger"]
|
385
|
+
Gem.loaded_specs["passenger"].version < first_compatible_version
|
408
386
|
elsif defined?(PhusionPassenger::VERSION_STRING)
|
409
387
|
Gem::Version.new(PhusionPassenger::VERSION_STRING) < first_compatible_version
|
410
388
|
else
|
@@ -417,7 +395,7 @@ module Datadog
|
|
417
395
|
overhead_target_percentage
|
418
396
|
else
|
419
397
|
Datadog.logger.error(
|
420
|
-
|
398
|
+
"Ignoring invalid value for profiling overhead_target_percentage setting: " \
|
421
399
|
"#{overhead_target_percentage.inspect}. Falling back to default value."
|
422
400
|
)
|
423
401
|
|
@@ -450,8 +428,8 @@ module Datadog
|
|
450
428
|
header_version = Gem::Version.new(info[:header_version]) if info[:header_version]
|
451
429
|
|
452
430
|
!!(header_version &&
|
453
|
-
libmysqlclient_version < Gem::Version.new(
|
454
|
-
header_version >= Gem::Version.new(
|
431
|
+
libmysqlclient_version < Gem::Version.new("5.0.0") &&
|
432
|
+
header_version >= Gem::Version.new("10.0.0"))
|
455
433
|
end
|
456
434
|
|
457
435
|
private_class_method def self.dir_interruption_workaround_enabled?(settings, no_signals_workaround_enabled)
|
@@ -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
|
|