datadog 2.39.0 → 2.47.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 +269 -44
- data/README.md +3 -0
- data/ext/datadog_profiling_native_extension/NativeExtensionDesign.md +12 -24
- data/ext/datadog_profiling_native_extension/collectors_cpu_and_wall_time_worker.c +256 -193
- data/ext/datadog_profiling_native_extension/collectors_discrete_dynamic_sampler.c +1 -5
- data/ext/datadog_profiling_native_extension/collectors_gc_profiling_helper.c +0 -2
- data/ext/datadog_profiling_native_extension/collectors_idle_sampling_helper.c +19 -20
- data/ext/datadog_profiling_native_extension/collectors_idle_sampling_helper.h +5 -1
- data/ext/datadog_profiling_native_extension/collectors_stack.c +267 -171
- data/ext/datadog_profiling_native_extension/collectors_stack.h +17 -3
- data/ext/datadog_profiling_native_extension/collectors_thread_context.c +307 -217
- data/ext/datadog_profiling_native_extension/collectors_thread_context.h +10 -5
- data/ext/datadog_profiling_native_extension/crashtracking_runtime_stacks.c +5 -4
- data/ext/datadog_profiling_native_extension/datadog_ruby_common.c +19 -11
- data/ext/datadog_profiling_native_extension/datadog_ruby_common.h +7 -10
- data/ext/datadog_profiling_native_extension/extconf.rb +67 -99
- data/ext/datadog_profiling_native_extension/heap_recorder.c +353 -257
- data/ext/datadog_profiling_native_extension/heap_recorder.h +50 -31
- data/ext/datadog_profiling_native_extension/native_extension_helpers.rb +3 -27
- data/ext/datadog_profiling_native_extension/private_vm_api_access.c +853 -496
- data/ext/datadog_profiling_native_extension/private_vm_api_access.h +42 -15
- data/ext/datadog_profiling_native_extension/profiling.c +30 -23
- data/ext/datadog_profiling_native_extension/ruby_helpers.c +4 -80
- data/ext/datadog_profiling_native_extension/ruby_helpers.h +4 -7
- data/ext/datadog_profiling_native_extension/setup_signal_handler.c +0 -2
- data/ext/datadog_profiling_native_extension/stack_recorder.c +116 -89
- data/ext/datadog_profiling_native_extension/stack_recorder.h +12 -5
- data/ext/datadog_profiling_native_extension/time_helpers.c +2 -4
- data/ext/datadog_profiling_native_extension/time_helpers.h +15 -15
- data/ext/libdatadog_api/datadog_ruby_common.c +19 -11
- data/ext/libdatadog_api/datadog_ruby_common.h +7 -10
- data/ext/libdatadog_api/di.c +43 -3
- data/ext/libdatadog_api/extconf.rb +6 -1
- data/ext/libdatadog_api/feature_flags.c +8 -0
- data/ext/libdatadog_api/init.c +9 -1
- data/ext/libdatadog_api/otel_thread_context.c +274 -0
- data/ext/libdatadog_api/otel_thread_context.h +5 -0
- data/ext/libdatadog_api/process_discovery.c +15 -1
- data/ext/libdatadog_api/trace_exporter.c +2078 -0
- data/ext/libdatadog_api/trace_exporter.h +5 -0
- data/ext/libdatadog_extconf_helpers.rb +14 -9
- data/lib/datadog/ai_guard/component.rb +17 -8
- data/lib/datadog/ai_guard/configuration/ext.rb +2 -0
- data/lib/datadog/ai_guard/configuration.rb +13 -0
- data/lib/datadog/ai_guard/contrib/ruby_llm/chat_instrumentation.rb +48 -55
- data/lib/datadog/ai_guard/contrib/ruby_llm/integration.rb +1 -1
- data/lib/datadog/ai_guard/contrib/ruby_llm/message_adapter.rb +76 -0
- data/lib/datadog/ai_guard/contrib/ruby_llm/patcher.rb +1 -0
- data/lib/datadog/ai_guard/contrib/ruby_llm/redaction_change_set.rb +135 -0
- data/lib/datadog/ai_guard/evaluation/client.rb +50 -0
- data/lib/datadog/ai_guard/evaluation/content_part.rb +12 -0
- data/lib/datadog/ai_guard/evaluation/message.rb +25 -7
- data/lib/datadog/ai_guard/evaluation/message_builder.rb +31 -0
- data/lib/datadog/ai_guard/evaluation/no_op_result.rb +6 -6
- data/lib/datadog/ai_guard/evaluation/outcome.rb +24 -0
- data/lib/datadog/ai_guard/evaluation/request.rb +8 -64
- data/lib/datadog/ai_guard/evaluation/response.rb +33 -0
- data/lib/datadog/ai_guard/evaluation/result.rb +11 -18
- data/lib/datadog/ai_guard/evaluation/tool_call.rb +15 -2
- data/lib/datadog/ai_guard/evaluation.rb +36 -14
- data/lib/datadog/ai_guard/ext.rb +4 -1
- data/lib/datadog/ai_guard/{api_client.rb → http_client.rb} +7 -5
- data/lib/datadog/ai_guard/metrics/telemetry.rb +43 -0
- data/lib/datadog/ai_guard/redaction/replacements.rb +97 -0
- data/lib/datadog/ai_guard/redaction/result.rb +29 -0
- data/lib/datadog/ai_guard/redaction.rb +80 -0
- data/lib/datadog/ai_guard.rb +58 -57
- data/lib/datadog/appsec/actions_handler/serializable_backtrace.rb +21 -42
- data/lib/datadog/appsec/api_security/endpoint_collection/grape_route_serializer.rb +1 -1
- data/lib/datadog/appsec/api_security/endpoint_collection/rails_route_serializer.rb +1 -1
- data/lib/datadog/appsec/api_security/endpoint_collection/sinatra_route_serializer.rb +1 -1
- data/lib/datadog/appsec/assets/blocked.html +1 -108
- data/lib/datadog/appsec/configuration.rb +11 -2
- data/lib/datadog/appsec/context.rb +1 -1
- data/lib/datadog/appsec/contrib/active_record/instrumentation.rb +1 -1
- data/lib/datadog/appsec/contrib/aws_lambda/waf_addresses.rb +2 -2
- data/lib/datadog/appsec/contrib/devise/configuration.rb +1 -1
- data/lib/datadog/appsec/contrib/devise/patcher.rb +1 -1
- data/lib/datadog/appsec/contrib/excon/ssrf_detection_middleware.rb +2 -2
- data/lib/datadog/appsec/contrib/faraday/ssrf_detection_middleware.rb +2 -2
- data/lib/datadog/appsec/contrib/graphql/gateway/watcher.rb +1 -1
- data/lib/datadog/appsec/contrib/rack/ext.rb +2 -2
- data/lib/datadog/appsec/contrib/rack/gateway/watcher.rb +2 -2
- data/lib/datadog/appsec/contrib/rack/patcher.rb +1 -1
- data/lib/datadog/appsec/contrib/rack/request_body_middleware.rb +6 -3
- data/lib/datadog/appsec/contrib/rails/gateway/watcher.rb +30 -3
- data/lib/datadog/appsec/contrib/rails/patches/render_to_body_patch.rb +8 -7
- data/lib/datadog/appsec/contrib/rails/request_middleware.rb +2 -1
- data/lib/datadog/appsec/contrib/rest_client/request_ssrf_detection_patch.rb +2 -2
- data/lib/datadog/appsec/contrib/sinatra/gateway/watcher.rb +15 -3
- data/lib/datadog/appsec/contrib/sinatra/patches/json_patch.rb +8 -7
- data/lib/datadog/appsec/contrib/sinatra/request_middleware.rb +2 -1
- data/lib/datadog/appsec/processor/rule_loader.rb +12 -12
- data/lib/datadog/appsec/response.rb +1 -1
- data/lib/datadog/appsec/route_normalizer/route_pattern.rb +3 -3
- data/lib/datadog/appsec/security_engine/engine.rb +5 -4
- data/lib/datadog/core/configuration/components.rb +50 -19
- data/lib/datadog/core/configuration/components_state.rb +8 -1
- data/lib/datadog/core/configuration/option_definition.rb +1 -1
- data/lib/datadog/core/configuration/options.rb +1 -1
- data/lib/datadog/core/configuration/settings.rb +38 -43
- data/lib/datadog/core/configuration/supported_configurations.rb +18 -2
- data/lib/datadog/core/crashtracking/component.rb +5 -1
- data/lib/datadog/core/diagnostics/environment_logger.rb +36 -1
- data/lib/datadog/core/environment/gc.rb +1 -1
- data/lib/datadog/core/environment/vm_cache.rb +1 -1
- data/lib/datadog/core/environment/yjit.rb +2 -2
- data/lib/datadog/core/metrics/helpers.rb +1 -1
- data/lib/datadog/core/metrics/options.rb +2 -2
- data/lib/datadog/core/process_discovery.rb +6 -2
- data/lib/datadog/core/remote/client/capabilities.rb +32 -21
- data/lib/datadog/core/remote/client.rb +45 -4
- data/lib/datadog/core/remote/component.rb +30 -7
- data/lib/datadog/core/remote/configuration/repository.rb +2 -2
- data/lib/datadog/core/remote/dispatcher.rb +47 -6
- data/lib/datadog/core/remote/worker.rb +8 -0
- data/lib/datadog/core/telemetry/configuration_value.rb +38 -0
- data/lib/datadog/core/telemetry/event/app_client_configuration_change.rb +3 -1
- data/lib/datadog/core/telemetry/event/app_endpoints_loaded.rb +1 -1
- data/lib/datadog/core/telemetry/event/app_started.rb +5 -24
- data/lib/datadog/core/telemetry/event/generate_metrics.rb +1 -1
- data/lib/datadog/core/telemetry/event/log.rb +2 -2
- data/lib/datadog/core/telemetry/event/synth_app_client_configuration_change.rb +1 -1
- data/lib/datadog/core/telemetry/metric.rb +2 -2
- data/lib/datadog/core/telemetry/request.rb +2 -2
- data/lib/datadog/core/transport/http.rb +1 -1
- data/lib/datadog/core/transport/transport.rb +1 -1
- data/lib/datadog/core/utils/at_fork_monkey_patch.rb +170 -18
- data/lib/datadog/core/utils/sequence.rb +3 -6
- data/lib/datadog/core/utils/time.rb +16 -54
- data/lib/datadog/core/workers/runtime_metrics.rb +1 -1
- data/lib/datadog/data_streams/pathway_context.rb +20 -22
- data/lib/datadog/data_streams/processor.rb +45 -14
- data/lib/datadog/di/boot.rb +1 -0
- data/lib/datadog/di/capture_expression_evaluator/result.rb +30 -0
- data/lib/datadog/di/capture_expression_evaluator.rb +39 -9
- data/lib/datadog/di/component.rb +108 -3
- data/lib/datadog/di/configuration.rb +53 -2
- data/lib/datadog/di/context.rb +7 -2
- data/lib/datadog/di/contrib/active_record.rb +8 -2
- data/lib/datadog/di/el/compiler.rb +88 -12
- data/lib/datadog/di/el/evaluator.rb +82 -2
- data/lib/datadog/di/el/expression.rb +13 -2
- data/lib/datadog/di/evaluation_failure.rb +28 -0
- data/lib/datadog/di/guardrails_telemetry/reason.rb +87 -0
- data/lib/datadog/di/guardrails_telemetry.rb +203 -0
- data/lib/datadog/di/instrumenter.rb +106 -15
- data/lib/datadog/di/logger.rb +32 -10
- data/lib/datadog/di/probe.rb +9 -1
- data/lib/datadog/di/probe_builder.rb +7 -6
- data/lib/datadog/di/probe_manager.rb +56 -8
- data/lib/datadog/di/probe_notification_builder.rb +31 -28
- data/lib/datadog/di/probe_notifier_worker.rb +56 -6
- data/lib/datadog/di/proc_responder.rb +1 -1
- data/lib/datadog/di/remote.rb +49 -5
- data/lib/datadog/di/serializer.rb +172 -55
- data/lib/datadog/di/snapshot_event.rb +38 -0
- data/lib/datadog/di/transport/http.rb +13 -3
- data/lib/datadog/di/transport/input.rb +32 -7
- data/lib/datadog/error_tracking/component.rb +1 -1
- data/lib/datadog/kit/appsec/events/v2.rb +2 -2
- data/lib/datadog/open_feature/activation.rb +268 -0
- data/lib/datadog/open_feature/agentless/configuration_source.rb +246 -0
- data/lib/datadog/open_feature/agentless/parser.rb +43 -0
- data/lib/datadog/open_feature/agentless/response.rb +19 -0
- data/lib/datadog/open_feature/agentless/transport.rb +103 -0
- data/lib/datadog/open_feature/component.rb +85 -13
- data/lib/datadog/open_feature/configuration/agentless_endpoint.rb +90 -0
- data/lib/datadog/open_feature/configuration/source/resolution.rb +22 -0
- data/lib/datadog/open_feature/configuration/source.rb +43 -0
- data/lib/datadog/open_feature/configuration.rb +124 -0
- data/lib/datadog/open_feature/evaluation_engine.rb +29 -3
- data/lib/datadog/open_feature/exposures/batch_builder.rb +1 -1
- data/lib/datadog/open_feature/exposures/event.rb +15 -8
- data/lib/datadog/open_feature/ext.rb +19 -0
- data/lib/datadog/open_feature/flag_evaluation/aggregator.rb +236 -80
- data/lib/datadog/open_feature/flag_evaluation/writer.rb +179 -68
- data/lib/datadog/open_feature/hooks/evaluation_telemetry_opt_out_hook.rb +25 -0
- data/lib/datadog/open_feature/hooks/flag_eval_evp_hook.rb +24 -21
- data/lib/datadog/open_feature/native_evaluator.rb +20 -6
- data/lib/datadog/open_feature/noop_evaluator.rb +5 -0
- data/lib/datadog/open_feature/provider.rb +315 -10
- data/lib/datadog/open_feature/remote.rb +5 -5
- data/lib/datadog/open_feature/transport.rb +5 -0
- data/lib/datadog/open_feature.rb +31 -1
- data/lib/datadog/opentelemetry/sdk/propagator.rb +1 -1
- data/lib/datadog/opentelemetry/signal_configuration.rb +13 -9
- data/lib/datadog/opentelemetry/trace.rb +3 -0
- data/lib/datadog/profiling/collectors/cpu_and_wall_time_worker.rb +10 -2
- data/lib/datadog/profiling/collectors/idle_sampling_helper.rb +5 -7
- data/lib/datadog/profiling/collectors/info.rb +40 -13
- data/lib/datadog/profiling/collectors/thread_context.rb +6 -17
- data/lib/datadog/profiling/component.rb +33 -39
- data/lib/datadog/profiling/exporter.rb +10 -10
- data/lib/datadog/profiling/tasks/exec.rb +1 -1
- data/lib/datadog/profiling.rb +4 -0
- data/lib/datadog/symbol_database/extractor.rb +89 -107
- data/lib/datadog/tracing/component.rb +44 -2
- data/lib/datadog/tracing/configuration/dynamic/option.rb +4 -0
- data/lib/datadog/tracing/configuration/dynamic.rb +5 -3
- data/lib/datadog/tracing/configuration/ext.rb +4 -0
- data/lib/datadog/tracing/configuration/settings.rb +36 -0
- data/lib/datadog/tracing/context.rb +24 -2
- data/lib/datadog/tracing/context_provider.rb +17 -5
- data/lib/datadog/tracing/contrib/action_cable/events.rb +1 -1
- data/lib/datadog/tracing/contrib/action_mailer/events.rb +1 -1
- data/lib/datadog/tracing/contrib/action_pack/action_controller/instrumentation.rb +2 -2
- data/lib/datadog/tracing/contrib/action_view/events.rb +1 -1
- data/lib/datadog/tracing/contrib/active_model_serializers/events.rb +1 -1
- data/lib/datadog/tracing/contrib/active_record/configuration/resolver.rb +1 -1
- data/lib/datadog/tracing/contrib/active_record/events/sql.rb +1 -0
- data/lib/datadog/tracing/contrib/active_record/events.rb +1 -1
- data/lib/datadog/tracing/contrib/active_support/cache/events/cache.rb +2 -2
- data/lib/datadog/tracing/contrib/aws/ext.rb +1 -1
- data/lib/datadog/tracing/contrib/aws/services.rb +1 -1
- data/lib/datadog/tracing/contrib/elasticsearch/quantize.rb +1 -1
- data/lib/datadog/tracing/contrib/ethon/easy_patch.rb +10 -5
- data/lib/datadog/tracing/contrib/excon/middleware.rb +10 -3
- data/lib/datadog/tracing/contrib/ext.rb +3 -3
- data/lib/datadog/tracing/contrib/faraday/middleware.rb +10 -4
- data/lib/datadog/tracing/contrib/grape/endpoint.rb +32 -5
- data/lib/datadog/tracing/contrib/grpc/datadog_interceptor/client.rb +1 -1
- data/lib/datadog/tracing/contrib/grpc/datadog_interceptor/server.rb +1 -1
- data/lib/datadog/tracing/contrib/grpc/distributed/propagation.rb +1 -1
- data/lib/datadog/tracing/contrib/hanami/router_tracing.rb +2 -1
- data/lib/datadog/tracing/contrib/http/instrumentation.rb +16 -1
- data/lib/datadog/tracing/contrib/httpclient/instrumentation.rb +8 -2
- data/lib/datadog/tracing/contrib/httprb/instrumentation.rb +10 -4
- data/lib/datadog/tracing/contrib/kafka/events/connection/request.rb +4 -0
- data/lib/datadog/tracing/contrib/kafka/events/produce_operation/send_messages.rb +7 -2
- data/lib/datadog/tracing/contrib/kafka/events/producer/deliver_messages.rb +7 -2
- data/lib/datadog/tracing/contrib/kafka/events.rb +1 -1
- data/lib/datadog/tracing/contrib/karafka/distributed/propagation.rb +1 -1
- data/lib/datadog/tracing/contrib/mongodb/parsers.rb +1 -1
- data/lib/datadog/tracing/contrib/opensearch/ext.rb +1 -1
- data/lib/datadog/tracing/contrib/opensearch/quantize.rb +1 -1
- data/lib/datadog/tracing/contrib/patchable.rb +1 -1
- data/lib/datadog/tracing/contrib/patcher.rb +1 -1
- data/lib/datadog/tracing/contrib/que/tracer.rb +1 -1
- data/lib/datadog/tracing/contrib/racecar/events.rb +1 -1
- data/lib/datadog/tracing/contrib/rack/configuration/settings.rb +1 -1
- data/lib/datadog/tracing/contrib/rack/header_tagging.rb +1 -1
- data/lib/datadog/tracing/contrib/rack/patcher.rb +1 -1
- data/lib/datadog/tracing/contrib/rack/trace_proxy_middleware.rb +1 -1
- data/lib/datadog/tracing/contrib/redis/configuration/resolver.rb +1 -1
- data/lib/datadog/tracing/contrib/redis/quantize.rb +36 -2
- data/lib/datadog/tracing/contrib/redis/trace_middleware.rb +9 -3
- data/lib/datadog/tracing/contrib/rest_client/request_patch.rb +10 -3
- data/lib/datadog/tracing/contrib/sequel/database.rb +1 -5
- data/lib/datadog/tracing/contrib/sequel/jdbc_connection_string.rb +140 -0
- data/lib/datadog/tracing/contrib/sequel/utils.rb +50 -63
- data/lib/datadog/tracing/contrib/sidekiq/distributed/propagation.rb +1 -1
- data/lib/datadog/tracing/contrib/sinatra/configuration/settings.rb +1 -1
- data/lib/datadog/tracing/contrib/sneakers/tracer.rb +1 -1
- data/lib/datadog/tracing/contrib/utils/quantization/hash_formatter.rb +1 -1
- data/lib/datadog/tracing/contrib/utils/quantization/http.rb +108 -3
- data/lib/datadog/tracing/contrib/waterdrop/distributed/propagation.rb +1 -1
- data/lib/datadog/tracing/correlation.rb +2 -2
- data/lib/datadog/tracing/diagnostics/environment_logger.rb +3 -2
- data/lib/datadog/tracing/distributed/baggage.rb +1 -3
- data/lib/datadog/tracing/distributed/datadog.rb +3 -3
- data/lib/datadog/tracing/distributed/propagation.rb +3 -0
- data/lib/datadog/tracing/distributed/propagation_policy.rb +5 -0
- data/lib/datadog/tracing/distributed/trace_context.rb +14 -271
- data/lib/datadog/tracing/distributed/trace_state/datadog.rb +233 -0
- data/lib/datadog/tracing/distributed/trace_state/ext.rb +44 -0
- data/lib/datadog/tracing/distributed/trace_state/open_telemetry.rb +156 -0
- data/lib/datadog/tracing/distributed/trace_state.rb +121 -0
- data/lib/datadog/tracing/metadata/ext.rb +3 -0
- data/lib/datadog/tracing/metadata/tagging.rb +1 -1
- data/lib/datadog/tracing/otel_thread_context.rb +97 -0
- data/lib/datadog/tracing/remote.rb +236 -37
- data/lib/datadog/tracing/sampling/rule_sampler.rb +2 -0
- data/lib/datadog/tracing/span.rb +1 -1
- data/lib/datadog/tracing/span_operation.rb +1 -1
- data/lib/datadog/tracing/sync_writer.rb +8 -3
- data/lib/datadog/tracing/trace_digest.rb +22 -4
- data/lib/datadog/tracing/trace_operation.rb +22 -10
- data/lib/datadog/tracing/tracer.rb +28 -7
- data/lib/datadog/tracing/transport/http/telemetry.rb +94 -0
- data/lib/datadog/tracing/transport/http/traces.rb +2 -0
- data/lib/datadog/tracing/transport/io/traces.rb +1 -1
- data/lib/datadog/tracing/transport/native/response.rb +71 -0
- data/lib/datadog/tracing/transport/native/telemetry.rb +17 -0
- data/lib/datadog/tracing/transport/native.rb +395 -0
- data/lib/datadog/tracing/transport/span_events_negotiation.rb +41 -0
- data/lib/datadog/tracing/transport/telemetry.rb +62 -0
- data/lib/datadog/tracing/transport/trace_formatter.rb +14 -4
- data/lib/datadog/tracing/transport/traces.rb +85 -38
- data/lib/datadog/tracing/writer.rb +17 -4
- data/lib/datadog/version.rb +1 -1
- metadata +51 -13
- data/lib/datadog/ai_guard/evaluation/content_builder.rb +0 -31
- data/lib/datadog/appsec/utils/hash_coercion.rb +0 -23
- data/lib/datadog/tracing/distributed/datadog_tags_codec.rb +0 -69
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require_relative "ext"
|
|
4
|
+
require_relative "../open_feature"
|
|
4
5
|
require_relative "../core/utils/time"
|
|
6
|
+
require_relative "hooks/evaluation_telemetry_opt_out_hook"
|
|
5
7
|
require "open_feature/sdk"
|
|
6
8
|
|
|
7
9
|
module Datadog
|
|
8
10
|
module OpenFeature
|
|
9
|
-
# OpenFeature feature flagging provider backed by Datadog
|
|
11
|
+
# OpenFeature feature flagging provider backed by Datadog configuration delivery.
|
|
10
12
|
#
|
|
11
13
|
# Requires openfeature-sdk >= 0.5.1 for flag evaluation metrics and EVP hook support.
|
|
12
14
|
#
|
|
@@ -24,13 +26,14 @@ module Datadog
|
|
|
24
26
|
#
|
|
25
27
|
# Example:
|
|
26
28
|
#
|
|
27
|
-
#
|
|
29
|
+
# Feature Flags use agentless configuration delivery by default. To use
|
|
30
|
+
# Remote Configuration delivery instead, configure the source explicitly.
|
|
28
31
|
#
|
|
29
32
|
# ```ruby
|
|
30
33
|
# # FILE: initializers/datadog.rb
|
|
31
34
|
# Datadog.configure do |config|
|
|
32
35
|
# config.remote.enabled = true
|
|
33
|
-
# config.
|
|
36
|
+
# config.feature_flags.configuration_source = "remote_config"
|
|
34
37
|
# end
|
|
35
38
|
# ```
|
|
36
39
|
#
|
|
@@ -58,28 +61,129 @@ module Datadog
|
|
|
58
61
|
# # => 'Welcome back!'
|
|
59
62
|
# ```
|
|
60
63
|
class Provider
|
|
64
|
+
include ::OpenFeature::SDK::Provider::EventEmitter
|
|
65
|
+
|
|
61
66
|
NAME = "Datadog Feature Flagging Provider"
|
|
67
|
+
INITIALIZATION_CANCELLED_MESSAGE = "Feature Flags provider initialization was cancelled by shutdown"
|
|
62
68
|
|
|
63
69
|
attr_reader :metadata
|
|
64
70
|
|
|
65
|
-
def initialize
|
|
71
|
+
def initialize(enable_evaluation_telemetry_opt_out_parameter: nil)
|
|
72
|
+
@enable_evaluation_telemetry_opt_out_parameter = case enable_evaluation_telemetry_opt_out_parameter
|
|
73
|
+
when nil
|
|
74
|
+
Datadog.configuration.feature_flags.evaluation_telemetry_per_subject_opt_out_enabled
|
|
75
|
+
when true, false
|
|
76
|
+
enable_evaluation_telemetry_opt_out_parameter
|
|
77
|
+
else
|
|
78
|
+
raise ArgumentError, "enable_evaluation_telemetry_opt_out_parameter expects true, false, or nil"
|
|
79
|
+
end
|
|
66
80
|
@metadata = ::OpenFeature::SDK::Provider::ProviderMetadata.new(name: NAME).freeze
|
|
81
|
+
@initialization_mutex = Mutex.new
|
|
82
|
+
@initializing = false
|
|
83
|
+
@initialization_thread = nil
|
|
84
|
+
@awaiting_ready_after_fork = false
|
|
85
|
+
@initialization_failed = false
|
|
86
|
+
@provider_error_observed = false
|
|
87
|
+
@ready_pending = false
|
|
88
|
+
@ready_dispatch_claimed = false
|
|
89
|
+
@stale_emitted = false
|
|
90
|
+
@stale_pending = false
|
|
91
|
+
@error_handler = nil
|
|
92
|
+
@initialization_ready_handler = nil
|
|
93
|
+
@waiting_component = nil
|
|
94
|
+
@shutdown = false
|
|
67
95
|
end
|
|
68
96
|
|
|
69
97
|
def init
|
|
70
|
-
|
|
98
|
+
@initialization_mutex.synchronize do
|
|
99
|
+
raise INITIALIZATION_CANCELLED_MESSAGE if @shutdown
|
|
100
|
+
|
|
101
|
+
@initializing = true
|
|
102
|
+
@initialization_thread = Thread.current
|
|
103
|
+
@awaiting_ready_after_fork = false
|
|
104
|
+
@initialization_failed = false
|
|
105
|
+
@provider_error_observed = false
|
|
106
|
+
@ready_pending = false
|
|
107
|
+
@ready_dispatch_claimed = false
|
|
108
|
+
@stale_emitted = false
|
|
109
|
+
@stale_pending = false
|
|
110
|
+
end
|
|
111
|
+
ready_handler_installed = install_initialization_ready_handler
|
|
112
|
+
|
|
113
|
+
component, failure = OpenFeature.activate_provider(self)
|
|
114
|
+
cancel_initialization_if_shutdown!
|
|
115
|
+
fail_initialization(component, failure || "Feature Flags component could not be activated") unless component
|
|
116
|
+
|
|
117
|
+
@initialization_mutex.synchronize do
|
|
118
|
+
raise INITIALIZATION_CANCELLED_MESSAGE if @shutdown
|
|
119
|
+
|
|
120
|
+
@waiting_component = component
|
|
121
|
+
end
|
|
122
|
+
# Shutdown publishes this flag through the component lock; taking our mutex here would invert lock order.
|
|
123
|
+
wait_result = component.wait_for_configuration { @shutdown }
|
|
124
|
+
cancel_initialization_if_shutdown!
|
|
125
|
+
|
|
126
|
+
case wait_result
|
|
127
|
+
when Component::CONFIGURATION_READY
|
|
128
|
+
@initialization_mutex.synchronize { @initializing = false } unless ready_handler_installed
|
|
129
|
+
when Component::CONFIGURATION_TIMEOUT
|
|
130
|
+
message = "Feature Flags provider initialization timed out while waiting for configuration"
|
|
131
|
+
Datadog.logger.error(message)
|
|
132
|
+
fail_initialization(component, message)
|
|
133
|
+
else
|
|
134
|
+
fail_initialization(component, "Feature Flags provider initialization stopped before configuration arrived")
|
|
135
|
+
end
|
|
136
|
+
rescue
|
|
137
|
+
prepare_initialization_failure(component) if @initialization_mutex.synchronize { @initializing }
|
|
138
|
+
raise
|
|
139
|
+
ensure
|
|
140
|
+
@initialization_mutex.synchronize do
|
|
141
|
+
@waiting_component = nil
|
|
142
|
+
# The SDK still owes READY after init returns; the initializing thread owns that dispatch.
|
|
143
|
+
@initialization_thread = nil unless @initializing
|
|
144
|
+
end
|
|
71
145
|
end
|
|
72
146
|
|
|
73
147
|
def shutdown
|
|
74
|
-
|
|
148
|
+
configuration = @configuration
|
|
149
|
+
# @type var error_handler: Provider::provider_event_handler?
|
|
150
|
+
error_handler = nil
|
|
151
|
+
# @type var initialization_ready_handler: Provider::provider_event_handler?
|
|
152
|
+
initialization_ready_handler = nil
|
|
153
|
+
waiting_component = nil #: Component?
|
|
154
|
+
@initialization_mutex.synchronize do
|
|
155
|
+
return if @shutdown
|
|
156
|
+
|
|
157
|
+
@shutdown = true
|
|
158
|
+
@initializing = false
|
|
159
|
+
@initialization_thread = nil
|
|
160
|
+
error_handler = @error_handler
|
|
161
|
+
initialization_ready_handler = @initialization_ready_handler
|
|
162
|
+
waiting_component = @waiting_component
|
|
163
|
+
@error_handler = nil
|
|
164
|
+
@initialization_ready_handler = nil
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
waiting_component&.wake_configuration_waiters
|
|
168
|
+
configuration&.remove_handler(::OpenFeature::SDK::ProviderEvent::PROVIDER_ERROR, error_handler) if error_handler
|
|
169
|
+
if initialization_ready_handler
|
|
170
|
+
configuration&.remove_handler(
|
|
171
|
+
::OpenFeature::SDK::ProviderEvent::PROVIDER_READY,
|
|
172
|
+
initialization_ready_handler,
|
|
173
|
+
)
|
|
174
|
+
end
|
|
175
|
+
OpenFeature.deactivate_provider(self)
|
|
75
176
|
end
|
|
76
177
|
|
|
77
178
|
def hooks
|
|
78
179
|
component = Datadog.send(:components).open_feature
|
|
79
|
-
[
|
|
180
|
+
hooks = [
|
|
80
181
|
component&.flag_eval_metrics_hook,
|
|
81
182
|
component&.flag_eval_evp_hook,
|
|
82
183
|
].compact
|
|
184
|
+
return hooks unless @enable_evaluation_telemetry_opt_out_parameter
|
|
185
|
+
|
|
186
|
+
hooks.map { |hook| Hooks::EvaluationTelemetryOptOutHook.new(hook) }
|
|
83
187
|
end
|
|
84
188
|
|
|
85
189
|
def fetch_boolean_value(flag_key:, default_value:, evaluation_context: nil)
|
|
@@ -108,10 +212,196 @@ module Datadog
|
|
|
108
212
|
|
|
109
213
|
private
|
|
110
214
|
|
|
215
|
+
def after_fork(component)
|
|
216
|
+
handler = @initialization_mutex.synchronize do
|
|
217
|
+
return if @shutdown || !@initializing || @initialization_thread&.alive?
|
|
218
|
+
|
|
219
|
+
@initializing = false
|
|
220
|
+
@initialization_thread = nil
|
|
221
|
+
@waiting_component = nil
|
|
222
|
+
@awaiting_ready_after_fork = true
|
|
223
|
+
@stale_pending = false
|
|
224
|
+
previous_handler = @initialization_ready_handler
|
|
225
|
+
@initialization_ready_handler = nil
|
|
226
|
+
previous_handler
|
|
227
|
+
end
|
|
228
|
+
if handler
|
|
229
|
+
@configuration&.remove_handler(::OpenFeature::SDK::ProviderEvent::PROVIDER_READY, handler)
|
|
230
|
+
end
|
|
231
|
+
configuration_changed(Component::CONFIGURATION_READY) if component&.configuration_received?
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
def fail_initialization(component, message)
|
|
235
|
+
prepare_initialization_failure(component)
|
|
236
|
+
cancel_initialization_if_shutdown!
|
|
237
|
+
raise message.to_s
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
def prepare_initialization_failure(component)
|
|
241
|
+
cancelled, initialization_ready_handler = @initialization_mutex.synchronize do
|
|
242
|
+
handler = @initialization_ready_handler
|
|
243
|
+
@initialization_ready_handler = nil
|
|
244
|
+
@stale_pending = false
|
|
245
|
+
@initializing = false
|
|
246
|
+
@initialization_thread = nil
|
|
247
|
+
if @shutdown
|
|
248
|
+
[true, handler]
|
|
249
|
+
else
|
|
250
|
+
@initialization_failed = true
|
|
251
|
+
@ready_pending ||= !!component&.configuration_received?
|
|
252
|
+
[false, handler]
|
|
253
|
+
end
|
|
254
|
+
end
|
|
255
|
+
if initialization_ready_handler
|
|
256
|
+
@configuration&.remove_handler(
|
|
257
|
+
::OpenFeature::SDK::ProviderEvent::PROVIDER_READY,
|
|
258
|
+
initialization_ready_handler,
|
|
259
|
+
)
|
|
260
|
+
end
|
|
261
|
+
return if cancelled
|
|
262
|
+
|
|
263
|
+
install_error_handler
|
|
264
|
+
end
|
|
265
|
+
|
|
266
|
+
def cancel_initialization_if_shutdown!
|
|
267
|
+
cancelled = @initialization_mutex.synchronize do
|
|
268
|
+
@initializing = false if @shutdown
|
|
269
|
+
@shutdown
|
|
270
|
+
end
|
|
271
|
+
raise INITIALIZATION_CANCELLED_MESSAGE if cancelled
|
|
272
|
+
end
|
|
273
|
+
|
|
274
|
+
def shutdown?
|
|
275
|
+
@initialization_mutex.synchronize { @shutdown }
|
|
276
|
+
end
|
|
277
|
+
|
|
278
|
+
def install_initialization_ready_handler
|
|
279
|
+
configuration = @configuration
|
|
280
|
+
return false unless configuration
|
|
281
|
+
|
|
282
|
+
handler = @initialization_mutex.synchronize do
|
|
283
|
+
return false if @shutdown
|
|
284
|
+
return true if @initialization_ready_handler
|
|
285
|
+
|
|
286
|
+
@initialization_ready_handler = ->(details) { provider_ready(details) }
|
|
287
|
+
end
|
|
288
|
+
configuration.add_handler(::OpenFeature::SDK::ProviderEvent::PROVIDER_READY, handler)
|
|
289
|
+
|
|
290
|
+
cancelled = @initialization_mutex.synchronize { @shutdown }
|
|
291
|
+
configuration.remove_handler(::OpenFeature::SDK::ProviderEvent::PROVIDER_READY, handler) if cancelled
|
|
292
|
+
return false if cancelled
|
|
293
|
+
|
|
294
|
+
true
|
|
295
|
+
end
|
|
296
|
+
|
|
297
|
+
def install_error_handler
|
|
298
|
+
configuration = @configuration
|
|
299
|
+
return unless configuration
|
|
300
|
+
|
|
301
|
+
handler = @initialization_mutex.synchronize do
|
|
302
|
+
return if @shutdown
|
|
303
|
+
|
|
304
|
+
@error_handler ||= ->(details) { provider_error(details) }
|
|
305
|
+
end
|
|
306
|
+
configuration.add_handler(::OpenFeature::SDK::ProviderEvent::PROVIDER_ERROR, handler)
|
|
307
|
+
|
|
308
|
+
cancelled = @initialization_mutex.synchronize { @shutdown }
|
|
309
|
+
configuration.remove_handler(::OpenFeature::SDK::ProviderEvent::PROVIDER_ERROR, handler) if cancelled
|
|
310
|
+
end
|
|
311
|
+
|
|
312
|
+
def provider_error(_details)
|
|
313
|
+
configuration = @configuration
|
|
314
|
+
return unless configuration
|
|
315
|
+
return unless configuration.send(:provider_state, self) == ::OpenFeature::SDK::ProviderState::ERROR
|
|
316
|
+
|
|
317
|
+
emit_ready = @initialization_mutex.synchronize do
|
|
318
|
+
if @shutdown
|
|
319
|
+
false
|
|
320
|
+
else
|
|
321
|
+
@provider_error_observed = true
|
|
322
|
+
if @ready_pending && !@ready_dispatch_claimed
|
|
323
|
+
@ready_dispatch_claimed = true
|
|
324
|
+
else
|
|
325
|
+
false
|
|
326
|
+
end
|
|
327
|
+
end
|
|
328
|
+
end
|
|
329
|
+
emit_event(::OpenFeature::SDK::ProviderEvent::PROVIDER_READY) if emit_ready
|
|
330
|
+
end
|
|
331
|
+
|
|
332
|
+
def provider_ready(_details)
|
|
333
|
+
configuration = @configuration
|
|
334
|
+
return unless configuration
|
|
335
|
+
return unless configuration.send(:provider_state, self) == ::OpenFeature::SDK::ProviderState::READY
|
|
336
|
+
|
|
337
|
+
handler, emit_stale = @initialization_mutex.synchronize do
|
|
338
|
+
handler = @initialization_ready_handler
|
|
339
|
+
@initialization_ready_handler = nil
|
|
340
|
+
@initializing = false
|
|
341
|
+
@initialization_thread = nil
|
|
342
|
+
if @stale_pending && !@shutdown
|
|
343
|
+
@stale_pending = false
|
|
344
|
+
@stale_emitted = true
|
|
345
|
+
[handler, true]
|
|
346
|
+
else
|
|
347
|
+
[handler, false]
|
|
348
|
+
end
|
|
349
|
+
end
|
|
350
|
+
configuration.remove_handler(::OpenFeature::SDK::ProviderEvent::PROVIDER_READY, handler) if handler
|
|
351
|
+
emit_event(::OpenFeature::SDK::ProviderEvent::PROVIDER_STALE) if emit_stale
|
|
352
|
+
end
|
|
353
|
+
|
|
354
|
+
def configuration_changed(event)
|
|
355
|
+
event_type = @initialization_mutex.synchronize do
|
|
356
|
+
if @shutdown
|
|
357
|
+
nil
|
|
358
|
+
elsif event == Component::CONFIGURATION_READY
|
|
359
|
+
if @initializing
|
|
360
|
+
@ready_pending = true
|
|
361
|
+
@stale_pending = false
|
|
362
|
+
nil
|
|
363
|
+
elsif @awaiting_ready_after_fork
|
|
364
|
+
@awaiting_ready_after_fork = false
|
|
365
|
+
@stale_emitted = false
|
|
366
|
+
::OpenFeature::SDK::ProviderEvent::PROVIDER_READY
|
|
367
|
+
elsif @initialization_failed && !@provider_error_observed
|
|
368
|
+
@stale_emitted = false
|
|
369
|
+
@ready_pending = true
|
|
370
|
+
nil
|
|
371
|
+
elsif @stale_emitted
|
|
372
|
+
@stale_emitted = false
|
|
373
|
+
::OpenFeature::SDK::ProviderEvent::PROVIDER_READY
|
|
374
|
+
elsif @initialization_failed
|
|
375
|
+
if @provider_error_observed && !@ready_dispatch_claimed
|
|
376
|
+
@ready_dispatch_claimed = true
|
|
377
|
+
::OpenFeature::SDK::ProviderEvent::PROVIDER_READY
|
|
378
|
+
else
|
|
379
|
+
@ready_pending = true
|
|
380
|
+
nil
|
|
381
|
+
end
|
|
382
|
+
end
|
|
383
|
+
elsif event == Component::CONFIGURATION_CHANGED && !@initializing
|
|
384
|
+
::OpenFeature::SDK::ProviderEvent::PROVIDER_CONFIGURATION_CHANGED
|
|
385
|
+
elsif event == Component::CONFIGURATION_LOST
|
|
386
|
+
@ready_pending = false
|
|
387
|
+
if @initializing
|
|
388
|
+
@stale_pending = true
|
|
389
|
+
nil
|
|
390
|
+
else
|
|
391
|
+
@stale_emitted = true
|
|
392
|
+
::OpenFeature::SDK::ProviderEvent::PROVIDER_STALE
|
|
393
|
+
end
|
|
394
|
+
end
|
|
395
|
+
end
|
|
396
|
+
|
|
397
|
+
emit_event(event_type) if event_type
|
|
398
|
+
end
|
|
399
|
+
|
|
111
400
|
def evaluate(flag_key, default_value:, expected_type:, evaluation_context:)
|
|
112
401
|
# Stamp evaluation entry time once, here on the eval thread. The EVP path uses this for
|
|
113
402
|
# accurate first/last_evaluation bounds instead of a later hook-fire clock read.
|
|
114
403
|
eval_time_ms = (Core::Utils::Time.now.to_f * 1000).to_i
|
|
404
|
+
flag_meta = nil
|
|
115
405
|
|
|
116
406
|
engine = OpenFeature.engine
|
|
117
407
|
return component_not_configured_default(default_value, eval_time_ms) if engine.nil?
|
|
@@ -128,7 +418,9 @@ module Datadog
|
|
|
128
418
|
# Drive APM span enrichment directly from the evaluation path. This is the only reliable
|
|
129
419
|
# way to attach `ffe_*` tags across all supported OpenFeature SDK versions, since older
|
|
130
420
|
# SDKs do not dispatch provider hooks. Guarded so enrichment can never break evaluation.
|
|
131
|
-
|
|
421
|
+
unless evaluation_telemetry_opted_out?(evaluation_context)
|
|
422
|
+
enrich_span(flag_key, result, evaluation_context)
|
|
423
|
+
end
|
|
132
424
|
|
|
133
425
|
sdk_success_details(result, flag_meta)
|
|
134
426
|
rescue => e
|
|
@@ -138,7 +430,10 @@ module Datadog
|
|
|
138
430
|
error_code: Ext::GENERAL,
|
|
139
431
|
error_message: error_message
|
|
140
432
|
)
|
|
141
|
-
error_flag_meta =
|
|
433
|
+
error_flag_meta = flag_meta
|
|
434
|
+
error_flag_meta ||= build_flag_metadata(
|
|
435
|
+
error_result, eval_time_ms || (Core::Utils::Time.now.to_f * 1000).to_i
|
|
436
|
+
)
|
|
142
437
|
|
|
143
438
|
sdk_error_details(default_value, Ext::GENERAL, error_message, Ext::ERROR, error_flag_meta)
|
|
144
439
|
end
|
|
@@ -173,6 +468,8 @@ module Datadog
|
|
|
173
468
|
|
|
174
469
|
def build_flag_metadata(result, eval_time_ms)
|
|
175
470
|
metadata = result.flag_metadata&.dup || {}
|
|
471
|
+
metadata[Ext::METADATA_OBSERVE_FULL_EVALUATION_DATA] =
|
|
472
|
+
metadata[Ext::METADATA_OBSERVE_FULL_EVALUATION_DATA] == true
|
|
176
473
|
allocation_key = result.allocation_key
|
|
177
474
|
metadata[Ext::METADATA_ALLOCATION_KEY] = allocation_key if allocation_key && !allocation_key.empty?
|
|
178
475
|
|
|
@@ -212,13 +509,21 @@ module Datadog
|
|
|
212
509
|
Datadog.send(:components).open_feature&.span_enrichment_hook
|
|
213
510
|
end
|
|
214
511
|
|
|
512
|
+
def evaluation_telemetry_opted_out?(evaluation_context)
|
|
513
|
+
@enable_evaluation_telemetry_opt_out_parameter &&
|
|
514
|
+
Hooks::EvaluationTelemetryOptOutHook.opted_out?(evaluation_context)
|
|
515
|
+
end
|
|
516
|
+
|
|
215
517
|
def component_not_configured_default(value, eval_time_ms)
|
|
216
518
|
::OpenFeature::SDK::Provider::ResolutionDetails.new(
|
|
217
519
|
value: value,
|
|
218
520
|
error_code: Ext::PROVIDER_FATAL,
|
|
219
521
|
error_message: "Datadog's OpenFeature component must be configured",
|
|
220
522
|
reason: Ext::ERROR,
|
|
221
|
-
flag_metadata: {
|
|
523
|
+
flag_metadata: {
|
|
524
|
+
"dd.eval.timestamp_ms" => eval_time_ms,
|
|
525
|
+
Ext::METADATA_OBSERVE_FULL_EVALUATION_DATA => false,
|
|
526
|
+
}
|
|
222
527
|
)
|
|
223
528
|
end
|
|
224
529
|
end
|
|
@@ -19,11 +19,11 @@ module Datadog
|
|
|
19
19
|
FFE_PRODUCTS
|
|
20
20
|
end
|
|
21
21
|
|
|
22
|
-
def receivers(telemetry)
|
|
22
|
+
def receivers(telemetry, component_provider:)
|
|
23
23
|
matcher = Core::Remote::Dispatcher::Matcher::Product.new(FFE_PRODUCTS)
|
|
24
24
|
receiver = Core::Remote::Dispatcher::Receiver.new(matcher) do |repository, changes|
|
|
25
|
-
|
|
26
|
-
next unless
|
|
25
|
+
component = component_provider.call
|
|
26
|
+
next unless component
|
|
27
27
|
|
|
28
28
|
changes.each do |change|
|
|
29
29
|
content = repository[change.path]
|
|
@@ -38,7 +38,7 @@ module Datadog
|
|
|
38
38
|
when :insert, :update
|
|
39
39
|
begin
|
|
40
40
|
# @type var content: Core::Remote::Configuration::Content
|
|
41
|
-
|
|
41
|
+
component.reconfigure!(read_content(content))
|
|
42
42
|
content.applied
|
|
43
43
|
rescue EvaluationEngine::ReconfigurationError => e
|
|
44
44
|
content.errored("Error applying OpenFeature configuration: #{e.class}: #{e.message}")
|
|
@@ -46,7 +46,7 @@ module Datadog
|
|
|
46
46
|
when :delete
|
|
47
47
|
# NOTE: For now, we treat deletion as clearing the configuration
|
|
48
48
|
# In a multi-config scenario, we might track configs per path
|
|
49
|
-
|
|
49
|
+
component.reconfigure!(nil)
|
|
50
50
|
end
|
|
51
51
|
end
|
|
52
52
|
end
|
|
@@ -8,6 +8,7 @@ require_relative "../core/transport/http/api/endpoint"
|
|
|
8
8
|
require_relative "../core/transport/http/api/instance"
|
|
9
9
|
require_relative "../core/transport/parcel"
|
|
10
10
|
require_relative "../core/transport/request"
|
|
11
|
+
require_relative "../version"
|
|
11
12
|
|
|
12
13
|
module Datadog
|
|
13
14
|
module OpenFeature
|
|
@@ -27,6 +28,8 @@ module Datadog
|
|
|
27
28
|
request_env.headers["Content-Type"] = env.request.parcel.content_type
|
|
28
29
|
request_env.headers[Core::EVP::SUBDOMAIN_HEADER_NAME] =
|
|
29
30
|
Core::EVP::EVENT_PLATFORM_INTAKE_SUBDOMAIN
|
|
31
|
+
request_env.headers["DD-EVP-ORIGIN"] = "dd-trace-rb"
|
|
32
|
+
request_env.headers["DD-EVP-ORIGIN-VERSION"] = Datadog::VERSION::STRING
|
|
30
33
|
request_env.body = env.request.parcel.data
|
|
31
34
|
|
|
32
35
|
block.call(request_env)
|
|
@@ -49,6 +52,8 @@ module Datadog
|
|
|
49
52
|
request_env.headers["Content-Type"] = env.request.parcel.content_type
|
|
50
53
|
request_env.headers[Core::EVP::SUBDOMAIN_HEADER_NAME] =
|
|
51
54
|
Core::EVP::EVENT_PLATFORM_INTAKE_SUBDOMAIN
|
|
55
|
+
request_env.headers["DD-EVP-ORIGIN"] = "dd-trace-rb"
|
|
56
|
+
request_env.headers["DD-EVP-ORIGIN-VERSION"] = Datadog::VERSION::STRING
|
|
52
57
|
request_env.body = env.request.parcel.data
|
|
53
58
|
|
|
54
59
|
block.call(request_env)
|
data/lib/datadog/open_feature.rb
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
require_relative "core/configuration"
|
|
4
4
|
require_relative "open_feature/configuration"
|
|
5
|
+
require_relative "open_feature/configuration/source"
|
|
5
6
|
|
|
6
7
|
module Datadog
|
|
7
8
|
# A namespace for the OpenFeature component.
|
|
@@ -9,11 +10,40 @@ module Datadog
|
|
|
9
10
|
Core::Configuration::Settings.extend(Configuration::Settings)
|
|
10
11
|
|
|
11
12
|
def self.enabled?
|
|
12
|
-
Datadog.configuration.
|
|
13
|
+
Configuration::Source.resolve(Datadog.configuration).enabled?
|
|
13
14
|
end
|
|
14
15
|
|
|
15
16
|
def self.engine
|
|
16
17
|
Datadog.send(:components).open_feature&.engine
|
|
17
18
|
end
|
|
19
|
+
|
|
20
|
+
def self.activate_provider(provider)
|
|
21
|
+
# Initialize the component tree before taking its reconfiguration lock.
|
|
22
|
+
Datadog.send(:components)
|
|
23
|
+
Datadog.send(:safely_synchronize) do
|
|
24
|
+
return [nil, nil] if provider.send(:shutdown?)
|
|
25
|
+
|
|
26
|
+
components = Datadog.send(:components, allow_initialization: false)
|
|
27
|
+
activation = components&.send(:open_feature_activation)
|
|
28
|
+
providers = @adopted_providers ||= {}.compare_by_identity
|
|
29
|
+
providers[provider] = true
|
|
30
|
+
[activation&.activate(provider), activation&.failure]
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def self.deactivate_provider(provider)
|
|
35
|
+
Datadog.send(:safely_synchronize) do
|
|
36
|
+
@adopted_providers&.delete(provider)
|
|
37
|
+
components = Datadog.send(:components, allow_initialization: false)
|
|
38
|
+
components&.send(:open_feature_activation)&.deactivate(provider)
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# Components startup already holds the non-reentrant reconfiguration lock.
|
|
43
|
+
def self.reattach(activation)
|
|
44
|
+
providers = @adopted_providers&.keys || []
|
|
45
|
+
providers.each { |provider| activation.activate(provider) }
|
|
46
|
+
nil
|
|
47
|
+
end
|
|
18
48
|
end
|
|
19
49
|
end
|
|
@@ -60,7 +60,7 @@ module Datadog
|
|
|
60
60
|
|
|
61
61
|
if digest.trace_state || digest.trace_flags
|
|
62
62
|
trace_flags = ::OpenTelemetry::Trace::TraceFlags.from_byte(digest.trace_flags)
|
|
63
|
-
tracestate = Tracing::Distributed::
|
|
63
|
+
tracestate = Tracing::Distributed::TraceState.serialize_digest(digest)
|
|
64
64
|
else
|
|
65
65
|
trace_flags = if Tracing::Sampling::PrioritySampler.sampled?(digest.trace_sampling_priority)
|
|
66
66
|
::OpenTelemetry::Trace::TraceFlags::SAMPLED
|
|
@@ -12,23 +12,24 @@ module Datadog
|
|
|
12
12
|
def create_resource
|
|
13
13
|
resource_attributes = {}
|
|
14
14
|
|
|
15
|
-
@settings.tags&.each do |key, value|
|
|
15
|
+
@settings.tags&.each do |key, value|
|
|
16
16
|
otel_key = case key
|
|
17
17
|
when "service" then "service.name"
|
|
18
|
-
when "env"
|
|
18
|
+
when "env", "deployment.environment.name", "deployment.environment" then next
|
|
19
19
|
when "version" then "service.version"
|
|
20
20
|
else key
|
|
21
21
|
end
|
|
22
22
|
resource_attributes[otel_key] = value
|
|
23
23
|
end
|
|
24
24
|
|
|
25
|
-
resource_attributes["service.name"] = @settings.service_without_fallback || resource_attributes["service.name"] || Datadog::Core::Environment::Ext::FALLBACK_SERVICE_NAME
|
|
26
|
-
|
|
27
|
-
resource_attributes["
|
|
25
|
+
resource_attributes["service.name"] = @settings.service_without_fallback || resource_attributes["service.name"] || Datadog::Core::Environment::Ext::FALLBACK_SERVICE_NAME
|
|
26
|
+
environment = @settings.env || @settings.tags["env"] || @settings.tags["deployment.environment.name"] || @settings.tags["deployment.environment"]
|
|
27
|
+
resource_attributes["deployment.environment.name"] = environment if environment
|
|
28
|
+
resource_attributes["service.version"] = @settings.version if @settings.version
|
|
28
29
|
|
|
29
|
-
hostname = Datadog::Core::Environment::Socket.resolved_hostname(@settings)
|
|
30
|
+
hostname = Datadog::Core::Environment::Socket.resolved_hostname(@settings)
|
|
30
31
|
if hostname
|
|
31
|
-
if hostname == @settings.hostname
|
|
32
|
+
if hostname == @settings.hostname
|
|
32
33
|
resource_attributes["host.name"] = hostname
|
|
33
34
|
elsif !resource_attributes.key?("host.name")
|
|
34
35
|
resource_attributes["host.name"] = hostname
|
|
@@ -41,9 +42,12 @@ module Datadog
|
|
|
41
42
|
# Returns the signal-specific option value when explicitly set,
|
|
42
43
|
# otherwise falls back to the general OTLP exporter config or computed_default.
|
|
43
44
|
def config_or_exporter_fallback(signal:, option_name:, computed_default: nil)
|
|
44
|
-
signal_settings =
|
|
45
|
+
signal_settings = case signal
|
|
46
|
+
when :logs then @settings.opentelemetry.logs
|
|
47
|
+
when :metrics then @settings.opentelemetry.metrics
|
|
48
|
+
end
|
|
45
49
|
if signal_settings.using_default?(option_name)
|
|
46
|
-
@settings.opentelemetry.exporter.public_send(option_name) || computed_default
|
|
50
|
+
@settings.opentelemetry.exporter.public_send(option_name) || computed_default
|
|
47
51
|
else
|
|
48
52
|
signal_settings.public_send(option_name)
|
|
49
53
|
end
|
|
@@ -50,6 +50,9 @@ module Datadog
|
|
|
50
50
|
trace_service: digest.trace_service,
|
|
51
51
|
trace_state: digest.trace_state,
|
|
52
52
|
trace_state_unknown_fields: digest.trace_state_unknown_fields,
|
|
53
|
+
trace_otel_random_value: digest.trace_otel_random_value,
|
|
54
|
+
trace_otel_threshold: digest.trace_otel_threshold,
|
|
55
|
+
trace_otel_unknown_fields: digest.trace_otel_unknown_fields,
|
|
53
56
|
span_remote: digest.span_remote,
|
|
54
57
|
).freeze
|
|
55
58
|
end
|
|
@@ -33,6 +33,7 @@ module Datadog
|
|
|
33
33
|
# @rbs allocation_counting_enabled: bool
|
|
34
34
|
# @rbs gvl_profiling_enabled: bool
|
|
35
35
|
# @rbs sighandler_sampling_enabled: bool
|
|
36
|
+
# @rbs waiting_for_gvl_threshold_ns: ::Integer
|
|
36
37
|
# @rbs skip_idle_samples_for_testing: false
|
|
37
38
|
# @rbs return: void
|
|
38
39
|
def initialize(
|
|
@@ -45,11 +46,12 @@ module Datadog
|
|
|
45
46
|
gvl_profiling_enabled:,
|
|
46
47
|
sighandler_sampling_enabled:,
|
|
47
48
|
cpu_sampling_interval_ms:,
|
|
49
|
+
waiting_for_gvl_threshold_ns:,
|
|
48
50
|
# **NOTE**: This should only be used for testing; disabling the dynamic sampling rate will increase the
|
|
49
51
|
# profiler overhead!
|
|
50
52
|
dynamic_sampling_rate_enabled: true,
|
|
51
53
|
skip_idle_samples_for_testing: false,
|
|
52
|
-
idle_sampling_helper: IdleSamplingHelper.new
|
|
54
|
+
idle_sampling_helper: IdleSamplingHelper.new
|
|
53
55
|
)
|
|
54
56
|
unless dynamic_sampling_rate_enabled
|
|
55
57
|
Datadog.logger.warn(
|
|
@@ -78,6 +80,7 @@ module Datadog
|
|
|
78
80
|
sighandler_sampling_enabled: sighandler_sampling_enabled,
|
|
79
81
|
skip_idle_samples_for_testing: skip_idle_samples_for_testing,
|
|
80
82
|
cpu_sampling_interval_ms: cpu_sampling_interval_ms,
|
|
83
|
+
waiting_for_gvl_threshold_ns: waiting_for_gvl_threshold_ns,
|
|
81
84
|
)
|
|
82
85
|
@worker_thread = nil
|
|
83
86
|
@failure_exception = nil
|
|
@@ -95,7 +98,7 @@ module Datadog
|
|
|
95
98
|
|
|
96
99
|
Datadog.logger.debug { "Starting thread for: #{self}" }
|
|
97
100
|
|
|
98
|
-
@idle_sampling_helper.start
|
|
101
|
+
@idle_sampling_helper.start(self)
|
|
99
102
|
|
|
100
103
|
@worker_thread = Thread.new do
|
|
101
104
|
Thread.current.name = self.class.name
|
|
@@ -144,6 +147,11 @@ module Datadog
|
|
|
144
147
|
end
|
|
145
148
|
end
|
|
146
149
|
|
|
150
|
+
# @rbs return: Datadog::Profiling::StackRecorder
|
|
151
|
+
def prepare_serialize
|
|
152
|
+
self.class._native_prepare_serialize(self)
|
|
153
|
+
end
|
|
154
|
+
|
|
147
155
|
#: () -> true
|
|
148
156
|
def reset_after_fork
|
|
149
157
|
self.class._native_reset_after_fork(self)
|
|
@@ -10,7 +10,6 @@ module Datadog
|
|
|
10
10
|
class IdleSamplingHelper
|
|
11
11
|
# @rbs @worker_thread: untyped
|
|
12
12
|
# @rbs @start_stop_mutex: ::Thread::Mutex
|
|
13
|
-
# @rbs @thread_context_collector: Datadog::Profiling::Collectors::ThreadContext?
|
|
14
13
|
|
|
15
14
|
private
|
|
16
15
|
|
|
@@ -18,15 +17,14 @@ module Datadog
|
|
|
18
17
|
|
|
19
18
|
public
|
|
20
19
|
|
|
21
|
-
#: (
|
|
22
|
-
def initialize
|
|
20
|
+
#: () -> void
|
|
21
|
+
def initialize
|
|
23
22
|
@worker_thread = nil
|
|
24
23
|
@start_stop_mutex = Mutex.new
|
|
25
|
-
@thread_context_collector = thread_context_collector
|
|
26
24
|
end
|
|
27
25
|
|
|
28
|
-
#: () ->
|
|
29
|
-
def start
|
|
26
|
+
#: (CpuAndWallTimeWorker cpu_and_wall_time_worker) -> true?
|
|
27
|
+
def start(cpu_and_wall_time_worker)
|
|
30
28
|
@start_stop_mutex.synchronize do
|
|
31
29
|
return if @worker_thread&.alive?
|
|
32
30
|
|
|
@@ -39,7 +37,7 @@ module Datadog
|
|
|
39
37
|
@worker_thread = Thread.new do
|
|
40
38
|
Thread.current.name = self.class.name
|
|
41
39
|
|
|
42
|
-
self.class._native_idle_sampling_loop(self,
|
|
40
|
+
self.class._native_idle_sampling_loop(self, cpu_and_wall_time_worker)
|
|
43
41
|
|
|
44
42
|
Datadog.logger.debug("IdleSamplingHelper thread stopping cleanly")
|
|
45
43
|
rescue Exception => e # rubocop:disable Lint/RescueException
|