datadog 2.3.0 → 2.5.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 +64 -2
- data/ext/datadog_profiling_loader/datadog_profiling_loader.c +9 -1
- data/ext/datadog_profiling_loader/extconf.rb +10 -22
- data/ext/datadog_profiling_native_extension/NativeExtensionDesign.md +3 -3
- data/ext/datadog_profiling_native_extension/collectors_cpu_and_wall_time_worker.c +198 -41
- data/ext/datadog_profiling_native_extension/collectors_discrete_dynamic_sampler.c +4 -2
- data/ext/datadog_profiling_native_extension/collectors_stack.c +89 -46
- data/ext/datadog_profiling_native_extension/collectors_thread_context.c +645 -107
- data/ext/datadog_profiling_native_extension/collectors_thread_context.h +15 -1
- data/ext/datadog_profiling_native_extension/datadog_ruby_common.c +0 -27
- data/ext/datadog_profiling_native_extension/datadog_ruby_common.h +0 -4
- data/ext/datadog_profiling_native_extension/extconf.rb +42 -25
- data/ext/datadog_profiling_native_extension/gvl_profiling_helper.c +50 -0
- data/ext/datadog_profiling_native_extension/gvl_profiling_helper.h +75 -0
- data/ext/datadog_profiling_native_extension/heap_recorder.c +194 -34
- data/ext/datadog_profiling_native_extension/heap_recorder.h +11 -0
- data/ext/datadog_profiling_native_extension/http_transport.c +38 -6
- data/ext/datadog_profiling_native_extension/native_extension_helpers.rb +1 -1
- data/ext/datadog_profiling_native_extension/private_vm_api_access.c +53 -2
- data/ext/datadog_profiling_native_extension/private_vm_api_access.h +3 -0
- data/ext/datadog_profiling_native_extension/profiling.c +1 -1
- data/ext/datadog_profiling_native_extension/ruby_helpers.c +14 -11
- data/ext/datadog_profiling_native_extension/stack_recorder.c +58 -22
- data/ext/datadog_profiling_native_extension/stack_recorder.h +2 -0
- data/ext/libdatadog_api/crashtracker.c +20 -18
- data/ext/libdatadog_api/datadog_ruby_common.c +0 -27
- data/ext/libdatadog_api/datadog_ruby_common.h +0 -4
- data/ext/libdatadog_extconf_helpers.rb +1 -1
- data/lib/datadog/appsec/assets/waf_rules/recommended.json +2184 -108
- data/lib/datadog/appsec/assets/waf_rules/strict.json +1430 -2
- data/lib/datadog/appsec/component.rb +29 -8
- data/lib/datadog/appsec/configuration/settings.rb +10 -2
- data/lib/datadog/appsec/contrib/devise/patcher/authenticatable_patch.rb +1 -0
- data/lib/datadog/appsec/contrib/devise/patcher/rememberable_patch.rb +21 -0
- data/lib/datadog/appsec/contrib/devise/patcher.rb +12 -2
- data/lib/datadog/appsec/contrib/graphql/appsec_trace.rb +0 -14
- data/lib/datadog/appsec/contrib/graphql/gateway/multiplex.rb +67 -31
- data/lib/datadog/appsec/contrib/graphql/gateway/watcher.rb +14 -15
- data/lib/datadog/appsec/contrib/graphql/integration.rb +14 -1
- data/lib/datadog/appsec/contrib/graphql/reactive/multiplex.rb +7 -20
- data/lib/datadog/appsec/contrib/rack/gateway/request.rb +2 -5
- data/lib/datadog/appsec/contrib/rack/gateway/watcher.rb +9 -15
- data/lib/datadog/appsec/contrib/rack/reactive/request.rb +6 -18
- data/lib/datadog/appsec/contrib/rack/reactive/request_body.rb +7 -20
- data/lib/datadog/appsec/contrib/rack/reactive/response.rb +5 -18
- data/lib/datadog/appsec/contrib/rack/request_middleware.rb +3 -1
- data/lib/datadog/appsec/contrib/rails/gateway/watcher.rb +3 -5
- data/lib/datadog/appsec/contrib/rails/reactive/action.rb +5 -18
- data/lib/datadog/appsec/contrib/sinatra/gateway/watcher.rb +6 -10
- data/lib/datadog/appsec/contrib/sinatra/reactive/routed.rb +7 -20
- data/lib/datadog/appsec/event.rb +25 -1
- data/lib/datadog/appsec/ext.rb +4 -0
- data/lib/datadog/appsec/monitor/gateway/watcher.rb +3 -5
- data/lib/datadog/appsec/monitor/reactive/set_user.rb +7 -20
- data/lib/datadog/appsec/processor/context.rb +109 -0
- data/lib/datadog/appsec/processor/rule_loader.rb +3 -1
- data/lib/datadog/appsec/processor/rule_merger.rb +33 -15
- data/lib/datadog/appsec/processor.rb +42 -107
- data/lib/datadog/appsec/rate_limiter.rb +25 -40
- data/lib/datadog/appsec/remote.rb +7 -3
- data/lib/datadog/appsec/scope.rb +1 -4
- data/lib/datadog/appsec/utils/trace_operation.rb +15 -0
- data/lib/datadog/appsec/utils.rb +2 -0
- data/lib/datadog/appsec.rb +3 -2
- data/lib/datadog/core/configuration/agent_settings_resolver.rb +26 -25
- data/lib/datadog/core/configuration/components.rb +4 -3
- data/lib/datadog/core/configuration/settings.rb +96 -5
- data/lib/datadog/core/configuration.rb +1 -3
- data/lib/datadog/core/crashtracking/component.rb +9 -6
- data/lib/datadog/core/environment/execution.rb +5 -5
- data/lib/datadog/core/environment/yjit.rb +5 -0
- data/lib/datadog/core/metrics/client.rb +7 -0
- data/lib/datadog/core/rate_limiter.rb +183 -0
- data/lib/datadog/core/remote/client/capabilities.rb +4 -3
- data/lib/datadog/core/remote/component.rb +4 -2
- data/lib/datadog/core/remote/negotiation.rb +4 -4
- data/lib/datadog/core/remote/tie.rb +2 -0
- data/lib/datadog/core/remote/transport/http.rb +5 -0
- data/lib/datadog/core/remote/worker.rb +1 -1
- data/lib/datadog/core/runtime/ext.rb +1 -0
- data/lib/datadog/core/runtime/metrics.rb +5 -1
- data/lib/datadog/core/semaphore.rb +35 -0
- data/lib/datadog/core/telemetry/component.rb +2 -0
- data/lib/datadog/core/telemetry/event.rb +12 -7
- data/lib/datadog/core/telemetry/logger.rb +51 -0
- data/lib/datadog/core/telemetry/logging.rb +50 -14
- data/lib/datadog/core/telemetry/request.rb +13 -1
- data/lib/datadog/core/transport/ext.rb +1 -0
- data/lib/datadog/core/utils/time.rb +12 -0
- data/lib/datadog/core/workers/async.rb +1 -1
- data/lib/datadog/di/code_tracker.rb +166 -0
- data/lib/datadog/di/configuration/settings.rb +163 -0
- data/lib/datadog/di/configuration.rb +11 -0
- data/lib/datadog/di/error.rb +31 -0
- data/lib/datadog/di/extensions.rb +16 -0
- data/lib/datadog/di/instrumenter.rb +301 -0
- data/lib/datadog/di/probe.rb +162 -0
- data/lib/datadog/di/probe_builder.rb +47 -0
- data/lib/datadog/di/probe_notification_builder.rb +207 -0
- data/lib/datadog/di/probe_notifier_worker.rb +244 -0
- data/lib/datadog/di/redactor.rb +188 -0
- data/lib/datadog/di/serializer.rb +215 -0
- data/lib/datadog/di/transport.rb +67 -0
- data/lib/datadog/di/utils.rb +39 -0
- data/lib/datadog/di.rb +57 -0
- data/lib/datadog/opentelemetry/sdk/propagator.rb +2 -0
- data/lib/datadog/profiling/collectors/cpu_and_wall_time_worker.rb +12 -10
- data/lib/datadog/profiling/collectors/info.rb +12 -3
- data/lib/datadog/profiling/collectors/thread_context.rb +32 -8
- data/lib/datadog/profiling/component.rb +21 -4
- data/lib/datadog/profiling/http_transport.rb +6 -1
- data/lib/datadog/profiling/scheduler.rb +2 -0
- data/lib/datadog/profiling/stack_recorder.rb +40 -9
- data/lib/datadog/single_step_instrument.rb +12 -0
- data/lib/datadog/tracing/component.rb +13 -0
- data/lib/datadog/tracing/contrib/action_cable/instrumentation.rb +8 -12
- data/lib/datadog/tracing/contrib/action_pack/action_controller/instrumentation.rb +5 -0
- data/lib/datadog/tracing/contrib/action_pack/action_dispatch/instrumentation.rb +78 -0
- data/lib/datadog/tracing/contrib/action_pack/action_dispatch/patcher.rb +33 -0
- data/lib/datadog/tracing/contrib/action_pack/patcher.rb +2 -0
- data/lib/datadog/tracing/contrib/active_record/configuration/resolver.rb +4 -0
- data/lib/datadog/tracing/contrib/active_record/events/instantiation.rb +3 -1
- data/lib/datadog/tracing/contrib/active_record/events/sql.rb +3 -1
- data/lib/datadog/tracing/contrib/active_support/cache/events/cache.rb +5 -1
- data/lib/datadog/tracing/contrib/aws/instrumentation.rb +5 -0
- data/lib/datadog/tracing/contrib/elasticsearch/patcher.rb +6 -1
- data/lib/datadog/tracing/contrib/ethon/easy_patch.rb +4 -0
- data/lib/datadog/tracing/contrib/excon/middleware.rb +3 -0
- data/lib/datadog/tracing/contrib/faraday/middleware.rb +12 -0
- data/lib/datadog/tracing/contrib/grape/endpoint.rb +24 -2
- data/lib/datadog/tracing/contrib/graphql/patcher.rb +9 -12
- data/lib/datadog/tracing/contrib/graphql/trace_patcher.rb +3 -3
- data/lib/datadog/tracing/contrib/graphql/tracing_patcher.rb +3 -3
- data/lib/datadog/tracing/contrib/graphql/unified_trace.rb +13 -9
- data/lib/datadog/tracing/contrib/graphql/unified_trace_patcher.rb +6 -3
- data/lib/datadog/tracing/contrib/http/circuit_breaker.rb +9 -0
- data/lib/datadog/tracing/contrib/http/instrumentation.rb +22 -15
- data/lib/datadog/tracing/contrib/httpclient/instrumentation.rb +10 -5
- data/lib/datadog/tracing/contrib/httpclient/patcher.rb +1 -14
- data/lib/datadog/tracing/contrib/httprb/instrumentation.rb +9 -0
- data/lib/datadog/tracing/contrib/httprb/patcher.rb +1 -14
- data/lib/datadog/tracing/contrib/lograge/patcher.rb +1 -2
- data/lib/datadog/tracing/contrib/mongodb/subscribers.rb +2 -0
- data/lib/datadog/tracing/contrib/opensearch/patcher.rb +13 -6
- data/lib/datadog/tracing/contrib/patcher.rb +2 -1
- data/lib/datadog/tracing/contrib/presto/patcher.rb +1 -13
- data/lib/datadog/tracing/contrib/rack/middlewares.rb +27 -0
- data/lib/datadog/tracing/contrib/rails/runner.rb +1 -1
- data/lib/datadog/tracing/contrib/redis/tags.rb +4 -0
- data/lib/datadog/tracing/contrib/rest_client/request_patch.rb +3 -0
- data/lib/datadog/tracing/contrib/sinatra/tracer.rb +4 -0
- data/lib/datadog/tracing/contrib/stripe/request.rb +3 -2
- data/lib/datadog/tracing/distributed/propagation.rb +7 -0
- data/lib/datadog/tracing/metadata/ext.rb +2 -0
- data/lib/datadog/tracing/remote.rb +5 -2
- data/lib/datadog/tracing/sampling/matcher.rb +6 -1
- data/lib/datadog/tracing/sampling/rate_sampler.rb +1 -1
- data/lib/datadog/tracing/sampling/rule.rb +2 -0
- data/lib/datadog/tracing/sampling/rule_sampler.rb +15 -9
- data/lib/datadog/tracing/sampling/span/ext.rb +1 -1
- data/lib/datadog/tracing/sampling/span/rule.rb +2 -2
- data/lib/datadog/tracing/trace_operation.rb +26 -2
- data/lib/datadog/tracing/tracer.rb +29 -22
- data/lib/datadog/tracing/transport/http/client.rb +1 -0
- data/lib/datadog/tracing/transport/http.rb +4 -0
- data/lib/datadog/tracing/transport/io/client.rb +1 -0
- data/lib/datadog/tracing/workers/trace_writer.rb +1 -1
- data/lib/datadog/tracing/workers.rb +2 -2
- data/lib/datadog/tracing/writer.rb +26 -28
- data/lib/datadog/version.rb +1 -1
- metadata +40 -15
- data/lib/datadog/tracing/sampling/rate_limiter.rb +0 -185
@@ -1,60 +1,45 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require_relative '../core/rate_limiter'
|
4
|
+
|
3
5
|
module Datadog
|
4
6
|
module AppSec
|
5
|
-
#
|
6
|
-
#
|
7
|
+
# Per-thread rate limiter based on token bucket rate limiter.
|
8
|
+
#
|
9
|
+
# Since AppSec marks sampling to keep on a security event, this limits
|
10
|
+
# the flood of egress traces involving AppSec
|
7
11
|
class RateLimiter
|
8
|
-
|
9
|
-
@rate = rate
|
10
|
-
@timestamps = []
|
11
|
-
end
|
12
|
-
|
13
|
-
def limit
|
14
|
-
now = Time.now.to_f
|
15
|
-
|
16
|
-
loop do
|
17
|
-
oldest = @timestamps.first
|
18
|
-
|
19
|
-
break if oldest.nil? || now - oldest < 1
|
20
|
-
|
21
|
-
@timestamps.shift
|
22
|
-
end
|
23
|
-
|
24
|
-
@timestamps << now
|
25
|
-
|
26
|
-
if (count = @timestamps.count) <= @rate
|
27
|
-
yield
|
28
|
-
else
|
29
|
-
Datadog.logger.debug { "Rate limit hit: #{count}/#{@rate} AppSec traces/second" }
|
30
|
-
end
|
31
|
-
end
|
12
|
+
THREAD_KEY = :datadog_security_appsec_rate_limiter
|
32
13
|
|
33
14
|
class << self
|
34
|
-
def
|
35
|
-
rate_limiter
|
15
|
+
def thread_local
|
16
|
+
rate_limiter = Thread.current.thread_variable_get(THREAD_KEY)
|
17
|
+
return rate_limiter unless rate_limiter.nil?
|
18
|
+
|
19
|
+
Thread.current.thread_variable_set(THREAD_KEY, new(trace_rate_limit))
|
36
20
|
end
|
37
21
|
|
38
22
|
# reset a rate limiter: used for testing
|
39
|
-
def reset!
|
40
|
-
Thread.current
|
23
|
+
def reset!
|
24
|
+
Thread.current.thread_variable_set(THREAD_KEY, nil)
|
41
25
|
end
|
42
26
|
|
43
|
-
|
44
|
-
|
45
|
-
def rate_limiter(name)
|
46
|
-
case name
|
47
|
-
when :traces
|
48
|
-
Thread.current[:datadog_security_trace_rate_limiter] ||= RateLimiter.new(trace_rate_limit)
|
49
|
-
else
|
50
|
-
raise "unsupported rate limiter: #{name.inspect}"
|
51
|
-
end
|
52
|
-
end
|
27
|
+
private
|
53
28
|
|
54
29
|
def trace_rate_limit
|
55
30
|
Datadog.configuration.appsec.trace_rate_limit
|
56
31
|
end
|
57
32
|
end
|
33
|
+
|
34
|
+
def initialize(rate)
|
35
|
+
@rate_limiter = Core::TokenBucket.new(rate)
|
36
|
+
end
|
37
|
+
|
38
|
+
def limit
|
39
|
+
return yield if @rate_limiter.allow?
|
40
|
+
|
41
|
+
Datadog.logger.debug { "Rate limit hit: #{@rate_limiter.current_window_rate} AppSec traces/second" }
|
42
|
+
end
|
58
43
|
end
|
59
44
|
end
|
60
45
|
end
|
@@ -53,7 +53,7 @@ module Datadog
|
|
53
53
|
end
|
54
54
|
|
55
55
|
# rubocop:disable Metrics/MethodLength
|
56
|
-
def receivers
|
56
|
+
def receivers(telemetry)
|
57
57
|
return [] unless remote_features_enabled?
|
58
58
|
|
59
59
|
matcher = Core::Remote::Dispatcher::Matcher::Product.new(ASM_PRODUCTS)
|
@@ -86,7 +86,10 @@ module Datadog
|
|
86
86
|
end
|
87
87
|
|
88
88
|
if rules.empty?
|
89
|
-
settings_rules = AppSec::Processor::RuleLoader.load_rules(
|
89
|
+
settings_rules = AppSec::Processor::RuleLoader.load_rules(
|
90
|
+
telemetry: telemetry,
|
91
|
+
ruleset: Datadog.configuration.appsec.ruleset
|
92
|
+
)
|
90
93
|
|
91
94
|
raise NoRulesError, 'no default rules available' unless settings_rules
|
92
95
|
|
@@ -99,9 +102,10 @@ module Datadog
|
|
99
102
|
overrides: overrides,
|
100
103
|
exclusions: exclusions,
|
101
104
|
custom_rules: custom_rules,
|
105
|
+
telemetry: telemetry
|
102
106
|
)
|
103
107
|
|
104
|
-
Datadog::AppSec.reconfigure(ruleset: ruleset, actions: actions)
|
108
|
+
Datadog::AppSec.reconfigure(ruleset: ruleset, actions: actions, telemetry: telemetry)
|
105
109
|
end
|
106
110
|
|
107
111
|
[receiver]
|
data/lib/datadog/appsec/scope.rb
CHANGED
@@ -1,7 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative 'processor'
|
4
|
-
|
5
3
|
module Datadog
|
6
4
|
module AppSec
|
7
5
|
# Capture context essential to consistently call processor and report via traces
|
@@ -22,8 +20,7 @@ module Datadog
|
|
22
20
|
def activate_scope(trace, service_entry_span, processor)
|
23
21
|
raise ActiveScopeError, 'another scope is active, nested scopes are not supported' if active_scope
|
24
22
|
|
25
|
-
context =
|
26
|
-
|
23
|
+
context = processor.new_context
|
27
24
|
self.active_scope = new(trace, service_entry_span, context)
|
28
25
|
end
|
29
26
|
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Datadog
|
4
|
+
module AppSec
|
5
|
+
module Utils
|
6
|
+
# Utility class to to AppSec-specific trace operations
|
7
|
+
class TraceOperation
|
8
|
+
def self.appsec_standalone_reject?(trace)
|
9
|
+
Datadog.configuration.appsec.standalone.enabled &&
|
10
|
+
(trace.nil? || trace.get_tag(Datadog::AppSec::Ext::TAG_DISTRIBUTED_APPSEC_EVENT) != '1')
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
data/lib/datadog/appsec/utils.rb
CHANGED
data/lib/datadog/appsec.rb
CHANGED
@@ -4,6 +4,7 @@ require_relative 'appsec/configuration'
|
|
4
4
|
require_relative 'appsec/extensions'
|
5
5
|
require_relative 'appsec/scope'
|
6
6
|
require_relative 'appsec/ext'
|
7
|
+
require_relative 'appsec/utils'
|
7
8
|
|
8
9
|
module Datadog
|
9
10
|
# Namespace for Datadog AppSec instrumentation
|
@@ -23,12 +24,12 @@ module Datadog
|
|
23
24
|
appsec_component.processor if appsec_component
|
24
25
|
end
|
25
26
|
|
26
|
-
def reconfigure(ruleset:, actions:)
|
27
|
+
def reconfigure(ruleset:, actions:, telemetry:)
|
27
28
|
appsec_component = components.appsec
|
28
29
|
|
29
30
|
return unless appsec_component
|
30
31
|
|
31
|
-
appsec_component.reconfigure(ruleset: ruleset, actions: actions)
|
32
|
+
appsec_component.reconfigure(ruleset: ruleset, actions: actions, telemetry: telemetry)
|
32
33
|
end
|
33
34
|
|
34
35
|
def reconfigure_lock(&block)
|
@@ -232,7 +232,32 @@ module Datadog
|
|
232
232
|
end
|
233
233
|
|
234
234
|
def should_use_uds?
|
235
|
-
|
235
|
+
# When we have mixed settings for http/https and uds, we print a warning
|
236
|
+
# and use the uds settings.
|
237
|
+
mixed_http_and_uds
|
238
|
+
can_use_uds?
|
239
|
+
end
|
240
|
+
|
241
|
+
def mixed_http_and_uds
|
242
|
+
return @mixed_http_and_uds if defined?(@mixed_http_and_uds)
|
243
|
+
|
244
|
+
@mixed_http_and_uds = (configured_hostname || configured_port) && can_use_uds?
|
245
|
+
if @mixed_http_and_uds
|
246
|
+
warn_if_configuration_mismatch(
|
247
|
+
[
|
248
|
+
DetectedConfiguration.new(
|
249
|
+
friendly_name: 'configuration for unix domain socket',
|
250
|
+
value: parsed_url.to_s,
|
251
|
+
),
|
252
|
+
DetectedConfiguration.new(
|
253
|
+
friendly_name: 'configuration of hostname/port for http/https use',
|
254
|
+
value: "hostname: '#{hostname}', port: '#{port}'",
|
255
|
+
),
|
256
|
+
]
|
257
|
+
)
|
258
|
+
end
|
259
|
+
|
260
|
+
@mixed_http_and_uds
|
236
261
|
end
|
237
262
|
|
238
263
|
def can_use_uds?
|
@@ -307,30 +332,6 @@ module Datadog
|
|
307
332
|
uri.scheme == 'unix'
|
308
333
|
end
|
309
334
|
|
310
|
-
# When we have mixed settings for http/https and uds, we print a warning and ignore the uds settings
|
311
|
-
def mixed_http_and_uds?
|
312
|
-
return @mixed_http_and_uds if defined?(@mixed_http_and_uds)
|
313
|
-
|
314
|
-
@mixed_http_and_uds = (configured_hostname || configured_port) && can_use_uds?
|
315
|
-
|
316
|
-
if @mixed_http_and_uds
|
317
|
-
warn_if_configuration_mismatch(
|
318
|
-
[
|
319
|
-
DetectedConfiguration.new(
|
320
|
-
friendly_name: 'configuration of hostname/port for http/https use',
|
321
|
-
value: "hostname: '#{hostname}', port: '#{port}'",
|
322
|
-
),
|
323
|
-
DetectedConfiguration.new(
|
324
|
-
friendly_name: 'configuration for unix domain socket',
|
325
|
-
value: parsed_url.to_s,
|
326
|
-
),
|
327
|
-
]
|
328
|
-
)
|
329
|
-
end
|
330
|
-
|
331
|
-
@mixed_http_and_uds
|
332
|
-
end
|
333
|
-
|
334
335
|
# Represents a given configuration value and where we got it from
|
335
336
|
class DetectedConfiguration
|
336
337
|
attr_reader :friendly_name, :value
|
@@ -94,7 +94,9 @@ module Datadog
|
|
94
94
|
# the Core resolver from within your product/component's namespace.
|
95
95
|
agent_settings = AgentSettingsResolver.call(settings, logger: @logger)
|
96
96
|
|
97
|
-
@
|
97
|
+
@telemetry = self.class.build_telemetry(settings, agent_settings, @logger)
|
98
|
+
|
99
|
+
@remote = Remote::Component.build(settings, agent_settings, telemetry: telemetry)
|
98
100
|
@tracer = self.class.build_tracer(settings, agent_settings, logger: @logger)
|
99
101
|
@crashtracker = self.class.build_crashtracker(settings, agent_settings, logger: @logger)
|
100
102
|
|
@@ -107,8 +109,7 @@ module Datadog
|
|
107
109
|
|
108
110
|
@runtime_metrics = self.class.build_runtime_metrics_worker(settings)
|
109
111
|
@health_metrics = self.class.build_health_metrics(settings)
|
110
|
-
@
|
111
|
-
@appsec = Datadog::AppSec::Component.build_appsec_component(settings)
|
112
|
+
@appsec = Datadog::AppSec::Component.build_appsec_component(settings, telemetry: telemetry)
|
112
113
|
|
113
114
|
self.class.configure_tracing(settings)
|
114
115
|
end
|
@@ -410,10 +410,8 @@ module Datadog
|
|
410
410
|
# The profiler gathers data by sending `SIGPROF` unix signals to Ruby application threads.
|
411
411
|
#
|
412
412
|
# We've discovered that this can trigger a bug in a number of Ruby APIs in the `Dir` class, as
|
413
|
-
# described in https://
|
414
|
-
#
|
415
|
-
#
|
416
|
-
# (In the future, once a fix lands upstream, we'll disable this workaround for Rubies that don't need it)
|
413
|
+
# described in https://bugs.ruby-lang.org/issues/20586 .
|
414
|
+
# This was fixed for Ruby 3.4+, and this setting is a no-op for those versions.
|
417
415
|
#
|
418
416
|
# @default `DD_PROFILING_DIR_INTERRUPTION_WORKAROUND_ENABLED` environment variable as a boolean,
|
419
417
|
# otherwise `true`
|
@@ -462,6 +460,72 @@ module Datadog
|
|
462
460
|
end
|
463
461
|
end
|
464
462
|
end
|
463
|
+
|
464
|
+
# Enables GVL profiling. This will show when threads are waiting for GVL in the timeline view.
|
465
|
+
#
|
466
|
+
# This is a preview feature and disabled by default. It requires Ruby 3.2+.
|
467
|
+
#
|
468
|
+
# @default `DD_PROFILING_PREVIEW_GVL_ENABLED` environment variable as a boolean, otherwise `false`
|
469
|
+
option :preview_gvl_enabled do |o|
|
470
|
+
o.type :bool
|
471
|
+
o.env 'DD_PROFILING_PREVIEW_GVL_ENABLED'
|
472
|
+
o.default false
|
473
|
+
end
|
474
|
+
|
475
|
+
# Controls the smallest time period the profiler will report a thread waiting for the GVL.
|
476
|
+
#
|
477
|
+
# The default value was set to minimize overhead. Periods smaller than the set value will not be reported (e.g.
|
478
|
+
# the thread will be reported as whatever it was doing before it waited for the GVL).
|
479
|
+
#
|
480
|
+
# We do not recommend setting this to less than 1ms. Tweaking this value can increase application latency and
|
481
|
+
# memory use.
|
482
|
+
#
|
483
|
+
# @default 10_000_000 (10ms)
|
484
|
+
option :waiting_for_gvl_threshold_ns do |o|
|
485
|
+
o.type :int
|
486
|
+
o.default 10_000_000
|
487
|
+
end
|
488
|
+
|
489
|
+
# Controls if the profiler should attempt to read context from the otel library
|
490
|
+
#
|
491
|
+
# @default false
|
492
|
+
option :preview_otel_context_enabled do |o|
|
493
|
+
o.env 'DD_PROFILING_PREVIEW_OTEL_CONTEXT_ENABLED'
|
494
|
+
o.default false
|
495
|
+
o.env_parser do |value|
|
496
|
+
if value
|
497
|
+
value = value.strip.downcase
|
498
|
+
if ['only', 'both'].include?(value)
|
499
|
+
value
|
500
|
+
elsif ['true', '1'].include?(value)
|
501
|
+
'both'
|
502
|
+
else
|
503
|
+
'false'
|
504
|
+
end
|
505
|
+
end
|
506
|
+
end
|
507
|
+
o.setter do |value|
|
508
|
+
if value == true
|
509
|
+
:both
|
510
|
+
elsif ['only', 'both', :only, :both].include?(value)
|
511
|
+
value.to_sym
|
512
|
+
else
|
513
|
+
false
|
514
|
+
end
|
515
|
+
end
|
516
|
+
end
|
517
|
+
|
518
|
+
# Controls if the heap profiler should attempt to clean young objects after GC, rather than just at
|
519
|
+
# serialization time. This lowers memory usage and high percentile latency.
|
520
|
+
#
|
521
|
+
# Only takes effect when used together with `gc_enabled: true` and `experimental_heap_enabled: true`.
|
522
|
+
#
|
523
|
+
# @default false
|
524
|
+
option :heap_clean_after_gc_enabled do |o|
|
525
|
+
o.type :bool
|
526
|
+
o.env 'DD_PROFILING_HEAP_CLEAN_AFTER_GC_ENABLED'
|
527
|
+
o.default false
|
528
|
+
end
|
465
529
|
end
|
466
530
|
|
467
531
|
# @public_api
|
@@ -630,6 +694,33 @@ module Datadog
|
|
630
694
|
end
|
631
695
|
end
|
632
696
|
|
697
|
+
# The monotonic clock time provider used by Datadog. This option is internal and is used by `datadog-ci`
|
698
|
+
# gem to avoid traces' durations being skewed by timecop.
|
699
|
+
#
|
700
|
+
# It must respect the interface of [Datadog::Core::Utils::Time#get_time] method.
|
701
|
+
#
|
702
|
+
# For [Timecop](https://rubygems.org/gems/timecop), for example,
|
703
|
+
# `->(unit = :float_second) { ::Process.clock_gettime_without_mock(::Process::CLOCK_MONOTONIC, unit) }`
|
704
|
+
# allows Datadog features to use the real monotonic time when time is frozen with
|
705
|
+
# `Timecop.mock_process_clock = true`.
|
706
|
+
#
|
707
|
+
# @default `->(unit = :float_second) { ::Process.clock_gettime(::Process::CLOCK_MONOTONIC, unit)}`
|
708
|
+
# @return [Proc<Numeric>]
|
709
|
+
option :get_time_provider do |o|
|
710
|
+
o.default_proc { |unit = :float_second| ::Process.clock_gettime(::Process::CLOCK_MONOTONIC, unit) }
|
711
|
+
o.type :proc
|
712
|
+
|
713
|
+
o.after_set do |get_time_provider|
|
714
|
+
Core::Utils::Time.get_time_provider = get_time_provider
|
715
|
+
end
|
716
|
+
|
717
|
+
o.resetter do |_value|
|
718
|
+
->(unit = :float_second) { ::Process.clock_gettime(::Process::CLOCK_MONOTONIC, unit) }.tap do |default|
|
719
|
+
Core::Utils::Time.get_time_provider = default
|
720
|
+
end
|
721
|
+
end
|
722
|
+
end
|
723
|
+
|
633
724
|
# The `version` tag in Datadog. Use it to enable [Deployment Tracking](https://docs.datadoghq.com/tracing/deployment_tracking/).
|
634
725
|
# @see https://docs.datadoghq.com/getting_started/tagging/unified_service_tagging
|
635
726
|
# @default `DD_VERSION` environment variable, otherwise `nils`
|
@@ -836,7 +927,7 @@ module Datadog
|
|
836
927
|
# Enables reporting of information when Ruby VM crashes.
|
837
928
|
option :enabled do |o|
|
838
929
|
o.type :bool
|
839
|
-
o.default
|
930
|
+
o.default false
|
840
931
|
o.env 'DD_CRASHTRACKING_ENABLED'
|
841
932
|
end
|
842
933
|
end
|
@@ -278,9 +278,7 @@ module Datadog
|
|
278
278
|
def handle_interrupt_shutdown!
|
279
279
|
logger = Datadog.logger
|
280
280
|
shutdown_thread = Thread.new { shutdown! }
|
281
|
-
|
282
|
-
shutdown_thread.name = Datadog::Core::Configuration.name
|
283
|
-
end
|
281
|
+
shutdown_thread.name = Datadog::Core::Configuration.name
|
284
282
|
|
285
283
|
print_message_treshold_seconds = 0.2
|
286
284
|
|
@@ -66,7 +66,8 @@ module Datadog
|
|
66
66
|
def start
|
67
67
|
Utils::AtForkMonkeyPatch.apply!
|
68
68
|
|
69
|
-
start_or_update_on_fork(action: :start)
|
69
|
+
start_or_update_on_fork(action: :start, tags: tags)
|
70
|
+
|
70
71
|
ONLY_ONCE.run do
|
71
72
|
Utils::AtForkMonkeyPatch.at_fork(:child) do
|
72
73
|
# Must NOT reference `self` here, as only the first instance will
|
@@ -77,8 +78,10 @@ module Datadog
|
|
77
78
|
end
|
78
79
|
end
|
79
80
|
|
80
|
-
def update_on_fork
|
81
|
-
|
81
|
+
def update_on_fork(settings: Datadog.configuration)
|
82
|
+
# Here we pick up the latest settings, so that we pick up any tags that change after forking
|
83
|
+
# such as the pid or runtime-id
|
84
|
+
start_or_update_on_fork(action: :update_on_fork, tags: TagBuilder.call(settings))
|
82
85
|
end
|
83
86
|
|
84
87
|
def stop
|
@@ -92,16 +95,16 @@ module Datadog
|
|
92
95
|
|
93
96
|
attr_reader :tags, :agent_base_url, :ld_library_path, :path_to_crashtracking_receiver_binary, :logger
|
94
97
|
|
95
|
-
def start_or_update_on_fork(action:)
|
98
|
+
def start_or_update_on_fork(action:, tags:)
|
96
99
|
self.class._native_start_or_update_on_fork(
|
97
100
|
action: action,
|
98
|
-
|
101
|
+
agent_base_url: agent_base_url,
|
99
102
|
path_to_crashtracking_receiver_binary: path_to_crashtracking_receiver_binary,
|
100
103
|
ld_library_path: ld_library_path,
|
101
104
|
tags_as_array: tags.to_a,
|
102
105
|
upload_timeout_seconds: 1
|
103
106
|
)
|
104
|
-
logger.debug("Crash tracking #{action}
|
107
|
+
logger.debug("Crash tracking action: #{action} successful")
|
105
108
|
rescue => e
|
106
109
|
logger.error("Failed to #{action} crash tracking: #{e.message}")
|
107
110
|
end
|
@@ -25,9 +25,9 @@ module Datadog
|
|
25
25
|
# 2. Checking if `Net::HTTP` is referring to the original one
|
26
26
|
# => ::Net::HTTP.equal?(::WebMock::HttpLibAdapters::NetHttpAdapter::OriginalNetHTTP)
|
27
27
|
def webmock_enabled?
|
28
|
-
defined?(::WebMock::HttpLibAdapters::NetHttpAdapter) &&
|
28
|
+
!!(defined?(::WebMock::HttpLibAdapters::NetHttpAdapter) &&
|
29
29
|
defined?(::Net::HTTP) &&
|
30
|
-
::Net::HTTP.equal?(::WebMock::HttpLibAdapters::NetHttpAdapter.instance_variable_get(:@webMockNetHTTP))
|
30
|
+
::Net::HTTP.equal?(::WebMock::HttpLibAdapters::NetHttpAdapter.instance_variable_get(:@webMockNetHTTP)))
|
31
31
|
end
|
32
32
|
|
33
33
|
private
|
@@ -68,7 +68,7 @@ module Datadog
|
|
68
68
|
|
69
69
|
# Check if we are running from `bin/cucumber` or `cucumber/rake/task`.
|
70
70
|
def cucumber?
|
71
|
-
defined?(::Cucumber::Cli)
|
71
|
+
!!defined?(::Cucumber::Cli)
|
72
72
|
end
|
73
73
|
|
74
74
|
# If this is a Rails application, use different heuristics to detect
|
@@ -80,7 +80,7 @@ module Datadog
|
|
80
80
|
# detecting its presence is enough to deduct if this is a development environment.
|
81
81
|
#
|
82
82
|
# @see https://github.com/rails/spring/blob/48b299348ace2188444489a0c216a6f3e9687281/README.md?plain=1#L204-L207
|
83
|
-
defined?(::Spring) || rails_env_development?
|
83
|
+
!!defined?(::Spring) || rails_env_development?
|
84
84
|
end
|
85
85
|
|
86
86
|
RAILS_ENV_DEVELOPMENT = Set['development', 'test'].freeze
|
@@ -94,7 +94,7 @@ module Datadog
|
|
94
94
|
# it's common to have a custom "staging" environment, and such environment normally want to run as close
|
95
95
|
# to production as possible.
|
96
96
|
def rails_env_development?
|
97
|
-
defined?(::Rails.env) && RAILS_ENV_DEVELOPMENT.include?(::Rails.env)
|
97
|
+
!!defined?(::Rails.env) && RAILS_ENV_DEVELOPMENT.include?(::Rails.env)
|
98
98
|
end
|
99
99
|
end
|
100
100
|
end
|
@@ -52,6 +52,11 @@ module Datadog
|
|
52
52
|
::RubyVM::YJIT.runtime_stats[:yjit_alloc_size]
|
53
53
|
end
|
54
54
|
|
55
|
+
# Ratio of YJIT-executed instructions
|
56
|
+
def ratio_in_yjit
|
57
|
+
::RubyVM::YJIT.runtime_stats[:ratio_in_yjit]
|
58
|
+
end
|
59
|
+
|
55
60
|
def available?
|
56
61
|
defined?(::RubyVM::YJIT) \
|
57
62
|
&& ::RubyVM::YJIT.enabled? \
|
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
require_relative '../utils/time'
|
4
4
|
require_relative '../utils/only_once'
|
5
|
+
require_relative '../telemetry/logger'
|
5
6
|
require_relative '../configuration/ext'
|
6
7
|
|
7
8
|
require_relative 'ext'
|
@@ -100,6 +101,7 @@ module Datadog
|
|
100
101
|
Datadog.logger.error(
|
101
102
|
"Failed to send count stat. Cause: #{e.class.name} #{e.message} Source: #{Array(e.backtrace).first}"
|
102
103
|
)
|
104
|
+
Telemetry::Logger.report(e, description: 'Failed to send count stat')
|
103
105
|
end
|
104
106
|
|
105
107
|
def distribution(stat, value = nil, options = nil, &block)
|
@@ -113,6 +115,7 @@ module Datadog
|
|
113
115
|
Datadog.logger.error(
|
114
116
|
"Failed to send distribution stat. Cause: #{e.class.name} #{e.message} Source: #{Array(e.backtrace).first}"
|
115
117
|
)
|
118
|
+
Telemetry::Logger.report(e, description: 'Failed to send distribution stat')
|
116
119
|
end
|
117
120
|
|
118
121
|
def increment(stat, options = nil)
|
@@ -125,6 +128,7 @@ module Datadog
|
|
125
128
|
Datadog.logger.error(
|
126
129
|
"Failed to send increment stat. Cause: #{e.class.name} #{e.message} Source: #{Array(e.backtrace).first}"
|
127
130
|
)
|
131
|
+
Telemetry::Logger.report(e, description: 'Failed to send increment stat')
|
128
132
|
end
|
129
133
|
|
130
134
|
def gauge(stat, value = nil, options = nil, &block)
|
@@ -138,6 +142,7 @@ module Datadog
|
|
138
142
|
Datadog.logger.error(
|
139
143
|
"Failed to send gauge stat. Cause: #{e.class.name} #{e.message} Source: #{Array(e.backtrace).first}"
|
140
144
|
)
|
145
|
+
Telemetry::Logger.report(e, description: 'Failed to send gauge stat')
|
141
146
|
end
|
142
147
|
|
143
148
|
def time(stat, options = nil)
|
@@ -153,9 +158,11 @@ module Datadog
|
|
153
158
|
distribution(stat, ((finished - start) * 1000), options)
|
154
159
|
end
|
155
160
|
rescue StandardError => e
|
161
|
+
# TODO: Likely to be redundant, since `distribution` handles its own errors.
|
156
162
|
Datadog.logger.error(
|
157
163
|
"Failed to send time stat. Cause: #{e.class.name} #{e.message} Source: #{Array(e.backtrace).first}"
|
158
164
|
)
|
165
|
+
Telemetry::Logger.report(e, description: 'Failed to send time stat')
|
159
166
|
end
|
160
167
|
end
|
161
168
|
|