datadog 2.30.0 → 2.31.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 +44 -1
- data/ext/datadog_profiling_native_extension/datadog_ruby_common.c +18 -0
- data/ext/datadog_profiling_native_extension/datadog_ruby_common.h +10 -0
- data/ext/datadog_profiling_native_extension/extconf.rb +2 -0
- data/ext/libdatadog_api/crashtracker.c +5 -8
- data/ext/libdatadog_api/datadog_ruby_common.c +18 -0
- data/ext/libdatadog_api/datadog_ruby_common.h +10 -0
- data/ext/libdatadog_api/di.c +79 -0
- data/ext/libdatadog_api/extconf.rb +2 -0
- data/ext/libdatadog_api/init.c +5 -2
- data/ext/libdatadog_extconf_helpers.rb +9 -1
- data/lib/datadog/ai_guard/component.rb +2 -0
- data/lib/datadog/ai_guard/contrib/ruby_llm/chat_instrumentation.rb +41 -3
- data/lib/datadog/ai_guard/evaluation/content_builder.rb +31 -0
- data/lib/datadog/ai_guard/evaluation/content_part.rb +36 -0
- data/lib/datadog/ai_guard/evaluation/no_op_result.rb +3 -1
- data/lib/datadog/ai_guard/evaluation/request.rb +14 -9
- data/lib/datadog/ai_guard/evaluation/result.rb +3 -1
- data/lib/datadog/ai_guard/evaluation.rb +36 -7
- data/lib/datadog/ai_guard.rb +26 -8
- data/lib/datadog/appsec/autoload.rb +1 -1
- data/lib/datadog/appsec/component.rb +11 -7
- data/lib/datadog/appsec/contrib/rack/gateway/request.rb +1 -1
- data/lib/datadog/appsec/contrib/rack/gateway/watcher.rb +6 -7
- data/lib/datadog/appsec/contrib/rails/patcher.rb +2 -2
- data/lib/datadog/appsec/instrumentation/gateway.rb +0 -13
- data/lib/datadog/appsec/monitor/gateway/watcher.rb +2 -0
- data/lib/datadog/appsec/utils/http/media_type.rb +1 -2
- data/lib/datadog/appsec/utils/http/url_encoded.rb +2 -2
- data/lib/datadog/appsec.rb +5 -9
- data/lib/datadog/core/configuration/base.rb +17 -5
- data/lib/datadog/core/configuration/components.rb +21 -8
- data/lib/datadog/core/configuration/config_helper.rb +9 -0
- data/lib/datadog/core/configuration/option.rb +30 -5
- data/lib/datadog/core/configuration/option_definition.rb +38 -12
- data/lib/datadog/core/configuration/options.rb +40 -6
- data/lib/datadog/core/configuration/settings.rb +15 -0
- data/lib/datadog/core/configuration/supported_configurations.rb +1 -0
- data/lib/datadog/core/contrib/rails/railtie.rb +32 -0
- data/lib/datadog/core/contrib/rails/utils.rb +7 -3
- data/lib/datadog/core/crashtracking/component.rb +3 -3
- data/lib/datadog/core/environment/container.rb +2 -2
- data/lib/datadog/core/environment/ext.rb +1 -0
- data/lib/datadog/core/environment/identity.rb +25 -3
- data/lib/datadog/core/environment/process.rb +12 -0
- data/lib/datadog/core/metrics/client.rb +5 -5
- data/lib/datadog/core/remote/component.rb +38 -21
- data/lib/datadog/core/runtime/metrics.rb +1 -1
- data/lib/datadog/core/telemetry/component.rb +3 -0
- data/lib/datadog/core/telemetry/event/app_client_configuration_change.rb +2 -3
- data/lib/datadog/core/telemetry/event/app_extended_heartbeat.rb +32 -0
- data/lib/datadog/core/telemetry/event/app_started.rb +151 -169
- data/lib/datadog/core/telemetry/event.rb +1 -7
- data/lib/datadog/core/telemetry/ext.rb +1 -0
- data/lib/datadog/core/telemetry/transport/http/telemetry.rb +5 -0
- data/lib/datadog/core/telemetry/worker.rb +20 -0
- data/lib/datadog/core/utils/only_once.rb +1 -1
- data/lib/datadog/core/utils/spawn_monkey_patch.rb +36 -0
- data/lib/datadog/core/workers/async.rb +1 -1
- data/lib/datadog/core.rb +0 -1
- data/lib/datadog/data_streams/pathway_context.rb +1 -1
- data/lib/datadog/di/boot.rb +2 -4
- data/lib/datadog/di/component.rb +4 -0
- data/lib/datadog/di/instrumenter.rb +10 -4
- data/lib/datadog/di/probe_notification_builder.rb +109 -1
- data/lib/datadog/di/serializer.rb +1 -1
- data/lib/datadog/di.rb +81 -0
- data/lib/datadog/kit/enable_core_dumps.rb +1 -1
- data/lib/datadog/open_feature/evaluation_engine.rb +1 -1
- data/lib/datadog/open_feature/exposures/reporter.rb +1 -1
- data/lib/datadog/open_feature/exposures/worker.rb +1 -1
- data/lib/datadog/open_feature/remote.rb +1 -1
- data/lib/datadog/open_feature/transport.rb +1 -1
- data/lib/datadog/opentelemetry/configuration/settings.rb +2 -0
- data/lib/datadog/profiling/collectors/code_provenance.rb +2 -3
- data/lib/datadog/profiling/collectors/cpu_and_wall_time_worker.rb +1 -1
- data/lib/datadog/profiling/collectors/idle_sampling_helper.rb +1 -1
- data/lib/datadog/profiling/component.rb +11 -1
- data/lib/datadog/profiling/load_native_extension.rb +1 -1
- data/lib/datadog/profiling/profiler.rb +0 -4
- data/lib/datadog/profiling/scheduler.rb +2 -2
- data/lib/datadog/profiling/tasks/exec.rb +2 -2
- data/lib/datadog/profiling/tasks/setup.rb +2 -2
- data/lib/datadog/profiling.rb +1 -2
- data/lib/datadog/single_step_instrument.rb +1 -1
- data/lib/datadog/tracing/buffer.rb +3 -3
- data/lib/datadog/tracing/component.rb +11 -0
- data/lib/datadog/tracing/configuration/settings.rb +2 -1
- data/lib/datadog/tracing/contrib/action_pack/action_controller/instrumentation.rb +2 -2
- data/lib/datadog/tracing/contrib/action_pack/action_dispatch/instrumentation.rb +20 -0
- data/lib/datadog/tracing/contrib/action_pack/action_dispatch/patcher.rb +3 -1
- data/lib/datadog/tracing/contrib/action_view/events/render_template.rb +1 -1
- data/lib/datadog/tracing/contrib/active_job/events/discard.rb +1 -1
- data/lib/datadog/tracing/contrib/active_job/events/enqueue.rb +1 -1
- data/lib/datadog/tracing/contrib/active_job/events/enqueue_at.rb +1 -1
- data/lib/datadog/tracing/contrib/active_job/events/enqueue_retry.rb +1 -1
- data/lib/datadog/tracing/contrib/active_job/events/perform.rb +1 -1
- data/lib/datadog/tracing/contrib/active_job/events/retry_stopped.rb +1 -1
- data/lib/datadog/tracing/contrib/active_model_serializers/events/render.rb +1 -1
- data/lib/datadog/tracing/contrib/active_model_serializers/events/serialize.rb +1 -1
- data/lib/datadog/tracing/contrib/active_record/events/instantiation.rb +1 -1
- data/lib/datadog/tracing/contrib/active_record/events/sql.rb +1 -1
- data/lib/datadog/tracing/contrib/active_record/utils.rb +1 -1
- data/lib/datadog/tracing/contrib/active_support/cache/events/cache.rb +1 -1
- data/lib/datadog/tracing/contrib/active_support/notifications/subscription.rb +2 -2
- data/lib/datadog/tracing/contrib/aws/instrumentation.rb +1 -1
- data/lib/datadog/tracing/contrib/configurable.rb +18 -3
- data/lib/datadog/tracing/contrib/elasticsearch/patcher.rb +1 -1
- data/lib/datadog/tracing/contrib/excon/middleware.rb +2 -2
- data/lib/datadog/tracing/contrib/faraday/middleware.rb +2 -2
- data/lib/datadog/tracing/contrib/grape/endpoint.rb +5 -5
- data/lib/datadog/tracing/contrib/http/instrumentation.rb +1 -1
- data/lib/datadog/tracing/contrib/httprb/instrumentation.rb +1 -1
- data/lib/datadog/tracing/contrib/opensearch/patcher.rb +1 -1
- data/lib/datadog/tracing/contrib/rails/log_injection.rb +1 -1
- data/lib/datadog/tracing/contrib/rails/patcher.rb +0 -1
- data/lib/datadog/tracing/contrib/rails/runner.rb +1 -1
- data/lib/datadog/tracing/contrib/rake/instrumentation.rb +2 -2
- data/lib/datadog/tracing/contrib/redis/tags.rb +1 -1
- data/lib/datadog/tracing/contrib/status_range_matcher.rb +4 -0
- data/lib/datadog/tracing/contrib/stripe/request.rb +1 -1
- data/lib/datadog/tracing/distributed/datadog.rb +4 -2
- data/lib/datadog/tracing/event.rb +1 -1
- data/lib/datadog/tracing/remote.rb +1 -1
- data/lib/datadog/tracing/sampling/ext.rb +2 -0
- data/lib/datadog/tracing/sampling/priority_sampler.rb +13 -0
- data/lib/datadog/tracing/sampling/rule.rb +1 -1
- data/lib/datadog/tracing/sampling/rule_sampler.rb +54 -25
- data/lib/datadog/tracing/sampling/span/rule_parser.rb +1 -1
- data/lib/datadog/tracing/span_operation.rb +1 -1
- data/lib/datadog/tracing/trace_operation.rb +50 -6
- data/lib/datadog/tracing/tracer.rb +25 -0
- data/lib/datadog/tracing/transport/io/client.rb +1 -1
- data/lib/datadog/tracing/transport/trace_formatter.rb +1 -1
- data/lib/datadog/version.rb +1 -1
- metadata +13 -7
data/lib/datadog/ai_guard.rb
CHANGED
|
@@ -10,7 +10,7 @@ module Datadog
|
|
|
10
10
|
module AIGuard
|
|
11
11
|
Core::Configuration::Settings.extend(Configuration::Settings)
|
|
12
12
|
|
|
13
|
-
# This error is raised when
|
|
13
|
+
# This error is raised when `allow_raise` is set to true (the default) in Evaluation.perform
|
|
14
14
|
# and AI Guard considers the messages not safe. Intended to be rescued by the user.
|
|
15
15
|
#
|
|
16
16
|
# WARNING: This name must not change, since front-end is using it.
|
|
@@ -68,13 +68,14 @@ module Datadog
|
|
|
68
68
|
# One or more message objects to be evaluated.
|
|
69
69
|
# @param allow_raise [Boolean]
|
|
70
70
|
# Whether this method may raise an exception when evaluation result is not ALLOW.
|
|
71
|
+
# Defaults to true.
|
|
71
72
|
#
|
|
72
73
|
# @return [Datadog::AIGuard::Evaluation::Result]
|
|
73
74
|
# The result of AI Guard evaluation.
|
|
74
75
|
# @raise [Datadog::AIGuard::AIGuardAbortError]
|
|
75
76
|
# If the evaluation results in DENY or ABORT action and `allow_raise` is set to true
|
|
76
77
|
# @public_api
|
|
77
|
-
def evaluate(*messages, allow_raise:
|
|
78
|
+
def evaluate(*messages, allow_raise: true)
|
|
78
79
|
if enabled?
|
|
79
80
|
Evaluation.perform(messages, allow_raise: allow_raise)
|
|
80
81
|
else
|
|
@@ -84,25 +85,42 @@ module Datadog
|
|
|
84
85
|
|
|
85
86
|
# Builds a generic evaluation message.
|
|
86
87
|
#
|
|
87
|
-
#
|
|
88
|
+
# Accepts either a string content or a block for multi-modal content parts:
|
|
88
89
|
#
|
|
89
90
|
# ```
|
|
91
|
+
# # String content:
|
|
90
92
|
# Datadog::AIGuard.message(role: :user, content: "Hello, assistant")
|
|
93
|
+
#
|
|
94
|
+
# # Multi-modal content with block:
|
|
95
|
+
# Datadog::AIGuard.message(role: :user) do |m|
|
|
96
|
+
# m.text("What's in this image?")
|
|
97
|
+
# m.image_url("https://example.com/img.png")
|
|
98
|
+
# end
|
|
91
99
|
# ```
|
|
92
100
|
#
|
|
93
101
|
# @param role [Symbol]
|
|
94
102
|
# The role associated with the message.
|
|
95
103
|
# Must be one of `:assistant`, `:tool`, `:system`, `:developer`, or `:user`.
|
|
96
|
-
# @param content [String]
|
|
97
|
-
# The textual content of the message.
|
|
104
|
+
# @param content [String, nil]
|
|
105
|
+
# The textual content of the message. Cannot be combined with a block.
|
|
106
|
+
# @yield [builder] A block for building multi-modal content parts.
|
|
107
|
+
# @yieldparam builder [Datadog::AIGuard::Evaluation::ContentBuilder]
|
|
98
108
|
#
|
|
99
109
|
# @return [Datadog::AIGuard::Evaluation::Message]
|
|
100
110
|
# A new message instance with the given role and content.
|
|
101
111
|
# @raise [ArgumentError]
|
|
102
|
-
# If an invalid role is provided.
|
|
112
|
+
# If both content and a block are provided, or if an invalid role is provided.
|
|
103
113
|
# @public_api
|
|
104
|
-
def message(role:, content:)
|
|
105
|
-
|
|
114
|
+
def message(role:, content: nil)
|
|
115
|
+
if block_given?
|
|
116
|
+
raise ArgumentError, "Cannot pass both content and a block" if content
|
|
117
|
+
|
|
118
|
+
builder = Evaluation::ContentBuilder.new
|
|
119
|
+
yield builder
|
|
120
|
+
Evaluation::Message.new(role: role, content: builder.parts)
|
|
121
|
+
else
|
|
122
|
+
Evaluation::Message.new(role: role, content: content)
|
|
123
|
+
end
|
|
106
124
|
end
|
|
107
125
|
|
|
108
126
|
# Builds an assistant message representing a tool call initiated by the model.
|
|
@@ -7,7 +7,7 @@ if %w[1 true].include?((Datadog::DATADOG_ENV['DD_APPSEC_ENABLED'] || '').downcas
|
|
|
7
7
|
rescue => e
|
|
8
8
|
Kernel.warn(
|
|
9
9
|
'[datadog] AppSec failed to instrument. No security check will be performed. error: ' \
|
|
10
|
-
" #{e.class
|
|
10
|
+
" #{e.class}: #{e}"
|
|
11
11
|
)
|
|
12
12
|
end
|
|
13
13
|
end
|
|
@@ -45,10 +45,15 @@ module Datadog
|
|
|
45
45
|
settings.appsec.instrument(:devise) unless devise_integration.patcher.patched?
|
|
46
46
|
|
|
47
47
|
security_engine = SecurityEngine::Engine.new(appsec_settings: settings.appsec, telemetry: telemetry)
|
|
48
|
-
new(security_engine: security_engine
|
|
49
|
-
rescue
|
|
50
|
-
Datadog.logger.warn(
|
|
51
|
-
|
|
48
|
+
new(security_engine: security_engine)
|
|
49
|
+
rescue => e
|
|
50
|
+
Datadog.logger.warn("AppSec is disabled: #{e.class}: #{e}; there may be additional logged errors above")
|
|
51
|
+
|
|
52
|
+
# Not reporting to telemetry here because some of the rescued exceptions
|
|
53
|
+
# have already been reported by the code that raised them
|
|
54
|
+
# (e.g. SecurityEngine::Engine.new reports WAF init failures).
|
|
55
|
+
# TODO: reconsider whether telemetry reporting belongs here
|
|
56
|
+
# (single catch-all) or in the downstream code (as it is now).
|
|
52
57
|
nil
|
|
53
58
|
end
|
|
54
59
|
|
|
@@ -70,11 +75,10 @@ module Datadog
|
|
|
70
75
|
end
|
|
71
76
|
end
|
|
72
77
|
|
|
73
|
-
attr_reader :security_engine
|
|
78
|
+
attr_reader :security_engine
|
|
74
79
|
|
|
75
|
-
def initialize(security_engine
|
|
80
|
+
def initialize(security_engine:)
|
|
76
81
|
@security_engine = security_engine
|
|
77
|
-
@telemetry = telemetry
|
|
78
82
|
end
|
|
79
83
|
|
|
80
84
|
def reconfigure!
|
|
@@ -25,7 +25,7 @@ module Datadog
|
|
|
25
25
|
def query
|
|
26
26
|
::Rack::Utils.parse_query(request.query_string)
|
|
27
27
|
rescue => e
|
|
28
|
-
Datadog.logger.debug { "AppSec: Failed to parse request query string: #{e.class}: #{e
|
|
28
|
+
Datadog.logger.debug { "AppSec: Failed to parse request query string: #{e.class}: #{e}" }
|
|
29
29
|
AppSec.telemetry.report(e, description: 'AppSec: Failed to parse request query string')
|
|
30
30
|
|
|
31
31
|
{}
|
|
@@ -116,17 +116,16 @@ module Datadog
|
|
|
116
116
|
gateway.watch('rack.request.finish') do |stack, gateway_request|
|
|
117
117
|
context = gateway_request.env[AppSec::Ext::CONTEXT_KEY]
|
|
118
118
|
|
|
119
|
-
if context.span.nil?
|
|
120
|
-
next stack.call(gateway_request.request)
|
|
121
|
-
end
|
|
119
|
+
next stack.call(gateway_request.request) if context.span.nil?
|
|
122
120
|
|
|
123
121
|
gateway_request.headers.each do |name, value|
|
|
124
|
-
if
|
|
125
|
-
|
|
126
|
-
next
|
|
122
|
+
if Ext::COLLECTABLE_REQUEST_HEADERS.include?(name)
|
|
123
|
+
context.span["http.request.headers.#{name}"] ||= value
|
|
127
124
|
end
|
|
128
125
|
|
|
129
|
-
context.
|
|
126
|
+
if context.state[:has_identity_event] && Ext::IDENTITY_COLLECTABLE_REQUEST_HEADERS.include?(name)
|
|
127
|
+
context.span["http.request.headers.#{name}"] ||= value
|
|
128
|
+
end
|
|
130
129
|
end
|
|
131
130
|
|
|
132
131
|
stack.call(gateway_request.request)
|
|
@@ -138,7 +138,7 @@ module Datadog
|
|
|
138
138
|
end
|
|
139
139
|
rescue => e
|
|
140
140
|
error_message = 'Failed to get application routes'
|
|
141
|
-
Datadog.logger.error("#{error_message}, #{e.class}: #{e
|
|
141
|
+
Datadog.logger.error("#{error_message}, #{e.class}: #{e}")
|
|
142
142
|
AppSec.telemetry.report(e, description: error_message)
|
|
143
143
|
end
|
|
144
144
|
end
|
|
@@ -148,7 +148,7 @@ module Datadog
|
|
|
148
148
|
Datadog::AppSec::Contrib::Rails::Patcher.report_routes_via_telemetry(::Rails.application.routes.routes)
|
|
149
149
|
rescue => e
|
|
150
150
|
error_message = 'Failed to get application routes'
|
|
151
|
-
Datadog.logger.error("#{error_message}, #{e.class}: #{e
|
|
151
|
+
Datadog.logger.error("#{error_message}, #{e.class}: #{e}")
|
|
152
152
|
AppSec.telemetry.report(e, description: error_message)
|
|
153
153
|
end
|
|
154
154
|
end
|
|
@@ -10,18 +10,9 @@ module Datadog
|
|
|
10
10
|
class Gateway
|
|
11
11
|
def initialize
|
|
12
12
|
@middlewares = Hash.new { |h, k| h[k] = [] }
|
|
13
|
-
@pushed_events = {}
|
|
14
13
|
end
|
|
15
14
|
|
|
16
|
-
# NOTE: Be careful with pushed names because every pushed event name
|
|
17
|
-
# is recorded in order to provide an ability to any subscriber
|
|
18
|
-
# to check wether an arbitrary event had happened.
|
|
19
|
-
#
|
|
20
|
-
# WARNING: If we start pushing generated names we should consider
|
|
21
|
-
# limiting the storage of pushed names.
|
|
22
15
|
def push(name, env, &block)
|
|
23
|
-
@pushed_events[name] = true
|
|
24
|
-
|
|
25
16
|
block ||= -> {}
|
|
26
17
|
middlewares_for_name = @middlewares[name]
|
|
27
18
|
|
|
@@ -44,10 +35,6 @@ module Datadog
|
|
|
44
35
|
def watch(name, &block)
|
|
45
36
|
@middlewares[name] << Middleware.new(&block)
|
|
46
37
|
end
|
|
47
|
-
|
|
48
|
-
def pushed?(name)
|
|
49
|
-
@pushed_events.key?(name)
|
|
50
|
-
end
|
|
51
38
|
end
|
|
52
39
|
|
|
53
40
|
# NOTE: This left as-is and will be depricated soon.
|
|
@@ -26,6 +26,7 @@ module Datadog
|
|
|
26
26
|
def watch_user_id(gateway = Instrumentation.gateway)
|
|
27
27
|
gateway.watch('identity.set_user') do |stack, user|
|
|
28
28
|
context = AppSec.active_context
|
|
29
|
+
context.state[:has_identity_event] = true
|
|
29
30
|
|
|
30
31
|
if user.id.nil? && user.login.nil? && user.session_id.nil?
|
|
31
32
|
Datadog.logger.debug { 'AppSec: skipping WAF check because no user information was provided' }
|
|
@@ -57,6 +58,7 @@ module Datadog
|
|
|
57
58
|
def watch_user_login(gateway = Instrumentation.gateway)
|
|
58
59
|
gateway.watch('appsec.events.user_lifecycle') do |stack, kind|
|
|
59
60
|
context = AppSec.active_context
|
|
61
|
+
context.state[:has_identity_event] = true
|
|
60
62
|
|
|
61
63
|
next stack.call(kind) unless WATCHED_LOGIN_EVENTS.include?(kind)
|
|
62
64
|
|
|
@@ -30,9 +30,9 @@ module Datadog
|
|
|
30
30
|
#
|
|
31
31
|
# @type var key: ::String
|
|
32
32
|
# @type var value: ::String
|
|
33
|
-
key, value = pair.split('=', 2).map! do |value|
|
|
33
|
+
key, value = pair.split('=', 2).map! do |value|
|
|
34
34
|
CGI.unescape(value)
|
|
35
|
-
end
|
|
35
|
+
end #: [::String, ::String]
|
|
36
36
|
|
|
37
37
|
if (stored = memo[key])
|
|
38
38
|
if stored.is_a?(Array)
|
data/lib/datadog/appsec.rb
CHANGED
|
@@ -11,25 +11,21 @@ module Datadog
|
|
|
11
11
|
module AppSec
|
|
12
12
|
class << self
|
|
13
13
|
def enabled?
|
|
14
|
-
|
|
14
|
+
!!components.appsec
|
|
15
15
|
end
|
|
16
16
|
|
|
17
17
|
def rasp_enabled?
|
|
18
|
-
|
|
18
|
+
# TODO this should take rasp_enabled flag from the settings in
|
|
19
|
+
# the appsec component rather than reading global configuration.
|
|
20
|
+
enabled? && Datadog.configuration.appsec.rasp_enabled
|
|
19
21
|
end
|
|
20
22
|
|
|
21
23
|
def active_context
|
|
22
24
|
Datadog::AppSec::Context.active
|
|
23
25
|
end
|
|
24
26
|
|
|
25
|
-
# NOTE: This is a temporary workaround for type checking.
|
|
26
|
-
#
|
|
27
|
-
# We want to move from possible nil-component to the disabled-component
|
|
28
|
-
# on an initialization error. Technically, telemetry will be never
|
|
29
|
-
# used if AppSec was not able to initialize, so it's safe to assume
|
|
30
|
-
# that telemetry will never be used and will be nil at the same time.
|
|
31
27
|
def telemetry
|
|
32
|
-
components.
|
|
28
|
+
components.telemetry
|
|
33
29
|
end
|
|
34
30
|
|
|
35
31
|
def security_engine
|
|
@@ -24,9 +24,21 @@ module Datadog
|
|
|
24
24
|
# e.g. `settings :foo { option :bar }` --> `config.foo.bar`
|
|
25
25
|
# @param [Symbol] name option name. Methods will be created based on this name.
|
|
26
26
|
def settings(name, &block)
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
27
|
+
nested_settings_path = settings_path ? "#{settings_path}.#{name}" : name.to_s
|
|
28
|
+
settings_class = new_settings_class(name, nested_settings_path, &block)
|
|
29
|
+
# Record the child settings class on the owning class so
|
|
30
|
+
# Options::ClassMethods#settings_path= can later propagate any path
|
|
31
|
+
# changes down to nested settings classes.
|
|
32
|
+
#
|
|
33
|
+
# Example:
|
|
34
|
+
# settings :cache_key { option :enabled }
|
|
35
|
+
# creates a child class whose initial settings_path is "cache_key".
|
|
36
|
+
# If a contrib integration later assigns the parent path to
|
|
37
|
+
# "tracing.active_support", settings_children lets us update the
|
|
38
|
+
# nested class to "tracing.active_support.cache_key" as well.
|
|
39
|
+
settings_children[name] = settings_class
|
|
40
|
+
|
|
41
|
+
option(name, is_settings: true) do |o|
|
|
30
42
|
o.default { settings_class.new }
|
|
31
43
|
|
|
32
44
|
o.resetter do |value|
|
|
@@ -40,9 +52,9 @@ module Datadog
|
|
|
40
52
|
|
|
41
53
|
private
|
|
42
54
|
|
|
43
|
-
def new_settings_class(name, &block)
|
|
55
|
+
def new_settings_class(name, settings_path, &block)
|
|
44
56
|
Class.new { include Configuration::Base }.tap do |klass|
|
|
45
|
-
klass.instance_variable_set(:@
|
|
57
|
+
klass.instance_variable_set(:@settings_path, settings_path)
|
|
46
58
|
klass.instance_eval(&block) if block
|
|
47
59
|
end
|
|
48
60
|
end
|
|
@@ -12,6 +12,7 @@ require_relative '../telemetry/component'
|
|
|
12
12
|
require_relative '../workers/runtime_metrics'
|
|
13
13
|
require_relative '../remote/component'
|
|
14
14
|
require_relative '../utils/at_fork_monkey_patch'
|
|
15
|
+
require_relative '../utils/spawn_monkey_patch'
|
|
15
16
|
require_relative '../utils/only_once'
|
|
16
17
|
require_relative '../../tracing/component'
|
|
17
18
|
require_relative '../../profiling/component'
|
|
@@ -22,6 +23,7 @@ require_relative '../../open_feature/component'
|
|
|
22
23
|
require_relative '../../error_tracking/component'
|
|
23
24
|
require_relative '../crashtracking/component'
|
|
24
25
|
require_relative '../environment/agent_info'
|
|
26
|
+
require_relative '../environment/identity'
|
|
25
27
|
require_relative '../process_discovery'
|
|
26
28
|
require_relative '../../data_streams/processor'
|
|
27
29
|
|
|
@@ -31,7 +33,7 @@ module Datadog
|
|
|
31
33
|
# Global components for the trace library.
|
|
32
34
|
class Components
|
|
33
35
|
# Class-level constant to ensure fork patch is applied only once
|
|
34
|
-
|
|
36
|
+
PATCH_ONLY_ONCE = Utils::OnlyOnce.new
|
|
35
37
|
|
|
36
38
|
class << self
|
|
37
39
|
def build_health_metrics(settings, logger, telemetry)
|
|
@@ -128,8 +130,11 @@ module Datadog
|
|
|
128
130
|
Deprecations.log_deprecations_from_all_sources(@logger)
|
|
129
131
|
|
|
130
132
|
# Register fork handling once globally
|
|
131
|
-
self.class::
|
|
133
|
+
self.class::PATCH_ONLY_ONCE.run do
|
|
132
134
|
Utils::AtForkMonkeyPatch.apply!
|
|
135
|
+
Utils::SpawnMonkeyPatch.apply!(
|
|
136
|
+
lineage_envs_provider: Core::Environment::Identity.method(:runtime_propagation_envs),
|
|
137
|
+
)
|
|
133
138
|
|
|
134
139
|
# Register callback that calls Components.after_fork
|
|
135
140
|
Utils::AtForkMonkeyPatch.at_fork(:child) do
|
|
@@ -172,6 +177,11 @@ module Datadog
|
|
|
172
177
|
|
|
173
178
|
# Configure non-privileged components.
|
|
174
179
|
Datadog::Tracing::Contrib::Component.configure(settings)
|
|
180
|
+
|
|
181
|
+
# Load the core Rails Railtie when Rails is present so all products benefit from Rails-specific setup.
|
|
182
|
+
if defined?(::Rails::Railtie)
|
|
183
|
+
require_relative '../contrib/rails/railtie'
|
|
184
|
+
end
|
|
175
185
|
end
|
|
176
186
|
|
|
177
187
|
# Called when a fork is detected
|
|
@@ -204,14 +214,13 @@ module Datadog
|
|
|
204
214
|
end
|
|
205
215
|
end
|
|
206
216
|
|
|
207
|
-
if
|
|
217
|
+
if remote && old_state&.remote_started?
|
|
208
218
|
# The library was reconfigured and previously it already started
|
|
209
219
|
# the remote component (i.e., it received at least one request
|
|
210
220
|
# through the installed Rack middleware which started the remote).
|
|
211
221
|
# If the new configuration also has remote enabled, start the
|
|
212
222
|
# new remote right away.
|
|
213
|
-
|
|
214
|
-
remote&.start
|
|
223
|
+
remote.start
|
|
215
224
|
end
|
|
216
225
|
|
|
217
226
|
# This should stay here, not in initialize. During reconfiguration, the order of the calls is:
|
|
@@ -279,11 +288,15 @@ module Datadog
|
|
|
279
288
|
unused_statsd = (old_statsd - (old_statsd & new_statsd))
|
|
280
289
|
unused_statsd.each(&:close)
|
|
281
290
|
|
|
282
|
-
|
|
291
|
+
Core::ProcessDiscovery.shutdown!
|
|
292
|
+
|
|
293
|
+
# Shut down telemetry last so that all other components may
|
|
294
|
+
# report shutdown errors.
|
|
295
|
+
#
|
|
296
|
+
# Enqueue closing event before stopping telemetry so it will be
|
|
297
|
+
# sent out on shutdown.
|
|
283
298
|
telemetry.emit_closing! unless replacement&.telemetry&.enabled
|
|
284
299
|
telemetry.shutdown!
|
|
285
|
-
|
|
286
|
-
Core::ProcessDiscovery.shutdown!
|
|
287
300
|
end
|
|
288
301
|
|
|
289
302
|
# Returns the current state of various components.
|
|
@@ -40,6 +40,12 @@ module Datadog
|
|
|
40
40
|
!get_environment_variable(name).nil?
|
|
41
41
|
end
|
|
42
42
|
|
|
43
|
+
# Returns the source environment as a Hash. Used when the full environment
|
|
44
|
+
# must be passed through (e.g. Process.spawn child env).
|
|
45
|
+
def to_h
|
|
46
|
+
@source_env.to_h
|
|
47
|
+
end
|
|
48
|
+
|
|
43
49
|
alias_method :has_key?, :key?
|
|
44
50
|
alias_method :include?, :key?
|
|
45
51
|
alias_method :member?, :key?
|
|
@@ -97,4 +103,7 @@ module Datadog
|
|
|
97
103
|
end
|
|
98
104
|
end
|
|
99
105
|
end
|
|
106
|
+
unless const_defined?(:DATADOG_ENV, false)
|
|
107
|
+
DATADOG_ENV = Core::Configuration::ConfigHelper.new
|
|
108
|
+
end
|
|
100
109
|
end
|
|
@@ -77,6 +77,16 @@ module Datadog
|
|
|
77
77
|
@precedence_set = Precedence::DEFAULT
|
|
78
78
|
end
|
|
79
79
|
|
|
80
|
+
# Computes the name of the option with the settings path.
|
|
81
|
+
# E.g. "tracing.rails.middleware_names" for the "middleware_names" option in the "tracing.rails" settings.
|
|
82
|
+
# @return [String] the name of the option with the settings path
|
|
83
|
+
def name_with_settings_path
|
|
84
|
+
@name_with_settings_path ||= begin
|
|
85
|
+
settings_path = @context.class.settings_path
|
|
86
|
+
settings_path.nil? ? definition.name.to_s : "#{settings_path}.#{definition.name}"
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
|
|
80
90
|
# Overrides the current value for this option if the `precedence` is equal or higher than
|
|
81
91
|
# the previously set value.
|
|
82
92
|
# The first call to `#set` will always store the value regardless of precedence.
|
|
@@ -89,7 +99,7 @@ module Datadog
|
|
|
89
99
|
# This should be uncommon, as higher precedence values tend to
|
|
90
100
|
# happen later in the application lifecycle.
|
|
91
101
|
Datadog.logger.info do
|
|
92
|
-
"Option '#{
|
|
102
|
+
"Option '#{name_with_settings_path}' not changed to '#{value}' (precedence: #{precedence.name}) because the higher " \
|
|
93
103
|
"precedence value '#{@value}' (precedence: #{@precedence_set.name}) was already set."
|
|
94
104
|
end
|
|
95
105
|
|
|
@@ -178,6 +188,21 @@ module Datadog
|
|
|
178
188
|
precedence_set == Precedence::DEFAULT
|
|
179
189
|
end
|
|
180
190
|
|
|
191
|
+
def settings?
|
|
192
|
+
@definition.is_settings
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
def values_per_precedence
|
|
196
|
+
# value_per_precedence is only filled after we call `get` once.
|
|
197
|
+
get unless @is_set
|
|
198
|
+
|
|
199
|
+
@value_per_precedence.each_with_object({}) do |(precedence, value), result|
|
|
200
|
+
next if value.equal?(UNSET)
|
|
201
|
+
|
|
202
|
+
result[precedence] = value
|
|
203
|
+
end
|
|
204
|
+
end
|
|
205
|
+
|
|
181
206
|
private
|
|
182
207
|
|
|
183
208
|
def coerce_env_variable(value)
|
|
@@ -216,7 +241,7 @@ module Datadog
|
|
|
216
241
|
value
|
|
217
242
|
else
|
|
218
243
|
raise InvalidDefinitionError,
|
|
219
|
-
"The option #{
|
|
244
|
+
"The option #{name_with_settings_path} is using an unsupported type option for env coercion `#{@definition.type}`"
|
|
220
245
|
end
|
|
221
246
|
end
|
|
222
247
|
|
|
@@ -239,10 +264,10 @@ module Datadog
|
|
|
239
264
|
|
|
240
265
|
if raise_error
|
|
241
266
|
error_msg = if @definition.type_options[:nilable]
|
|
242
|
-
"The setting `#{
|
|
267
|
+
"The setting `#{name_with_settings_path}` inside your app's `Datadog.configure` block expects a " \
|
|
243
268
|
"#{@definition.type} or `nil`, but a `#{value.class}` was provided (#{value.inspect})." \
|
|
244
269
|
else
|
|
245
|
-
"The setting `#{
|
|
270
|
+
"The setting `#{name_with_settings_path}` inside your app's `Datadog.configure` block expects a " \
|
|
246
271
|
"#{@definition.type}, but a `#{value.class}` was provided (#{value.inspect})." \
|
|
247
272
|
end
|
|
248
273
|
|
|
@@ -276,7 +301,7 @@ module Datadog
|
|
|
276
301
|
true # No validation is performed when option is typeless
|
|
277
302
|
else
|
|
278
303
|
raise InvalidDefinitionError,
|
|
279
|
-
"The option #{
|
|
304
|
+
"The option #{name_with_settings_path} is using an unsupported type option `#{@definition.type}`"
|
|
280
305
|
end
|
|
281
306
|
end
|
|
282
307
|
|
|
@@ -10,28 +10,36 @@ module Datadog
|
|
|
10
10
|
IDENTITY = ->(new_value, _old_value) { new_value }
|
|
11
11
|
|
|
12
12
|
attr_reader \
|
|
13
|
+
:is_settings,
|
|
13
14
|
:default,
|
|
14
15
|
:default_proc,
|
|
15
16
|
:env,
|
|
16
17
|
:env_parser,
|
|
17
18
|
:name,
|
|
18
19
|
:after_set,
|
|
20
|
+
:skip_telemetry,
|
|
19
21
|
:resetter,
|
|
20
22
|
:setter,
|
|
21
23
|
:type,
|
|
22
24
|
:type_options
|
|
23
25
|
|
|
24
|
-
def initialize(name,
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
@
|
|
26
|
+
def initialize(name, attributes, &block)
|
|
27
|
+
# When a settings is defined using the config DSL, an option is also created.
|
|
28
|
+
# See Datadog::Core::Configuration::Base::ClassMethods#settings for more details.
|
|
29
|
+
# This flag is used to indicate that the option is a settings option.
|
|
30
|
+
@is_settings = attributes[:is_settings]
|
|
31
|
+
|
|
32
|
+
@default = attributes[:default]
|
|
33
|
+
@default_proc = attributes[:default_proc]
|
|
34
|
+
@env = attributes[:env]
|
|
35
|
+
@env_parser = attributes[:env_parser]
|
|
29
36
|
@name = name.to_sym
|
|
30
|
-
@after_set =
|
|
31
|
-
@
|
|
32
|
-
@
|
|
33
|
-
@
|
|
34
|
-
@
|
|
37
|
+
@after_set = attributes[:after_set]
|
|
38
|
+
@skip_telemetry = attributes[:skip_telemetry]
|
|
39
|
+
@resetter = attributes[:resetter]
|
|
40
|
+
@setter = attributes[:setter] || block || IDENTITY
|
|
41
|
+
@type = attributes[:type]
|
|
42
|
+
@type_options = attributes[:type_options]
|
|
35
43
|
end
|
|
36
44
|
|
|
37
45
|
# Creates a new Option, bound to the context provided.
|
|
@@ -49,6 +57,8 @@ module Datadog
|
|
|
49
57
|
:helpers
|
|
50
58
|
|
|
51
59
|
def initialize(name, options = {})
|
|
60
|
+
@is_settings = options.fetch(:is_settings, false)
|
|
61
|
+
|
|
52
62
|
@env = nil
|
|
53
63
|
@env_parser = nil
|
|
54
64
|
@default = nil
|
|
@@ -56,6 +66,7 @@ module Datadog
|
|
|
56
66
|
@helpers = {}
|
|
57
67
|
@name = name.to_sym
|
|
58
68
|
@after_set = nil
|
|
69
|
+
@skip_telemetry = false
|
|
59
70
|
@resetter = nil
|
|
60
71
|
@setter = OptionDefinition::IDENTITY
|
|
61
72
|
@type = nil
|
|
@@ -95,6 +106,16 @@ module Datadog
|
|
|
95
106
|
@after_set = block
|
|
96
107
|
end
|
|
97
108
|
|
|
109
|
+
# This should only be set to true for options that are manually modified
|
|
110
|
+
# before being added to the telemetry payload in app_started.rb.
|
|
111
|
+
# E.g. telemetry is skipped for `tracing.writer_options`, but in app_started.rb,
|
|
112
|
+
# we send two separate entries for the buffer_size and flush_interval values.
|
|
113
|
+
# Standard: We want to keep this method as skip_telemetry(value),
|
|
114
|
+
# not skip_telemetry = value, so attr_writer is not used.
|
|
115
|
+
def skip_telemetry(value) # standard:disable Style/TrivialAccessors
|
|
116
|
+
@skip_telemetry = value
|
|
117
|
+
end
|
|
118
|
+
|
|
98
119
|
def resetter(&block)
|
|
99
120
|
@resetter = block
|
|
100
121
|
end
|
|
@@ -119,6 +140,8 @@ module Datadog
|
|
|
119
140
|
env(options[:env]) if options.key?(:env)
|
|
120
141
|
env_parser(&options[:env_parser]) if options.key?(:env_parser)
|
|
121
142
|
after_set(&options[:after_set]) if options.key?(:after_set)
|
|
143
|
+
# Steep: https://github.com/soutaro/steep/issues/1979
|
|
144
|
+
skip_telemetry(options[:skip_telemetry]) if options.key?(:skip_telemetry) # steep:ignore ArgumentTypeMismatch
|
|
122
145
|
resetter(&options[:resetter]) if options.key?(:resetter)
|
|
123
146
|
# Steep: https://github.com/soutaro/steep/issues/1979
|
|
124
147
|
setter(&options[:setter]) if options.key?(:setter) # steep:ignore BlockTypeMismatch
|
|
@@ -126,16 +149,19 @@ module Datadog
|
|
|
126
149
|
end
|
|
127
150
|
|
|
128
151
|
def to_definition
|
|
129
|
-
OptionDefinition.new(@name,
|
|
152
|
+
OptionDefinition.new(@name, attributes)
|
|
130
153
|
end
|
|
131
154
|
|
|
132
|
-
def
|
|
155
|
+
def attributes
|
|
133
156
|
{
|
|
157
|
+
is_settings: @is_settings,
|
|
158
|
+
|
|
134
159
|
default: @default,
|
|
135
160
|
default_proc: @default_proc,
|
|
136
161
|
env: @env,
|
|
137
162
|
env_parser: @env_parser,
|
|
138
163
|
after_set: @after_set,
|
|
164
|
+
skip_telemetry: @skip_telemetry,
|
|
139
165
|
resetter: @resetter,
|
|
140
166
|
setter: @setter,
|
|
141
167
|
type: @type,
|