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
|
@@ -51,11 +51,10 @@ module Datadog
|
|
|
51
51
|
# @type var products: telemetry_products
|
|
52
52
|
products = {
|
|
53
53
|
appsec: {
|
|
54
|
-
|
|
55
|
-
enabled: components.settings.appsec.enabled,
|
|
54
|
+
enabled: !!components.appsec,
|
|
56
55
|
},
|
|
57
56
|
profiler: {
|
|
58
|
-
enabled: !!components.profiler
|
|
57
|
+
enabled: !!components.profiler,
|
|
59
58
|
},
|
|
60
59
|
dynamic_instrumentation: {
|
|
61
60
|
enabled: !!components.dynamic_instrumentation,
|
|
@@ -72,138 +71,39 @@ module Datadog
|
|
|
72
71
|
products
|
|
73
72
|
end
|
|
74
73
|
|
|
75
|
-
TARGET_OPTIONS = %w[
|
|
76
|
-
dynamic_instrumentation.enabled
|
|
77
|
-
logger.level
|
|
78
|
-
profiling.advanced.code_provenance_enabled
|
|
79
|
-
profiling.advanced.endpoint.collection.enabled
|
|
80
|
-
profiling.enabled
|
|
81
|
-
runtime_metrics.enabled
|
|
82
|
-
tracing.analytics.enabled
|
|
83
|
-
tracing.propagation_style_extract
|
|
84
|
-
tracing.propagation_style_inject
|
|
85
|
-
tracing.enabled
|
|
86
|
-
tracing.log_injection
|
|
87
|
-
tracing.partial_flush.enabled
|
|
88
|
-
tracing.partial_flush.min_spans_threshold
|
|
89
|
-
tracing.report_hostname
|
|
90
|
-
tracing.sampling.rate_limit
|
|
91
|
-
apm.tracing.enabled
|
|
92
|
-
].freeze
|
|
93
|
-
|
|
94
|
-
# standard:disable Metrics/AbcSize
|
|
95
|
-
# standard:disable Metrics/MethodLength
|
|
96
74
|
def configuration(settings, agent_settings)
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
# tracing.writer_options.buffer_size and tracing.writer_options.flush_interval have the same origin.
|
|
100
|
-
writer_option_origin = get_telemetry_origin(settings, 'tracing.writer_options')
|
|
101
|
-
|
|
75
|
+
# Special values that are not tied to a configuration option
|
|
102
76
|
list = [
|
|
103
|
-
# Only set using env var as of June 2025
|
|
104
|
-
conf_value('DD_GIT_REPOSITORY_URL', Core::Environment::Git.git_repository_url, seq_id, 'env_var'),
|
|
105
|
-
conf_value('DD_GIT_COMMIT_SHA', Core::Environment::Git.git_commit_sha, seq_id, 'env_var'),
|
|
106
|
-
|
|
107
|
-
# Set by the customer application (eg. `require 'datadog/auto_instrument'`)
|
|
108
77
|
conf_value(
|
|
109
|
-
'
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
'code'
|
|
78
|
+
'DD_GIT_REPOSITORY_URL',
|
|
79
|
+
Core::Environment::Git.git_repository_url,
|
|
80
|
+
(Core::Environment::Git.git_repository_url ? Configuration::Option::Precedence::ENVIRONMENT : Configuration::Option::Precedence::DEFAULT)
|
|
113
81
|
),
|
|
114
82
|
conf_value(
|
|
115
|
-
'
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
'code'
|
|
83
|
+
'DD_GIT_COMMIT_SHA',
|
|
84
|
+
Core::Environment::Git.git_commit_sha,
|
|
85
|
+
(Core::Environment::Git.git_commit_sha ? Configuration::Option::Precedence::ENVIRONMENT : Configuration::Option::Precedence::DEFAULT)
|
|
119
86
|
),
|
|
120
87
|
|
|
121
88
|
# Mix of env var, programmatic and default config, so we use unknown
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
# writer_options is defined as an option that has a Hash value.
|
|
125
|
-
conf_value(
|
|
126
|
-
'tracing.writer_options.buffer_size',
|
|
127
|
-
to_value(settings.tracing.writer_options[:buffer_size]),
|
|
128
|
-
seq_id,
|
|
129
|
-
writer_option_origin
|
|
130
|
-
),
|
|
131
|
-
conf_value(
|
|
132
|
-
'tracing.writer_options.flush_interval',
|
|
133
|
-
to_value(settings.tracing.writer_options[:flush_interval]),
|
|
134
|
-
seq_id,
|
|
135
|
-
writer_option_origin
|
|
136
|
-
),
|
|
137
|
-
|
|
138
|
-
conf_value('DD_AGENT_HOST', settings.agent.host, seq_id, get_telemetry_origin(settings, 'agent.host')),
|
|
139
|
-
conf_value(
|
|
140
|
-
'DD_TRACE_SAMPLE_RATE',
|
|
141
|
-
to_value(settings.tracing.sampling.default_rate),
|
|
142
|
-
seq_id,
|
|
143
|
-
get_telemetry_origin(settings, 'tracing.sampling.default_rate')
|
|
144
|
-
),
|
|
145
|
-
conf_value(
|
|
146
|
-
'DD_TRACE_REMOVE_INTEGRATION_SERVICE_NAMES_ENABLED',
|
|
147
|
-
settings.tracing.contrib.global_default_service_name.enabled,
|
|
148
|
-
seq_id,
|
|
149
|
-
get_telemetry_origin(settings, 'tracing.contrib.global_default_service_name.enabled')
|
|
150
|
-
),
|
|
151
|
-
conf_value(
|
|
152
|
-
'DD_TRACE_PEER_SERVICE_DEFAULTS_ENABLED',
|
|
153
|
-
settings.tracing.contrib.peer_service_defaults,
|
|
154
|
-
seq_id,
|
|
155
|
-
get_telemetry_origin(settings, 'tracing.contrib.peer_service_defaults')
|
|
156
|
-
),
|
|
157
|
-
conf_value(
|
|
158
|
-
'DD_TRACE_DEBUG',
|
|
159
|
-
settings.diagnostics.debug,
|
|
160
|
-
seq_id,
|
|
161
|
-
get_telemetry_origin(settings, 'diagnostics.debug')
|
|
162
|
-
)
|
|
89
|
+
unknown_conf_value('DD_AGENT_TRANSPORT', agent_transport(agent_settings)), # rubocop:disable CustomCops/EnvStringValidationCop
|
|
163
90
|
]
|
|
164
91
|
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
peer_service_mapping = settings.tracing.contrib.peer_service_mapping
|
|
168
|
-
peer_service_mapping_str = peer_service_mapping.map { |key, value| "#{key}:#{value}" }.join(',')
|
|
169
|
-
end
|
|
92
|
+
# Set by the customer application (eg. `require 'datadog/auto_instrument'`)
|
|
93
|
+
auto_instrument_enabled = !defined?(Datadog::AutoInstrument::LOADED).nil?
|
|
170
94
|
list << conf_value(
|
|
171
|
-
'
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
get_telemetry_origin(settings, 'tracing.contrib.peer_service_mapping')
|
|
95
|
+
'tracing.auto_instrument.enabled',
|
|
96
|
+
auto_instrument_enabled,
|
|
97
|
+
auto_instrument_enabled ? Configuration::Option::Precedence::PROGRAMMATIC : Configuration::Option::Precedence::DEFAULT
|
|
175
98
|
)
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
conf_value('OTEL_EXPORTER_OTLP_ENDPOINT', settings.opentelemetry.exporter.endpoint, seq_id, get_telemetry_origin(settings, 'opentelemetry.exporter.endpoint')),
|
|
182
|
-
conf_value('OTEL_EXPORTER_OTLP_HEADERS', otel_exporter_headers_string, seq_id, get_telemetry_origin(settings, 'opentelemetry.exporter.headers')),
|
|
183
|
-
conf_value('OTEL_EXPORTER_OTLP_PROTOCOL', settings.opentelemetry.exporter.protocol, seq_id, get_telemetry_origin(settings, 'opentelemetry.exporter.protocol')),
|
|
184
|
-
conf_value('OTEL_EXPORTER_OTLP_TIMEOUT', settings.opentelemetry.exporter.timeout_millis, seq_id, get_telemetry_origin(settings, 'opentelemetry.exporter.timeout_millis')),
|
|
185
|
-
conf_value('DD_METRICS_OTEL_ENABLED', settings.opentelemetry.metrics.enabled, seq_id, get_telemetry_origin(settings, 'opentelemetry.metrics.enabled')),
|
|
186
|
-
conf_value('OTEL_METRICS_EXPORTER', settings.opentelemetry.metrics.exporter, seq_id, get_telemetry_origin(settings, 'opentelemetry.metrics.exporter')),
|
|
187
|
-
conf_value('OTEL_EXPORTER_OTLP_METRICS_ENDPOINT', settings.opentelemetry.metrics.endpoint, seq_id, get_telemetry_origin(settings, 'opentelemetry.metrics.endpoint')),
|
|
188
|
-
conf_value('OTEL_EXPORTER_OTLP_METRICS_HEADERS', otel_exporter_metrics_headers_string, seq_id, get_telemetry_origin(settings, 'opentelemetry.metrics.headers')),
|
|
189
|
-
conf_value('OTEL_EXPORTER_OTLP_METRICS_PROTOCOL', settings.opentelemetry.metrics.protocol, seq_id, get_telemetry_origin(settings, 'opentelemetry.metrics.protocol')),
|
|
190
|
-
conf_value('OTEL_EXPORTER_OTLP_METRICS_TIMEOUT', settings.opentelemetry.metrics.timeout_millis, seq_id, get_telemetry_origin(settings, 'opentelemetry.metrics.timeout_millis')),
|
|
191
|
-
conf_value('OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE', settings.opentelemetry.metrics.temporality_preference, seq_id, get_telemetry_origin(settings, 'opentelemetry.metrics.temporality_preference')),
|
|
192
|
-
conf_value('OTEL_METRIC_EXPORT_INTERVAL', settings.opentelemetry.metrics.export_interval_millis, seq_id, get_telemetry_origin(settings, 'opentelemetry.metrics.export_interval_millis')),
|
|
193
|
-
conf_value('OTEL_METRIC_EXPORT_TIMEOUT', settings.opentelemetry.metrics.export_timeout_millis, seq_id, get_telemetry_origin(settings, 'opentelemetry.metrics.export_timeout_millis')),
|
|
99
|
+
opentelemetry_enabled = !defined?(Datadog::OpenTelemetry::LOADED).nil?
|
|
100
|
+
list << conf_value(
|
|
101
|
+
'tracing.opentelemetry.enabled',
|
|
102
|
+
opentelemetry_enabled,
|
|
103
|
+
opentelemetry_enabled ? Configuration::Option::Precedence::PROGRAMMATIC : Configuration::Option::Precedence::DEFAULT
|
|
194
104
|
)
|
|
195
105
|
|
|
196
|
-
#
|
|
197
|
-
TARGET_OPTIONS.each do |option_path|
|
|
198
|
-
split_option = option_path.split('.')
|
|
199
|
-
list << conf_value(
|
|
200
|
-
option_path,
|
|
201
|
-
to_value(settings.dig(*split_option)),
|
|
202
|
-
seq_id,
|
|
203
|
-
get_telemetry_origin(settings, option_path)
|
|
204
|
-
)
|
|
205
|
-
end
|
|
206
|
-
|
|
106
|
+
# Track ssi configurations
|
|
207
107
|
instrumentation_source = if Datadog.const_defined?(:SingleStepInstrument, false) &&
|
|
208
108
|
Datadog::SingleStepInstrument.const_defined?(:LOADED, false) &&
|
|
209
109
|
Datadog::SingleStepInstrument::LOADED
|
|
@@ -211,50 +111,81 @@ module Datadog
|
|
|
211
111
|
else
|
|
212
112
|
'manual'
|
|
213
113
|
end
|
|
214
|
-
|
|
114
|
+
|
|
215
115
|
list.push(
|
|
216
|
-
conf_value(
|
|
217
|
-
|
|
218
|
-
|
|
116
|
+
conf_value(
|
|
117
|
+
'instrumentation_source',
|
|
118
|
+
instrumentation_source,
|
|
119
|
+
(instrumentation_source == 'ssi') ? Configuration::Option::Precedence::PROGRAMMATIC : Configuration::Option::Precedence::DEFAULT
|
|
120
|
+
),
|
|
121
|
+
conf_value(
|
|
122
|
+
'DD_INJECT_FORCE',
|
|
123
|
+
Core::Environment::VariableHelpers.env_to_bool('DD_INJECT_FORCE', false),
|
|
124
|
+
(DATADOG_ENV.key?('DD_INJECT_FORCE') ? Configuration::Option::Precedence::ENVIRONMENT : Configuration::Option::Precedence::DEFAULT)
|
|
125
|
+
),
|
|
126
|
+
conf_value(
|
|
127
|
+
'DD_INJECTION_ENABLED',
|
|
128
|
+
DATADOG_ENV['DD_INJECTION_ENABLED'] || '',
|
|
129
|
+
(DATADOG_ENV.key?('DD_INJECTION_ENABLED') ? Configuration::Option::Precedence::ENVIRONMENT : Configuration::Option::Precedence::DEFAULT)
|
|
130
|
+
),
|
|
219
131
|
)
|
|
220
132
|
|
|
221
|
-
#
|
|
222
|
-
|
|
133
|
+
# Extract writer options as separate configuration payloads.
|
|
134
|
+
resolve_option(settings, 'tracing.writer_options').values_per_precedence.each do |precedence, value|
|
|
223
135
|
list << conf_value(
|
|
224
|
-
'
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
136
|
+
'tracing.writer_options.buffer_size',
|
|
137
|
+
# Steep: Value is always a hash for writer_options (ensured by o.type :hash)
|
|
138
|
+
to_telemetry_value(value[:buffer_size]), # steep:ignore NoMethod
|
|
139
|
+
precedence
|
|
228
140
|
)
|
|
229
|
-
end
|
|
230
|
-
if settings.respond_to?('appsec')
|
|
231
141
|
list << conf_value(
|
|
232
|
-
'
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
142
|
+
'tracing.writer_options.flush_interval',
|
|
143
|
+
# Steep: Value is always a hash for writer_options (ensured by o.type :hash)
|
|
144
|
+
to_telemetry_value(value[:flush_interval]), # steep:ignore NoMethod
|
|
145
|
+
precedence
|
|
236
146
|
)
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
# OpenTelemetry configuration options (using environment variable names)
|
|
150
|
+
otel_exporter_headers_option = resolve_option(settings, 'opentelemetry.exporter.headers')
|
|
151
|
+
otel_exporter_headers_option.values_per_precedence.each do |precedence, value|
|
|
237
152
|
list << conf_value(
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
153
|
+
option_telemetry_name(otel_exporter_headers_option),
|
|
154
|
+
# Steep: Value is always a hash for opentelemetry.exporter.headers (ensured by o.type :hash)
|
|
155
|
+
value&.map { |key, header_value| "#{key}=#{header_value}" }&.join(','), # steep:ignore NoMethod
|
|
156
|
+
precedence
|
|
242
157
|
)
|
|
243
158
|
end
|
|
244
|
-
|
|
159
|
+
|
|
160
|
+
otel_metrics_headers_option = resolve_option(settings, 'opentelemetry.metrics.headers')
|
|
161
|
+
otel_metrics_headers_option.values_per_precedence.each do |precedence, value|
|
|
245
162
|
list << conf_value(
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
163
|
+
option_telemetry_name(otel_metrics_headers_option),
|
|
164
|
+
# Steep: Value is always a hash for opentelemetry.metrics.headers (ensured by o.type :hash)
|
|
165
|
+
value&.map { |key, header_value| "#{key}=#{header_value}" }&.join(','), # steep:ignore NoMethod
|
|
166
|
+
precedence
|
|
250
167
|
)
|
|
251
168
|
end
|
|
252
169
|
|
|
253
|
-
|
|
170
|
+
# Add some more custom additional payload values here
|
|
171
|
+
if settings.logger.instance
|
|
172
|
+
logger_instance_option = resolve_option(settings, 'logger.instance')
|
|
173
|
+
logger_instance_option.values_per_precedence.each do |precedence, value|
|
|
174
|
+
list << conf_value(option_telemetry_name(logger_instance_option), value.nil? ? nil : value.class.to_s, precedence)
|
|
175
|
+
end
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
# Configuration options (regular + integration specific)
|
|
179
|
+
collect_all_configuration_options(settings).each do |option|
|
|
180
|
+
option.values_per_precedence.each do |precedence, value|
|
|
181
|
+
list << conf_value(option_telemetry_name(option), to_telemetry_value(value), precedence)
|
|
182
|
+
end
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
# We still want to report nil default and programmatic values as they are valid values
|
|
186
|
+
list.reject! { |entry| entry[:origin] != 'default' && entry[:origin] != 'code' && entry[:value].nil? }
|
|
254
187
|
list
|
|
255
188
|
end
|
|
256
|
-
# standard:enable Metrics/AbcSize
|
|
257
|
-
# standard:enable Metrics/MethodLength
|
|
258
189
|
|
|
259
190
|
def agent_transport(agent_settings)
|
|
260
191
|
adapter = agent_settings.adapter
|
|
@@ -266,19 +197,25 @@ module Datadog
|
|
|
266
197
|
end
|
|
267
198
|
|
|
268
199
|
# `origin`: Source of the configuration. One of :
|
|
269
|
-
# - `
|
|
270
|
-
# -
|
|
271
|
-
# -
|
|
272
|
-
# -
|
|
273
|
-
# -
|
|
274
|
-
# -
|
|
275
|
-
# -
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
200
|
+
# - 1: `default`: set when the user has not set any configuration for the key (defaults to a value)
|
|
201
|
+
# - 2:`local_stable_config`: configuration set via a user-managed file
|
|
202
|
+
# - 3:`env_var`: configurations that are set through environment variables
|
|
203
|
+
# - 4:`fleet_stable_config`: configuration is set via the fleet automation Datadog UI
|
|
204
|
+
# - 5:`code`: configurations that are set through the customer application
|
|
205
|
+
# - 6:`remote_config`: values that are set using remote config
|
|
206
|
+
# - 7:`unknown`: set for cases where it is difficult/not possible to determine the source of a config.
|
|
207
|
+
def conf_value(name, value, precedence)
|
|
208
|
+
build_conf_value(name, value, precedence.origin, precedence.numeric + 1)
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
def unknown_conf_value(name, value)
|
|
212
|
+
build_conf_value(name, value, 'unknown', Configuration::Option::Precedence::LIST.size + 1)
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
def build_conf_value(name, value, origin, seq_id)
|
|
216
|
+
# @type var result: Event::telemetry_configuration
|
|
281
217
|
result = {name: name, value: value, origin: origin, seq_id: seq_id}
|
|
218
|
+
|
|
282
219
|
if origin == 'fleet_stable_config'
|
|
283
220
|
fleet_id = Core::Configuration::StableConfig.configuration.dig(:fleet, :id)
|
|
284
221
|
result[:config_id] = fleet_id if fleet_id
|
|
@@ -286,16 +223,27 @@ module Datadog
|
|
|
286
223
|
local_id = Core::Configuration::StableConfig.configuration.dig(:local, :id)
|
|
287
224
|
result[:config_id] = local_id if local_id
|
|
288
225
|
end
|
|
226
|
+
|
|
289
227
|
result
|
|
290
228
|
end
|
|
291
229
|
|
|
292
|
-
def
|
|
230
|
+
def to_telemetry_value(value)
|
|
293
231
|
# TODO: Add float if telemetry starts accepting it
|
|
294
232
|
case value
|
|
295
233
|
when Integer, String, true, false, nil
|
|
296
234
|
value
|
|
235
|
+
when Hash
|
|
236
|
+
value.map { |key, entry_value| "#{key}:#{entry_value}" }.join(',')
|
|
237
|
+
when Array
|
|
238
|
+
value.join(',')
|
|
239
|
+
when Module
|
|
240
|
+
value.name.to_s
|
|
297
241
|
else
|
|
298
|
-
value
|
|
242
|
+
if implements_to_s?(value)
|
|
243
|
+
value.to_s
|
|
244
|
+
else
|
|
245
|
+
value.class.to_s
|
|
246
|
+
end
|
|
299
247
|
end
|
|
300
248
|
end
|
|
301
249
|
|
|
@@ -307,16 +255,50 @@ module Datadog
|
|
|
307
255
|
}
|
|
308
256
|
end
|
|
309
257
|
|
|
310
|
-
def
|
|
258
|
+
def collect_all_configuration_options(settings)
|
|
259
|
+
collect_configuration_options_from(settings).concat(collect_integration_configuration_options(settings.tracing))
|
|
260
|
+
end
|
|
261
|
+
|
|
262
|
+
def collect_integration_configuration_options(tracing_settings)
|
|
263
|
+
return [] unless tracing_settings.respond_to?(:instrumented_integrations)
|
|
264
|
+
|
|
265
|
+
tracing_settings.instrumented_integrations.each_value.with_object([]) do |integration, entries|
|
|
266
|
+
integration.configurations.each_value do |configuration|
|
|
267
|
+
entries.concat(collect_configuration_options_from(configuration))
|
|
268
|
+
end
|
|
269
|
+
end
|
|
270
|
+
end
|
|
271
|
+
|
|
272
|
+
def collect_configuration_options_from(settings)
|
|
273
|
+
settings.class.options.each_key.with_object([]) do |name, options|
|
|
274
|
+
option = settings.send(:resolve_option, name)
|
|
275
|
+
next if option.definition.skip_telemetry
|
|
276
|
+
|
|
277
|
+
if option.settings?
|
|
278
|
+
options.concat(collect_configuration_options_from(option.get))
|
|
279
|
+
else
|
|
280
|
+
options << option
|
|
281
|
+
end
|
|
282
|
+
end
|
|
283
|
+
end
|
|
284
|
+
|
|
285
|
+
def option_telemetry_name(option)
|
|
286
|
+
option.definition.env || option.name_with_settings_path
|
|
287
|
+
end
|
|
288
|
+
|
|
289
|
+
def resolve_option(settings, config_path)
|
|
311
290
|
split_option = config_path.split('.')
|
|
312
291
|
option_name = split_option.pop
|
|
313
|
-
|
|
292
|
+
raise ArgumentError, "Invalid config path: #{config_path}" if option_name.nil?
|
|
314
293
|
|
|
315
|
-
# @type var parent_setting: Core::Configuration::Options
|
|
316
|
-
# @type var option: Core::Configuration::Option
|
|
317
294
|
parent_setting = settings.dig(*split_option)
|
|
318
|
-
|
|
319
|
-
|
|
295
|
+
parent_setting.send(:resolve_option, option_name.to_sym)
|
|
296
|
+
end
|
|
297
|
+
|
|
298
|
+
def implements_to_s?(value)
|
|
299
|
+
value.method(:to_s).owner != Kernel
|
|
300
|
+
rescue NameError
|
|
301
|
+
false
|
|
320
302
|
end
|
|
321
303
|
end
|
|
322
304
|
end
|
|
@@ -10,13 +10,6 @@ module Datadog
|
|
|
10
10
|
#
|
|
11
11
|
# @api private
|
|
12
12
|
module Event
|
|
13
|
-
extend Core::Utils::Forking
|
|
14
|
-
|
|
15
|
-
# returns sequence that increments every time the configuration changes
|
|
16
|
-
def self.configuration_sequence
|
|
17
|
-
after_fork! { @sequence = Datadog::Core::Utils::Sequence.new(1) }
|
|
18
|
-
@sequence ||= Datadog::Core::Utils::Sequence.new(1)
|
|
19
|
-
end
|
|
20
13
|
end
|
|
21
14
|
end
|
|
22
15
|
end
|
|
@@ -25,6 +18,7 @@ end
|
|
|
25
18
|
require_relative 'event/base'
|
|
26
19
|
require_relative 'event/app_client_configuration_change'
|
|
27
20
|
require_relative 'event/app_closing'
|
|
21
|
+
require_relative 'event/app_extended_heartbeat'
|
|
28
22
|
require_relative 'event/app_dependencies_loaded'
|
|
29
23
|
require_relative 'event/app_endpoints_loaded'
|
|
30
24
|
require_relative 'event/app_heartbeat'
|
|
@@ -7,6 +7,7 @@ module Datadog
|
|
|
7
7
|
ENV_ENABLED = 'DD_INSTRUMENTATION_TELEMETRY_ENABLED'
|
|
8
8
|
ENV_METRICS_ENABLED = 'DD_TELEMETRY_METRICS_ENABLED'
|
|
9
9
|
ENV_HEARTBEAT_INTERVAL = 'DD_TELEMETRY_HEARTBEAT_INTERVAL'
|
|
10
|
+
ENV_EXTENDED_HEARTBEAT_INTERVAL = 'DD_TELEMETRY_EXTENDED_HEARTBEAT_INTERVAL'
|
|
10
11
|
ENV_METRICS_AGGREGATION_INTERVAL = 'DD_TELEMETRY_METRICS_AGGREGATION_INTERVAL'
|
|
11
12
|
ENV_DEPENDENCY_COLLECTION = 'DD_TELEMETRY_DEPENDENCY_COLLECTION_ENABLED'
|
|
12
13
|
ENV_INSTALL_ID = 'DD_INSTRUMENTATION_INSTALL_ID'
|
|
@@ -44,11 +44,16 @@ module Datadog
|
|
|
44
44
|
'DD-Telemetry-Request-Type' => request_type,
|
|
45
45
|
'DD-Client-Library-Language' => Core::Environment::Ext::LANG,
|
|
46
46
|
'DD-Client-Library-Version' => Core::Environment::Identity.gem_datadog_version_semver2,
|
|
47
|
+
'DD-Session-ID' => Core::Environment::Identity.id,
|
|
47
48
|
|
|
48
49
|
# Enable debug mode for telemetry
|
|
49
50
|
# 'DD-Telemetry-Debug-Enabled' => 'true',
|
|
50
51
|
}.tap do |result|
|
|
51
52
|
result['DD-API-KEY'] = api_key unless api_key.nil?
|
|
53
|
+
root = Core::Environment::Identity.root_runtime_id
|
|
54
|
+
result['DD-Root-Session-ID'] = root if root
|
|
55
|
+
parent = Core::Environment::Identity.parent_runtime_id
|
|
56
|
+
result['DD-Parent-Session-ID'] = parent if parent
|
|
52
57
|
end
|
|
53
58
|
end
|
|
54
59
|
end
|
|
@@ -27,6 +27,9 @@ module Datadog
|
|
|
27
27
|
metrics_manager:,
|
|
28
28
|
dependency_collection:,
|
|
29
29
|
logger:,
|
|
30
|
+
settings:,
|
|
31
|
+
agent_settings:,
|
|
32
|
+
extended_heartbeat_interval_seconds:,
|
|
30
33
|
enabled: true,
|
|
31
34
|
shutdown_timeout: Workers::Polling::DEFAULT_SHUTDOWN_TIMEOUT,
|
|
32
35
|
buffer_size: DEFAULT_BUFFER_MAX_SIZE
|
|
@@ -35,8 +38,11 @@ module Datadog
|
|
|
35
38
|
@metrics_manager = metrics_manager
|
|
36
39
|
@dependency_collection = dependency_collection
|
|
37
40
|
@logger = logger
|
|
41
|
+
@settings = settings
|
|
42
|
+
@agent_settings = agent_settings
|
|
38
43
|
|
|
39
44
|
@ticks_per_heartbeat = (heartbeat_interval_seconds / metrics_aggregation_interval_seconds).to_i
|
|
45
|
+
@ticks_per_extended_heartbeat = (extended_heartbeat_interval_seconds / metrics_aggregation_interval_seconds).to_i
|
|
40
46
|
@current_ticks = 0
|
|
41
47
|
|
|
42
48
|
# Workers::Polling settings
|
|
@@ -63,6 +69,7 @@ module Datadog
|
|
|
63
69
|
self.buffer = buffer_klass.new(@buffer_size)
|
|
64
70
|
|
|
65
71
|
@initial_event_once = Utils::OnlyOnceSuccessful.new(APP_STARTED_EVENT_RETRIES)
|
|
72
|
+
@extended_heartbeat_ticks = 0
|
|
66
73
|
end
|
|
67
74
|
|
|
68
75
|
attr_reader :logger
|
|
@@ -151,6 +158,13 @@ module Datadog
|
|
|
151
158
|
end
|
|
152
159
|
|
|
153
160
|
@current_ticks += 1
|
|
161
|
+
@extended_heartbeat_ticks += 1
|
|
162
|
+
|
|
163
|
+
if @extended_heartbeat_ticks >= @ticks_per_extended_heartbeat
|
|
164
|
+
@extended_heartbeat_ticks = 0
|
|
165
|
+
extended_heartbeat!
|
|
166
|
+
end
|
|
167
|
+
|
|
154
168
|
return if @current_ticks < @ticks_per_heartbeat
|
|
155
169
|
|
|
156
170
|
@current_ticks = 0
|
|
@@ -170,6 +184,12 @@ module Datadog
|
|
|
170
184
|
send_event(Event::AppHeartbeat.new)
|
|
171
185
|
end
|
|
172
186
|
|
|
187
|
+
def extended_heartbeat!
|
|
188
|
+
return if !enabled? || !sent_initial_event?
|
|
189
|
+
|
|
190
|
+
send_event(Event::AppExtendedHeartbeat.new(settings: @settings, agent_settings: @agent_settings))
|
|
191
|
+
end
|
|
192
|
+
|
|
173
193
|
def started!
|
|
174
194
|
return unless enabled?
|
|
175
195
|
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
module Datadog
|
|
4
4
|
module Core
|
|
5
5
|
module Utils
|
|
6
|
-
# Helper class to execute something only once such as not repeating warning logs
|
|
6
|
+
# Helper class to execute something only once, such as not repeating warning logs and instrumenting classes
|
|
7
7
|
# only once.
|
|
8
8
|
#
|
|
9
9
|
# Thread-safe when used correctly (e.g. be careful of races when lazily initializing instances of this class).
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Datadog
|
|
4
|
+
module Core
|
|
5
|
+
module Utils
|
|
6
|
+
module SpawnMonkeyPatch
|
|
7
|
+
# @param lineage_envs_provider [#call] returns a Hash of env vars to merge into the child process
|
|
8
|
+
def self.apply!(lineage_envs_provider:)
|
|
9
|
+
@lineage_envs_provider = lineage_envs_provider
|
|
10
|
+
::Process.singleton_class.prepend(ProcessSpawnPatch)
|
|
11
|
+
true
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
module ProcessSpawnPatch
|
|
15
|
+
def spawn(*args, **opts)
|
|
16
|
+
args.replace(SpawnMonkeyPatch.inject_lineage_envs(args))
|
|
17
|
+
super
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# Process.spawn(env?, cmd, ...): env is optional first arg (Hash). When present, merge
|
|
22
|
+
# runtime_ids into it; when absent, prepend full ENV + runtime_ids so the child inherits both.
|
|
23
|
+
def self.inject_lineage_envs(args)
|
|
24
|
+
runtime_ids = @lineage_envs_provider.call
|
|
25
|
+
env_provided = Hash === args.first
|
|
26
|
+
|
|
27
|
+
base_env = env_provided ? args.first : DATADOG_ENV.to_h
|
|
28
|
+
env = base_env.merge(runtime_ids)
|
|
29
|
+
rest = env_provided ? args.drop(1) : args
|
|
30
|
+
|
|
31
|
+
[env, *rest]
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -168,7 +168,7 @@ module Datadog
|
|
|
168
168
|
rescue Exception => e
|
|
169
169
|
@error = e
|
|
170
170
|
Datadog.logger.debug(
|
|
171
|
-
"Worker thread error. Cause: #{e.class
|
|
171
|
+
"Worker thread error. Cause: #{e.class}: #{e} Location: #{Array(e.backtrace).first}"
|
|
172
172
|
)
|
|
173
173
|
raise
|
|
174
174
|
|
data/lib/datadog/core.rb
CHANGED
|
@@ -46,7 +46,7 @@ module Datadog
|
|
|
46
46
|
decode(binary_data)
|
|
47
47
|
rescue ArgumentError => e
|
|
48
48
|
# Invalid base64 encoding - may indicate version mismatch or corruption
|
|
49
|
-
Datadog.logger.debug
|
|
49
|
+
Datadog.logger.debug { "Failed to decode DSM pathway context: #{e.class}: #{e}" }
|
|
50
50
|
nil
|
|
51
51
|
end
|
|
52
52
|
end
|
data/lib/datadog/di/boot.rb
CHANGED
|
@@ -18,8 +18,7 @@ require_relative 'serializer'
|
|
|
18
18
|
require_relative 'transport/http'
|
|
19
19
|
require_relative 'utils'
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
if %w[1 true yes].include?(Datadog::DATADOG_ENV['DD_DYNAMIC_INSTRUMENTATION_ENABLED']) # steep:ignore ArgumentTypeMismatch
|
|
21
|
+
if %w[1 true yes].include?(Datadog::DATADOG_ENV['DD_DYNAMIC_INSTRUMENTATION_ENABLED'])
|
|
23
22
|
|
|
24
23
|
# For initial release of Dynamic Instrumentation, activate code tracking
|
|
25
24
|
# only if DI is explicitly requested in the environment.
|
|
@@ -37,8 +36,7 @@ require_relative 'contrib'
|
|
|
37
36
|
|
|
38
37
|
Datadog::DI::Contrib.load_now_or_later
|
|
39
38
|
|
|
40
|
-
|
|
41
|
-
if %w[1 true yes].include?(Datadog::DATADOG_ENV['DD_DYNAMIC_INSTRUMENTATION_ENABLED']) # steep:ignore ArgumentTypeMismatch
|
|
39
|
+
if %w[1 true yes].include?(Datadog::DATADOG_ENV['DD_DYNAMIC_INSTRUMENTATION_ENABLED'])
|
|
42
40
|
if Datadog::DATADOG_ENV['DD_DYNAMIC_INSTRUMENTATION_PROBE_FILE']
|
|
43
41
|
require_relative 'probe_file_loader'
|
|
44
42
|
Datadog::DI::ProbeFileLoader.load_now_or_later
|
data/lib/datadog/di/component.rb
CHANGED
|
@@ -49,6 +49,10 @@ module Datadog
|
|
|
49
49
|
logger.warn("di: cannot enable dynamic instrumentation: Ruby 2.6+ is required, but running on #{RUBY_VERSION}")
|
|
50
50
|
return false
|
|
51
51
|
end
|
|
52
|
+
unless DI.respond_to?(:exception_message)
|
|
53
|
+
logger.warn("di: cannot enable dynamic instrumentation: C extension is not available")
|
|
54
|
+
return false
|
|
55
|
+
end
|
|
52
56
|
true
|
|
53
57
|
end
|
|
54
58
|
end
|
|
@@ -229,8 +229,7 @@ module Datadog
|
|
|
229
229
|
# that location here.
|
|
230
230
|
[]
|
|
231
231
|
end
|
|
232
|
-
|
|
233
|
-
caller_locs = method_frame + caller_locations # steep:ignore ArgumentTypeMismatch
|
|
232
|
+
caller_locs = method_frame + caller_locations
|
|
234
233
|
# TODO capture arguments at exit
|
|
235
234
|
|
|
236
235
|
context = Context.new(locals: nil, target_self: self,
|
|
@@ -239,9 +238,16 @@ module Datadog
|
|
|
239
238
|
caller_locations: caller_locs,
|
|
240
239
|
return_value: rv, duration: duration, exception: exc,)
|
|
241
240
|
|
|
242
|
-
|
|
241
|
+
begin
|
|
242
|
+
responder.probe_executed_callback(context)
|
|
243
|
+
|
|
244
|
+
instrumenter.send(:check_and_disable_if_exceeded, probe, responder, di_start_time, di_duration)
|
|
245
|
+
rescue => di_exc
|
|
246
|
+
raise if settings.dynamic_instrumentation.internal.propagate_all_exceptions
|
|
243
247
|
|
|
244
|
-
|
|
248
|
+
instrumenter.logger.debug { "di: unhandled exception in method probe: #{di_exc.class}: #{di_exc}" }
|
|
249
|
+
instrumenter.telemetry&.report(di_exc, description: "Unhandled exception in method probe")
|
|
250
|
+
end
|
|
245
251
|
|
|
246
252
|
if exc
|
|
247
253
|
raise exc
|