datadog 2.8.0 → 2.9.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +36 -1
- data/ext/datadog_profiling_native_extension/clock_id.h +2 -2
- data/ext/datadog_profiling_native_extension/collectors_cpu_and_wall_time_worker.c +64 -54
- data/ext/datadog_profiling_native_extension/collectors_discrete_dynamic_sampler.c +1 -1
- data/ext/datadog_profiling_native_extension/collectors_discrete_dynamic_sampler.h +1 -1
- data/ext/datadog_profiling_native_extension/collectors_idle_sampling_helper.c +16 -16
- data/ext/datadog_profiling_native_extension/collectors_stack.c +7 -7
- data/ext/datadog_profiling_native_extension/collectors_thread_context.c +219 -122
- data/ext/datadog_profiling_native_extension/heap_recorder.h +1 -1
- data/ext/datadog_profiling_native_extension/http_transport.c +4 -4
- data/ext/datadog_profiling_native_extension/private_vm_api_access.c +3 -0
- data/ext/datadog_profiling_native_extension/private_vm_api_access.h +3 -1
- data/ext/datadog_profiling_native_extension/profiling.c +10 -8
- data/ext/datadog_profiling_native_extension/ruby_helpers.c +8 -8
- data/ext/datadog_profiling_native_extension/stack_recorder.c +54 -54
- data/ext/datadog_profiling_native_extension/stack_recorder.h +1 -1
- data/ext/datadog_profiling_native_extension/time_helpers.h +1 -1
- data/ext/datadog_profiling_native_extension/unsafe_api_calls_check.c +47 -0
- data/ext/datadog_profiling_native_extension/unsafe_api_calls_check.h +31 -0
- data/ext/libdatadog_api/crashtracker.c +3 -0
- data/lib/datadog/appsec/assets/waf_rules/recommended.json +355 -157
- data/lib/datadog/appsec/assets/waf_rules/strict.json +62 -32
- data/lib/datadog/appsec/context.rb +54 -0
- data/lib/datadog/appsec/contrib/active_record/instrumentation.rb +7 -7
- data/lib/datadog/appsec/contrib/devise/patcher/authenticatable_patch.rb +6 -6
- data/lib/datadog/appsec/contrib/devise/patcher/registration_controller_patch.rb +4 -4
- data/lib/datadog/appsec/contrib/graphql/gateway/watcher.rb +19 -28
- data/lib/datadog/appsec/contrib/graphql/reactive/multiplex.rb +5 -5
- data/lib/datadog/appsec/contrib/rack/gateway/response.rb +3 -3
- data/lib/datadog/appsec/contrib/rack/gateway/watcher.rb +64 -96
- data/lib/datadog/appsec/contrib/rack/reactive/request.rb +10 -10
- data/lib/datadog/appsec/contrib/rack/reactive/request_body.rb +5 -5
- data/lib/datadog/appsec/contrib/rack/reactive/response.rb +6 -6
- data/lib/datadog/appsec/contrib/rack/request_body_middleware.rb +10 -11
- data/lib/datadog/appsec/contrib/rack/request_middleware.rb +43 -49
- data/lib/datadog/appsec/contrib/rails/gateway/watcher.rb +21 -32
- data/lib/datadog/appsec/contrib/rails/patcher.rb +1 -1
- data/lib/datadog/appsec/contrib/rails/reactive/action.rb +6 -6
- data/lib/datadog/appsec/contrib/sinatra/gateway/watcher.rb +41 -63
- data/lib/datadog/appsec/contrib/sinatra/patcher.rb +2 -2
- data/lib/datadog/appsec/contrib/sinatra/reactive/routed.rb +5 -5
- data/lib/datadog/appsec/event.rb +6 -6
- data/lib/datadog/appsec/ext.rb +3 -1
- data/lib/datadog/appsec/monitor/gateway/watcher.rb +22 -32
- data/lib/datadog/appsec/monitor/reactive/set_user.rb +5 -5
- data/lib/datadog/appsec/processor/rule_loader.rb +0 -3
- data/lib/datadog/appsec.rb +3 -3
- data/lib/datadog/auto_instrument.rb +3 -0
- data/lib/datadog/core/configuration/agent_settings_resolver.rb +39 -11
- data/lib/datadog/core/configuration/components.rb +4 -2
- data/lib/datadog/core/configuration.rb +1 -1
- data/lib/datadog/{tracing → core}/contrib/rails/utils.rb +1 -3
- data/lib/datadog/core/crashtracking/component.rb +1 -3
- data/lib/datadog/core/telemetry/event.rb +87 -3
- data/lib/datadog/core/telemetry/logging.rb +2 -2
- data/lib/datadog/core/telemetry/metric.rb +22 -0
- data/lib/datadog/core/telemetry/worker.rb +33 -0
- data/lib/datadog/di/base.rb +115 -0
- data/lib/datadog/di/code_tracker.rb +7 -4
- data/lib/datadog/di/component.rb +17 -11
- data/lib/datadog/di/configuration/settings.rb +11 -1
- data/lib/datadog/di/contrib/railtie.rb +15 -0
- data/lib/datadog/di/contrib.rb +26 -0
- data/lib/datadog/di/error.rb +5 -0
- data/lib/datadog/di/instrumenter.rb +39 -18
- data/lib/datadog/di/{init.rb → preload.rb} +2 -4
- data/lib/datadog/di/probe_manager.rb +4 -4
- data/lib/datadog/di/probe_notification_builder.rb +16 -2
- data/lib/datadog/di/probe_notifier_worker.rb +5 -6
- data/lib/datadog/di/remote.rb +4 -4
- data/lib/datadog/di/transport.rb +2 -4
- data/lib/datadog/di.rb +5 -108
- data/lib/datadog/kit/appsec/events.rb +3 -3
- data/lib/datadog/kit/identity.rb +4 -4
- data/lib/datadog/profiling/component.rb +55 -53
- data/lib/datadog/profiling/http_transport.rb +1 -26
- data/lib/datadog/tracing/contrib/action_cable/integration.rb +5 -2
- data/lib/datadog/tracing/contrib/action_mailer/integration.rb +6 -2
- data/lib/datadog/tracing/contrib/action_pack/integration.rb +5 -2
- data/lib/datadog/tracing/contrib/action_view/integration.rb +5 -2
- data/lib/datadog/tracing/contrib/active_job/integration.rb +5 -2
- data/lib/datadog/tracing/contrib/active_record/integration.rb +6 -2
- data/lib/datadog/tracing/contrib/active_support/cache/events/cache.rb +3 -1
- data/lib/datadog/tracing/contrib/active_support/cache/instrumentation.rb +3 -1
- data/lib/datadog/tracing/contrib/active_support/configuration/settings.rb +10 -0
- data/lib/datadog/tracing/contrib/active_support/integration.rb +5 -2
- data/lib/datadog/tracing/contrib/auto_instrument.rb +2 -2
- data/lib/datadog/tracing/contrib/aws/integration.rb +3 -0
- data/lib/datadog/tracing/contrib/concurrent_ruby/integration.rb +3 -0
- data/lib/datadog/tracing/contrib/httprb/integration.rb +3 -0
- data/lib/datadog/tracing/contrib/kafka/integration.rb +3 -0
- data/lib/datadog/tracing/contrib/mongodb/integration.rb +3 -0
- data/lib/datadog/tracing/contrib/opensearch/integration.rb +3 -0
- data/lib/datadog/tracing/contrib/presto/integration.rb +3 -0
- data/lib/datadog/tracing/contrib/rack/integration.rb +2 -2
- data/lib/datadog/tracing/contrib/rails/framework.rb +2 -2
- data/lib/datadog/tracing/contrib/rails/patcher.rb +1 -1
- data/lib/datadog/tracing/contrib/rest_client/integration.rb +3 -0
- data/lib/datadog/tracing/span.rb +12 -4
- data/lib/datadog/tracing/span_event.rb +123 -3
- data/lib/datadog/tracing/span_operation.rb +6 -0
- data/lib/datadog/tracing/transport/serializable_trace.rb +24 -6
- data/lib/datadog/version.rb +1 -1
- metadata +19 -10
- data/lib/datadog/appsec/reactive/operation.rb +0 -68
- data/lib/datadog/appsec/scope.rb +0 -58
- data/lib/datadog/core/crashtracking/agent_base_url.rb +0 -21
data/lib/datadog/di/remote.rb
CHANGED
@@ -51,7 +51,7 @@ module Datadog
|
|
51
51
|
probe = ProbeBuilder.build_from_remote_config(probe_spec)
|
52
52
|
payload = component.probe_notification_builder.build_received(probe)
|
53
53
|
component.probe_notifier_worker.add_status(payload)
|
54
|
-
component.logger.
|
54
|
+
component.logger.debug { "di: received probe from RC: #{probe.type} #{probe.location}" }
|
55
55
|
|
56
56
|
begin
|
57
57
|
# TODO test exception capture
|
@@ -60,7 +60,7 @@ module Datadog
|
|
60
60
|
rescue => exc
|
61
61
|
raise if component.settings.dynamic_instrumentation.internal.propagate_all_exceptions
|
62
62
|
|
63
|
-
component.logger.
|
63
|
+
component.logger.debug { "di: unhandled exception adding probe in DI remote receiver: #{exc.class}: #{exc}" }
|
64
64
|
component.telemetry&.report(exc, description: "Unhandled exception adding probe in DI remote receiver")
|
65
65
|
|
66
66
|
# If a probe fails to install, we will mark the content
|
@@ -81,7 +81,7 @@ module Datadog
|
|
81
81
|
rescue => exc
|
82
82
|
raise if component.settings.dynamic_instrumentation.internal.propagate_all_exceptions
|
83
83
|
|
84
|
-
component.logger.
|
84
|
+
component.logger.debug { "di: unhandled exception handling probe in DI remote receiver: #{exc.class}: #{exc}" }
|
85
85
|
component.telemetry&.report(exc, description: "Unhandled exception handling probe in DI remote receiver")
|
86
86
|
|
87
87
|
content.errored("Error applying dynamic instrumentation configuration: #{exc.class.name} #{exc.message}: #{Array(exc.backtrace).join("\n")}")
|
@@ -95,7 +95,7 @@ module Datadog
|
|
95
95
|
rescue => exc
|
96
96
|
raise if component.settings.dynamic_instrumentation.internal.propagate_all_exceptions
|
97
97
|
|
98
|
-
component.logger.
|
98
|
+
component.logger.debug { "di: unhandled exception removing probes in DI remote receiver: #{exc.class}: #{exc}" }
|
99
99
|
component.telemetry&.report(exc, description: "Unhandled exception removing probes in DI remote receiver")
|
100
100
|
end
|
101
101
|
end
|
data/lib/datadog/di/transport.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'ostruct'
|
4
3
|
require_relative 'error'
|
4
|
+
require_relative '../core/transport/http/adapters/net'
|
5
5
|
|
6
6
|
module Datadog
|
7
7
|
module DI
|
@@ -60,9 +60,7 @@ module Datadog
|
|
60
60
|
attr_reader :client
|
61
61
|
|
62
62
|
def send_request(desc, **options)
|
63
|
-
|
64
|
-
env = OpenStruct.new(**options)
|
65
|
-
# steep:ignore:end
|
63
|
+
env = Core::Transport::HTTP::Env.new(nil, options)
|
66
64
|
response = client.post(env)
|
67
65
|
unless response.ok?
|
68
66
|
raise Error::AgentCommunicationError, "#{desc} failed: #{response.code}: #{response.payload}"
|
data/lib/datadog/di.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require_relative 'di/base'
|
3
4
|
require_relative 'di/error'
|
4
5
|
require_relative 'di/code_tracker'
|
5
6
|
require_relative 'di/component'
|
@@ -17,21 +18,6 @@ require_relative 'di/serializer'
|
|
17
18
|
require_relative 'di/transport'
|
18
19
|
require_relative 'di/utils'
|
19
20
|
|
20
|
-
if defined?(ActiveRecord::Base)
|
21
|
-
# The third-party library integrations need to be loaded after the
|
22
|
-
# third-party libraries are loaded. Tracing and appsec use Railtie
|
23
|
-
# to delay integrations until all of the application's dependencies
|
24
|
-
# are loaded, when running under Rails. We should do the same here in
|
25
|
-
# principle, however DI currently only has an ActiveRecord integration
|
26
|
-
# and AR should be loaded before any application code is loaded, being
|
27
|
-
# part of Rails, therefore for now we should be OK to just require the
|
28
|
-
# AR integration from here.
|
29
|
-
#
|
30
|
-
# TODO this require might need to be delayed via Rails post-initialization
|
31
|
-
# logic?
|
32
|
-
require_relative 'di/contrib/active_record'
|
33
|
-
end
|
34
|
-
|
35
21
|
module Datadog
|
36
22
|
# Namespace for Datadog dynamic instrumentation.
|
37
23
|
#
|
@@ -46,67 +32,7 @@ module Datadog
|
|
46
32
|
# Expose DI to global shared objects
|
47
33
|
Extensions.activate!
|
48
34
|
|
49
|
-
LOCK = Mutex.new
|
50
|
-
|
51
35
|
class << self
|
52
|
-
attr_reader :code_tracker
|
53
|
-
|
54
|
-
# Activates code tracking. Normally this method should be called
|
55
|
-
# when the application starts. If instrumenting third-party code,
|
56
|
-
# code tracking needs to be enabled before the third-party libraries
|
57
|
-
# are loaded. If you definitely will not be instrumenting
|
58
|
-
# third-party libraries, activating tracking after third-party libraries
|
59
|
-
# have been loaded may improve lookup performance.
|
60
|
-
#
|
61
|
-
# TODO test that activating tracker multiple times preserves
|
62
|
-
# existing mappings in the registry
|
63
|
-
def activate_tracking!
|
64
|
-
(@code_tracker ||= CodeTracker.new).start
|
65
|
-
end
|
66
|
-
|
67
|
-
# Activates code tracking if possible.
|
68
|
-
#
|
69
|
-
# This method does nothing if invoked in an environment that does not
|
70
|
-
# implement required trace points for code tracking (MRI Ruby < 2.6,
|
71
|
-
# JRuby) and rescues any exceptions that may be raised by downstream
|
72
|
-
# DI code.
|
73
|
-
def activate_tracking
|
74
|
-
# :script_compiled trace point was added in Ruby 2.6.
|
75
|
-
return unless RUBY_VERSION >= '2.6'
|
76
|
-
|
77
|
-
begin
|
78
|
-
# Activate code tracking by default because line trace points will not work
|
79
|
-
# without it.
|
80
|
-
Datadog::DI.activate_tracking!
|
81
|
-
rescue => exc
|
82
|
-
if defined?(Datadog.logger)
|
83
|
-
Datadog.logger.warn("Failed to activate code tracking for DI: #{exc.class}: #{exc}")
|
84
|
-
else
|
85
|
-
# We do not have Datadog logger potentially because DI code tracker is
|
86
|
-
# being loaded early in application boot process and the rest of datadog
|
87
|
-
# wasn't loaded yet. Output to standard error.
|
88
|
-
warn("Failed to activate code tracking for DI: #{exc.class}: #{exc}")
|
89
|
-
end
|
90
|
-
end
|
91
|
-
end
|
92
|
-
|
93
|
-
# Deactivates code tracking. In normal usage of DI this method should
|
94
|
-
# never be called, however it is used by DI's test suite to reset
|
95
|
-
# state for individual tests.
|
96
|
-
#
|
97
|
-
# Note that deactivating tracking clears out the registry, losing
|
98
|
-
# the ability to look up files that have been loaded into the process
|
99
|
-
# already.
|
100
|
-
def deactivate_tracking!
|
101
|
-
code_tracker&.stop
|
102
|
-
end
|
103
|
-
|
104
|
-
# Returns whether code tracking is available.
|
105
|
-
# This method should be used instead of querying #code_tracker
|
106
|
-
# because the latter one may be nil.
|
107
|
-
def code_tracking_active?
|
108
|
-
code_tracker&.active? || false
|
109
|
-
end
|
110
36
|
|
111
37
|
# This method is called from DI Remote handler to issue DI operations
|
112
38
|
# to the probe manager (add or remove probes).
|
@@ -120,39 +46,6 @@ module Datadog
|
|
120
46
|
def component
|
121
47
|
Datadog.send(:components).dynamic_instrumentation
|
122
48
|
end
|
123
|
-
|
124
|
-
# DI code tracker is instantiated globally before the regular set of
|
125
|
-
# components is created, but the code tracker needs to call out to the
|
126
|
-
# "current" DI component to perform instrumentation when application
|
127
|
-
# code is loaded. Because this call may happen prior to Datadog
|
128
|
-
# components having been initialized, we maintain the "current component"
|
129
|
-
# which contains a reference to the most recently instantiated
|
130
|
-
# DI::Component. This way, if a DI component hasn't been instantiated,
|
131
|
-
# we do not try to reference Datadog.components.
|
132
|
-
def current_component
|
133
|
-
LOCK.synchronize do
|
134
|
-
@current_components&.last
|
135
|
-
end
|
136
|
-
end
|
137
|
-
|
138
|
-
# To avoid potential races with DI::Component being added and removed,
|
139
|
-
# we maintain a list of the components. Normally the list should contain
|
140
|
-
# either zero or one component depending on whether DI is enabled in
|
141
|
-
# Datadog configuration. However, if a new instance of DI::Component
|
142
|
-
# is created while the previous instance is still running, we are
|
143
|
-
# guaranteed to not end up with no component when one is running.
|
144
|
-
def add_current_component(component)
|
145
|
-
LOCK.synchronize do
|
146
|
-
@current_components ||= []
|
147
|
-
@current_components << component
|
148
|
-
end
|
149
|
-
end
|
150
|
-
|
151
|
-
def remove_current_component(component)
|
152
|
-
LOCK.synchronize do
|
153
|
-
@current_components&.delete(component)
|
154
|
-
end
|
155
|
-
end
|
156
49
|
end
|
157
50
|
end
|
158
51
|
end
|
@@ -167,3 +60,7 @@ if %w(1 true).include?(ENV['DD_DYNAMIC_INSTRUMENTATION_ENABLED']) # steep:ignore
|
|
167
60
|
# for line probes to work) activate tracking in an initializer.
|
168
61
|
Datadog::DI.activate_tracking
|
169
62
|
end
|
63
|
+
|
64
|
+
require_relative 'di/contrib'
|
65
|
+
|
66
|
+
Datadog::DI::Contrib.load_now_or_later
|
@@ -136,9 +136,9 @@ module Datadog
|
|
136
136
|
private
|
137
137
|
|
138
138
|
def set_trace_and_span_context(method, trace = nil, span = nil)
|
139
|
-
if (
|
140
|
-
trace =
|
141
|
-
span =
|
139
|
+
if (appsec_context = Datadog::AppSec.active_context)
|
140
|
+
trace = appsec_context.trace
|
141
|
+
span = appsec_context.span
|
142
142
|
end
|
143
143
|
|
144
144
|
trace ||= Datadog::Tracing.active_trace
|
data/lib/datadog/kit/identity.rb
CHANGED
@@ -66,7 +66,7 @@ module Datadog
|
|
66
66
|
active_span.set_tag("usr.#{k}", v) unless v.nil?
|
67
67
|
end
|
68
68
|
|
69
|
-
if Datadog::AppSec.
|
69
|
+
if Datadog::AppSec.active_context
|
70
70
|
user = ::Datadog::AppSec::Instrumentation::Gateway::User.new(id)
|
71
71
|
::Datadog::AppSec::Instrumentation.gateway.push('identity.set_user', user)
|
72
72
|
end
|
@@ -78,9 +78,9 @@ module Datadog
|
|
78
78
|
private
|
79
79
|
|
80
80
|
def set_trace_and_span_context(method, trace = nil, span = nil)
|
81
|
-
if (
|
82
|
-
trace =
|
83
|
-
span =
|
81
|
+
if (appsec_context = Datadog::AppSec.active_context)
|
82
|
+
trace = appsec_context.trace
|
83
|
+
span = appsec_context.span
|
84
84
|
end
|
85
85
|
|
86
86
|
trace ||= Datadog::Tracing.active_trace
|
@@ -4,10 +4,13 @@ module Datadog
|
|
4
4
|
module Profiling
|
5
5
|
# Responsible for wiring up the Profiler for execution
|
6
6
|
module Component
|
7
|
+
ALLOCATION_WITH_RACTORS_ONLY_ONCE = Datadog::Core::Utils::OnlyOnce.new
|
8
|
+
private_constant :ALLOCATION_WITH_RACTORS_ONLY_ONCE
|
9
|
+
|
7
10
|
# Passing in a `nil` tracer is supported and will disable the following profiling features:
|
8
|
-
# *
|
11
|
+
# * Profiling in the trace viewer, as well as scoping a profile down to a span
|
9
12
|
# * Endpoint aggregation in the profiler UX, including normalization (resource per endpoint call)
|
10
|
-
def self.build_profiler_component(settings:, agent_settings:, optional_tracer:) # rubocop:disable Metrics/MethodLength
|
13
|
+
def self.build_profiler_component(settings:, agent_settings:, optional_tracer:, logger:) # rubocop:disable Metrics/MethodLength
|
11
14
|
return [nil, {profiling_enabled: false}] unless settings.profiling.enabled
|
12
15
|
|
13
16
|
# Workaround for weird dependency direction: the Core::Configuration::Components class currently has a
|
@@ -36,14 +39,14 @@ module Datadog
|
|
36
39
|
|
37
40
|
# NOTE: Please update the Initialization section of ProfilingDevelopment.md with any changes to this method
|
38
41
|
|
39
|
-
no_signals_workaround_enabled = no_signals_workaround_enabled?(settings)
|
42
|
+
no_signals_workaround_enabled = no_signals_workaround_enabled?(settings, logger)
|
40
43
|
timeline_enabled = settings.profiling.advanced.timeline_enabled
|
41
|
-
allocation_profiling_enabled = enable_allocation_profiling?(settings)
|
44
|
+
allocation_profiling_enabled = enable_allocation_profiling?(settings, logger)
|
42
45
|
heap_sample_every = get_heap_sample_every(settings)
|
43
|
-
heap_profiling_enabled = enable_heap_profiling?(settings, allocation_profiling_enabled, heap_sample_every)
|
44
|
-
heap_size_profiling_enabled = enable_heap_size_profiling?(settings, heap_profiling_enabled)
|
46
|
+
heap_profiling_enabled = enable_heap_profiling?(settings, allocation_profiling_enabled, heap_sample_every, logger)
|
47
|
+
heap_size_profiling_enabled = enable_heap_size_profiling?(settings, heap_profiling_enabled, logger)
|
45
48
|
|
46
|
-
overhead_target_percentage = valid_overhead_target(settings.profiling.advanced.overhead_target_percentage)
|
49
|
+
overhead_target_percentage = valid_overhead_target(settings.profiling.advanced.overhead_target_percentage, logger)
|
47
50
|
upload_period_seconds = [60, settings.profiling.advanced.upload_period_seconds].max
|
48
51
|
|
49
52
|
recorder = Datadog::Profiling::StackRecorder.new(
|
@@ -57,13 +60,13 @@ module Datadog
|
|
57
60
|
)
|
58
61
|
thread_context_collector = build_thread_context_collector(settings, recorder, optional_tracer, timeline_enabled)
|
59
62
|
worker = Datadog::Profiling::Collectors::CpuAndWallTimeWorker.new(
|
60
|
-
gc_profiling_enabled: enable_gc_profiling?(settings),
|
63
|
+
gc_profiling_enabled: enable_gc_profiling?(settings, logger),
|
61
64
|
no_signals_workaround_enabled: no_signals_workaround_enabled,
|
62
65
|
thread_context_collector: thread_context_collector,
|
63
66
|
dynamic_sampling_rate_overhead_target_percentage: overhead_target_percentage,
|
64
67
|
allocation_profiling_enabled: allocation_profiling_enabled,
|
65
68
|
allocation_counting_enabled: settings.profiling.advanced.allocation_counting_enabled,
|
66
|
-
gvl_profiling_enabled: enable_gvl_profiling?(settings),
|
69
|
+
gvl_profiling_enabled: enable_gvl_profiling?(settings, logger),
|
67
70
|
)
|
68
71
|
|
69
72
|
internal_metadata = {
|
@@ -120,7 +123,7 @@ module Datadog
|
|
120
123
|
)
|
121
124
|
end
|
122
125
|
|
123
|
-
private_class_method def self.enable_gc_profiling?(settings)
|
126
|
+
private_class_method def self.enable_gc_profiling?(settings, logger)
|
124
127
|
return false unless settings.profiling.advanced.gc_enabled
|
125
128
|
|
126
129
|
# SEVERE - Only with Ractors
|
@@ -131,14 +134,14 @@ module Datadog
|
|
131
134
|
if RUBY_VERSION.start_with?("3.0.") ||
|
132
135
|
(RUBY_VERSION.start_with?("3.1.") && RUBY_VERSION < "3.1.4") ||
|
133
136
|
(RUBY_VERSION.start_with?("3.2.") && RUBY_VERSION < "3.2.3")
|
134
|
-
|
137
|
+
logger.warn(
|
135
138
|
"Current Ruby version (#{RUBY_VERSION}) has a VM bug where enabling GC profiling would cause " \
|
136
139
|
"crashes (https://bugs.ruby-lang.org/issues/18464). GC profiling has been disabled."
|
137
140
|
)
|
138
141
|
return false
|
139
142
|
elsif RUBY_VERSION.start_with?("3.")
|
140
|
-
|
141
|
-
"
|
143
|
+
logger.debug(
|
144
|
+
"Using Ractors may result in GC profiling unexpectedly " \
|
142
145
|
"stopping (https://bugs.ruby-lang.org/issues/19112). Note that this stop has no impact in your " \
|
143
146
|
"application stability or performance. This does not happen if Ractors are not used."
|
144
147
|
)
|
@@ -155,7 +158,7 @@ module Datadog
|
|
155
158
|
heap_sample_rate
|
156
159
|
end
|
157
160
|
|
158
|
-
private_class_method def self.enable_allocation_profiling?(settings)
|
161
|
+
private_class_method def self.enable_allocation_profiling?(settings, logger)
|
159
162
|
return false unless settings.profiling.allocation_enabled
|
160
163
|
|
161
164
|
# Allocation sampling is safe and supported on Ruby 2.x, but has a few caveats on Ruby 3.x.
|
@@ -165,7 +168,7 @@ module Datadog
|
|
165
168
|
# https://github.com/ruby/ruby/pull/7464) that makes this crash in any configuration. This bug is
|
166
169
|
# fixed on Ruby versions 3.2.3 and 3.3.0.
|
167
170
|
if RUBY_VERSION.start_with?("3.2.") && RUBY_VERSION < "3.2.3"
|
168
|
-
|
171
|
+
logger.warn(
|
169
172
|
"Allocation profiling is not supported in Ruby versions 3.2.0, 3.2.1 and 3.2.2 and will be forcibly " \
|
170
173
|
"disabled. This is due to a VM bug that can lead to crashes (https://bugs.ruby-lang.org/issues/19482). " \
|
171
174
|
"Other Ruby versions do not suffer from this issue."
|
@@ -181,7 +184,7 @@ module Datadog
|
|
181
184
|
if RUBY_VERSION.start_with?("3.0.") ||
|
182
185
|
(RUBY_VERSION.start_with?("3.1.") && RUBY_VERSION < "3.1.4") ||
|
183
186
|
(RUBY_VERSION.start_with?("3.2.") && RUBY_VERSION < "3.2.3")
|
184
|
-
|
187
|
+
logger.warn(
|
185
188
|
"Current Ruby version (#{RUBY_VERSION}) has a VM bug where enabling allocation profiling while using " \
|
186
189
|
"Ractors may cause unexpected issues, including crashes (https://bugs.ruby-lang.org/issues/18464). " \
|
187
190
|
"This does not happen if Ractors are not used."
|
@@ -190,25 +193,27 @@ module Datadog
|
|
190
193
|
# On all known versions of Ruby 3.x, due to https://bugs.ruby-lang.org/issues/19112, when a ractor gets
|
191
194
|
# garbage collected, Ruby will disable all active tracepoints, which this feature internally relies on.
|
192
195
|
elsif RUBY_VERSION.start_with?("3.")
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
196
|
+
ALLOCATION_WITH_RACTORS_ONLY_ONCE.run do
|
197
|
+
logger.info(
|
198
|
+
"Using Ractors may result in allocation profiling " \
|
199
|
+
"stopping (https://bugs.ruby-lang.org/issues/19112). Note that this stop has no impact in your " \
|
200
|
+
"application stability or performance. This does not happen if Ractors are not used."
|
201
|
+
)
|
202
|
+
end
|
198
203
|
end
|
199
204
|
|
200
|
-
|
205
|
+
logger.debug("Enabled allocation profiling")
|
201
206
|
|
202
207
|
true
|
203
208
|
end
|
204
209
|
|
205
|
-
private_class_method def self.enable_heap_profiling?(settings, allocation_profiling_enabled, heap_sample_rate)
|
210
|
+
private_class_method def self.enable_heap_profiling?(settings, allocation_profiling_enabled, heap_sample_rate, logger)
|
206
211
|
heap_profiling_enabled = settings.profiling.advanced.experimental_heap_enabled
|
207
212
|
|
208
213
|
return false unless heap_profiling_enabled
|
209
214
|
|
210
215
|
if RUBY_VERSION < "3.1"
|
211
|
-
|
216
|
+
logger.warn(
|
212
217
|
"Current Ruby version (#{RUBY_VERSION}) cannot support heap profiling due to VM limitations. " \
|
213
218
|
"Please upgrade to Ruby >= 3.1 in order to use this feature. Heap profiling has been disabled."
|
214
219
|
)
|
@@ -219,7 +224,7 @@ module Datadog
|
|
219
224
|
raise ArgumentError, "Heap profiling requires allocation profiling to be enabled"
|
220
225
|
end
|
221
226
|
|
222
|
-
|
227
|
+
logger.warn(
|
223
228
|
"Enabled experimental heap profiling: heap_sample_rate=#{heap_sample_rate}. This is experimental, not " \
|
224
229
|
"recommended, and will increase overhead!"
|
225
230
|
)
|
@@ -227,25 +232,23 @@ module Datadog
|
|
227
232
|
true
|
228
233
|
end
|
229
234
|
|
230
|
-
private_class_method def self.enable_heap_size_profiling?(settings, heap_profiling_enabled)
|
235
|
+
private_class_method def self.enable_heap_size_profiling?(settings, heap_profiling_enabled, logger)
|
231
236
|
heap_size_profiling_enabled = settings.profiling.advanced.experimental_heap_size_enabled
|
232
237
|
|
233
238
|
return false unless heap_profiling_enabled && heap_size_profiling_enabled
|
234
239
|
|
235
|
-
|
240
|
+
logger.warn(
|
236
241
|
"Enabled experimental heap size profiling. This is experimental, not recommended, and will increase overhead!"
|
237
242
|
)
|
238
243
|
|
239
244
|
true
|
240
245
|
end
|
241
246
|
|
242
|
-
private_class_method def self.no_signals_workaround_enabled?(settings) # rubocop:disable Metrics/MethodLength
|
247
|
+
private_class_method def self.no_signals_workaround_enabled?(settings, logger) # rubocop:disable Metrics/MethodLength
|
243
248
|
setting_value = settings.profiling.advanced.no_signals_workaround_enabled
|
244
|
-
legacy_ruby_that_should_use_workaround = RUBY_VERSION.start_with?("2.5.")
|
245
249
|
|
246
250
|
unless [true, false, :auto].include?(setting_value)
|
247
|
-
|
248
|
-
Datadog.logger.error(
|
251
|
+
logger.warn(
|
249
252
|
"Ignoring invalid value for profiling no_signals_workaround_enabled setting: #{setting_value.inspect}. " \
|
250
253
|
"Valid options are `true`, `false` or (default) `:auto`."
|
251
254
|
)
|
@@ -254,23 +257,23 @@ module Datadog
|
|
254
257
|
end
|
255
258
|
|
256
259
|
if setting_value == false
|
257
|
-
if
|
258
|
-
|
259
|
-
'The profiling "no signals" workaround has been disabled via configuration on
|
260
|
-
"
|
261
|
-
"in production environments, as due to limitations in Ruby APIs, we suspect it may lead to crashes " \
|
262
|
-
"
|
260
|
+
if RUBY_VERSION.start_with?("2.5.")
|
261
|
+
logger.warn(
|
262
|
+
'The profiling "no signals" workaround has been disabled via configuration on Ruby 2.5. ' \
|
263
|
+
"This is not recommended " \
|
264
|
+
"in production environments, as due to limitations in Ruby APIs, we suspect it may lead to rare crashes " \
|
265
|
+
"Please report any issues you run into to Datadog support or " \
|
263
266
|
"via <https://github.com/datadog/dd-trace-rb/issues/new>!"
|
264
267
|
)
|
265
268
|
else
|
266
|
-
|
269
|
+
logger.warn('Profiling "no signals" workaround disabled via configuration')
|
267
270
|
end
|
268
271
|
|
269
272
|
return false
|
270
273
|
end
|
271
274
|
|
272
275
|
if setting_value == true
|
273
|
-
|
276
|
+
logger.warn(
|
274
277
|
'Profiling "no signals" workaround enabled via configuration. Profiling data will have lower quality.'
|
275
278
|
)
|
276
279
|
|
@@ -280,10 +283,10 @@ module Datadog
|
|
280
283
|
# Setting is in auto mode. Let's probe to see if we should enable it:
|
281
284
|
|
282
285
|
# We don't warn users in this situation because "upgrade your Ruby" is not a great warning
|
283
|
-
return true if
|
286
|
+
return true if RUBY_VERSION.start_with?("2.5.")
|
284
287
|
|
285
|
-
if Gem.loaded_specs["mysql2"] && incompatible_libmysqlclient_version?(settings)
|
286
|
-
|
288
|
+
if Gem.loaded_specs["mysql2"] && incompatible_libmysqlclient_version?(settings, logger)
|
289
|
+
logger.warn(
|
287
290
|
'Enabling the profiling "no signals" workaround because an incompatible version of the mysql2 gem is ' \
|
288
291
|
"installed. Profiling data will have lower quality. " \
|
289
292
|
"To fix this, upgrade the libmysqlclient in your OS image to version 8.0.0 or above."
|
@@ -292,7 +295,7 @@ module Datadog
|
|
292
295
|
end
|
293
296
|
|
294
297
|
if Gem.loaded_specs["rugged"]
|
295
|
-
|
298
|
+
logger.warn(
|
296
299
|
'Enabling the profiling "no signals" workaround because the rugged gem is installed. ' \
|
297
300
|
"This is needed because some operations on this gem are currently incompatible with the normal working mode " \
|
298
301
|
"of the profiler, as detailed in <https://github.com/datadog/dd-trace-rb/issues/2721>. " \
|
@@ -302,7 +305,7 @@ module Datadog
|
|
302
305
|
end
|
303
306
|
|
304
307
|
if (defined?(::PhusionPassenger) || Gem.loaded_specs["passenger"]) && incompatible_passenger_version?
|
305
|
-
|
308
|
+
logger.warn(
|
306
309
|
'Enabling the profiling "no signals" workaround because an incompatible version of the passenger gem is ' \
|
307
310
|
"installed. Profiling data will have lower quality." \
|
308
311
|
"To fix this, upgrade the passenger gem to version 6.0.19 or above."
|
@@ -322,10 +325,10 @@ module Datadog
|
|
322
325
|
#
|
323
326
|
# The `mysql2` gem's `info` method can be used to determine which `libmysqlclient` version is in use, and thus to
|
324
327
|
# detect if it's safe for the profiler to use signals or if we need to employ a fallback.
|
325
|
-
private_class_method def self.incompatible_libmysqlclient_version?(settings)
|
328
|
+
private_class_method def self.incompatible_libmysqlclient_version?(settings, logger)
|
326
329
|
return true if settings.profiling.advanced.skip_mysql2_check
|
327
330
|
|
328
|
-
|
331
|
+
logger.debug(
|
329
332
|
"Requiring `mysql2` to check if the `libmysqlclient` version it uses is compatible with profiling"
|
330
333
|
)
|
331
334
|
|
@@ -354,14 +357,14 @@ module Datadog
|
|
354
357
|
libmysqlclient_version >= Gem::Version.new("8.0.0") ||
|
355
358
|
looks_like_mariadb?(info, libmysqlclient_version)
|
356
359
|
|
357
|
-
|
360
|
+
logger.debug(
|
358
361
|
"The `mysql2` gem is using #{compatible ? "a compatible" : "an incompatible"} version of " \
|
359
362
|
"the `libmysqlclient` library (#{libmysqlclient_version})"
|
360
363
|
)
|
361
364
|
|
362
365
|
!compatible
|
363
366
|
rescue StandardError, LoadError => e
|
364
|
-
|
367
|
+
logger.warn(
|
365
368
|
"Failed to probe `mysql2` gem information. " \
|
366
369
|
"Cause: #{e.class.name} #{e.message} Location: #{Array(e.backtrace).first}"
|
367
370
|
)
|
@@ -383,12 +386,11 @@ module Datadog
|
|
383
386
|
end
|
384
387
|
end
|
385
388
|
|
386
|
-
private_class_method def self.valid_overhead_target(overhead_target_percentage)
|
389
|
+
private_class_method def self.valid_overhead_target(overhead_target_percentage, logger)
|
387
390
|
if overhead_target_percentage > 0 && overhead_target_percentage <= 20
|
388
391
|
overhead_target_percentage
|
389
392
|
else
|
390
|
-
|
391
|
-
Datadog.logger.error(
|
393
|
+
logger.warn(
|
392
394
|
"Ignoring invalid value for profiling overhead_target_percentage setting: " \
|
393
395
|
"#{overhead_target_percentage.inspect}. Falling back to default value."
|
394
396
|
)
|
@@ -432,10 +434,10 @@ module Datadog
|
|
432
434
|
settings.profiling.advanced.dir_interruption_workaround_enabled
|
433
435
|
end
|
434
436
|
|
435
|
-
private_class_method def self.enable_gvl_profiling?(settings)
|
437
|
+
private_class_method def self.enable_gvl_profiling?(settings, logger)
|
436
438
|
if RUBY_VERSION < "3.2"
|
437
439
|
if settings.profiling.advanced.preview_gvl_enabled
|
438
|
-
|
440
|
+
logger.warn("GVL profiling is currently not supported in Ruby < 3.2 and will not be enabled.")
|
439
441
|
end
|
440
442
|
|
441
443
|
return false
|
@@ -13,13 +13,11 @@ module Datadog
|
|
13
13
|
def initialize(agent_settings:, site:, api_key:, upload_timeout_seconds:)
|
14
14
|
@upload_timeout_milliseconds = (upload_timeout_seconds * 1_000).to_i
|
15
15
|
|
16
|
-
validate_agent_settings(agent_settings)
|
17
|
-
|
18
16
|
@exporter_configuration =
|
19
17
|
if agentless?(site, api_key)
|
20
18
|
[:agentless, site, api_key].freeze
|
21
19
|
else
|
22
|
-
[:agent,
|
20
|
+
[:agent, agent_settings.url].freeze
|
23
21
|
end
|
24
22
|
|
25
23
|
status, result = validate_exporter(exporter_configuration)
|
@@ -75,29 +73,6 @@ module Datadog
|
|
75
73
|
|
76
74
|
private
|
77
75
|
|
78
|
-
def base_url_from(agent_settings)
|
79
|
-
case agent_settings.adapter
|
80
|
-
when Datadog::Core::Configuration::Ext::Agent::HTTP::ADAPTER
|
81
|
-
"#{agent_settings.ssl ? "https" : "http"}://#{agent_settings.hostname}:#{agent_settings.port}/"
|
82
|
-
when Datadog::Core::Configuration::Ext::Agent::UnixSocket::ADAPTER
|
83
|
-
"unix://#{agent_settings.uds_path}"
|
84
|
-
else
|
85
|
-
raise ArgumentError, "Unexpected adapter: #{agent_settings.adapter}"
|
86
|
-
end
|
87
|
-
end
|
88
|
-
|
89
|
-
def validate_agent_settings(agent_settings)
|
90
|
-
supported_adapters = [
|
91
|
-
Datadog::Core::Configuration::Ext::Agent::UnixSocket::ADAPTER,
|
92
|
-
Datadog::Core::Configuration::Ext::Agent::HTTP::ADAPTER
|
93
|
-
]
|
94
|
-
unless supported_adapters.include?(agent_settings.adapter)
|
95
|
-
raise ArgumentError,
|
96
|
-
"Unsupported transport configuration for profiling: Adapter #{agent_settings.adapter} " \
|
97
|
-
" is not supported"
|
98
|
-
end
|
99
|
-
end
|
100
|
-
|
101
76
|
def agentless?(site, api_key)
|
102
77
|
site && api_key && Core::Environment::VariableHelpers.env_to_bool(Profiling::Ext::ENV_AGENTLESS, false)
|
103
78
|
end
|
@@ -3,7 +3,7 @@
|
|
3
3
|
require_relative '../integration'
|
4
4
|
require_relative 'configuration/settings'
|
5
5
|
require_relative 'patcher'
|
6
|
-
require_relative '
|
6
|
+
require_relative '../../../core/contrib/rails/utils'
|
7
7
|
|
8
8
|
module Datadog
|
9
9
|
module Tracing
|
@@ -17,6 +17,9 @@ module Datadog
|
|
17
17
|
|
18
18
|
# @public_api Changing the integration name or integration options can cause breaking changes
|
19
19
|
register_as :action_cable, auto_patch: false
|
20
|
+
def self.gem_name
|
21
|
+
'actioncable'
|
22
|
+
end
|
20
23
|
|
21
24
|
def self.version
|
22
25
|
Gem.loaded_specs['actioncable'] && Gem.loaded_specs['actioncable'].version
|
@@ -33,7 +36,7 @@ module Datadog
|
|
33
36
|
# enabled by rails integration so should only auto instrument
|
34
37
|
# if detected that it is being used without rails
|
35
38
|
def auto_instrument?
|
36
|
-
!Contrib::Rails::Utils.railtie_supported?
|
39
|
+
!Core::Contrib::Rails::Utils.railtie_supported?
|
37
40
|
end
|
38
41
|
|
39
42
|
def new_configuration
|
@@ -3,7 +3,7 @@
|
|
3
3
|
require_relative 'configuration/settings'
|
4
4
|
require_relative 'patcher'
|
5
5
|
require_relative '../integration'
|
6
|
-
require_relative '
|
6
|
+
require_relative '../../../core/contrib/rails/utils'
|
7
7
|
|
8
8
|
module Datadog
|
9
9
|
module Tracing
|
@@ -18,6 +18,10 @@ module Datadog
|
|
18
18
|
# @public_api Changing the integration name or integration options can cause breaking changes
|
19
19
|
register_as :action_mailer, auto_patch: false
|
20
20
|
|
21
|
+
def self.gem_name
|
22
|
+
'actionmailer'
|
23
|
+
end
|
24
|
+
|
21
25
|
def self.version
|
22
26
|
Gem.loaded_specs['actionmailer'] && Gem.loaded_specs['actionmailer'].version
|
23
27
|
end
|
@@ -33,7 +37,7 @@ module Datadog
|
|
33
37
|
# enabled by rails integration so should only auto instrument
|
34
38
|
# if detected that it is being used without rails
|
35
39
|
def auto_instrument?
|
36
|
-
!Contrib::Rails::Utils.railtie_supported?
|
40
|
+
!Core::Contrib::Rails::Utils.railtie_supported?
|
37
41
|
end
|
38
42
|
|
39
43
|
def new_configuration
|
@@ -4,7 +4,7 @@ require_relative 'configuration/settings'
|
|
4
4
|
require_relative 'patcher'
|
5
5
|
require_relative '../integration'
|
6
6
|
require_relative '../rails/ext'
|
7
|
-
require_relative '
|
7
|
+
require_relative '../../../core/contrib/rails/utils'
|
8
8
|
|
9
9
|
module Datadog
|
10
10
|
module Tracing
|
@@ -18,6 +18,9 @@ module Datadog
|
|
18
18
|
|
19
19
|
# @public_api Changing the integration name or integration options can cause breaking changes
|
20
20
|
register_as :action_pack, auto_patch: false
|
21
|
+
def self.gem_name
|
22
|
+
'actionpack'
|
23
|
+
end
|
21
24
|
|
22
25
|
def self.version
|
23
26
|
Gem.loaded_specs['actionpack'] && Gem.loaded_specs['actionpack'].version
|
@@ -34,7 +37,7 @@ module Datadog
|
|
34
37
|
# enabled by rails integration so should only auto instrument
|
35
38
|
# if detected that it is being used without rails
|
36
39
|
def auto_instrument?
|
37
|
-
!Contrib::Rails::Utils.railtie_supported?
|
40
|
+
!Core::Contrib::Rails::Utils.railtie_supported?
|
38
41
|
end
|
39
42
|
|
40
43
|
def new_configuration
|