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
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
require_relative "transport"
|
|
4
4
|
require_relative "evaluation_engine"
|
|
5
|
+
require_relative "../core/utils/time"
|
|
6
|
+
require_relative "configuration/source"
|
|
5
7
|
require_relative "exposures/buffer"
|
|
6
8
|
require_relative "exposures/worker"
|
|
7
9
|
require_relative "exposures/deduplicator"
|
|
@@ -16,20 +18,18 @@ module Datadog
|
|
|
16
18
|
module OpenFeature
|
|
17
19
|
# This class is the entry point for the OpenFeature component
|
|
18
20
|
class Component
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
CONFIGURATION_READY = :ready
|
|
22
|
+
CONFIGURATION_TIMEOUT = :timeout
|
|
23
|
+
CONFIGURATION_SHUTDOWN = :shutdown
|
|
24
|
+
CONFIGURATION_CHANGED = :changed
|
|
25
|
+
CONFIGURATION_LOST = :lost
|
|
23
26
|
|
|
24
|
-
|
|
25
|
-
message = "OpenFeature could not be enabled as Remote Configuration is currently disabled. " \
|
|
26
|
-
"To enable Remote Configuration, see https://docs.datadoghq.com/remote_configuration/."
|
|
27
|
+
attr_reader :engine, :flag_eval_metrics_hook, :flag_eval_evp_hook, :span_enrichment_hook
|
|
27
28
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
end
|
|
29
|
+
def self.build(settings, agent_settings, resolution:, on_configuration_change:, logger:, telemetry:)
|
|
30
|
+
return unless resolution.enabled?
|
|
31
31
|
|
|
32
|
-
|
|
32
|
+
unless ["ruby", "truffleruby"].include?(RUBY_ENGINE)
|
|
33
33
|
message = "OpenFeature could not be enabled as MRI is required, " \
|
|
34
34
|
"but running on #{RUBY_ENGINE.inspect}"
|
|
35
35
|
|
|
@@ -46,10 +46,16 @@ module Datadog
|
|
|
46
46
|
return
|
|
47
47
|
end
|
|
48
48
|
|
|
49
|
-
new(
|
|
49
|
+
new(
|
|
50
|
+
settings,
|
|
51
|
+
agent_settings,
|
|
52
|
+
on_configuration_change: on_configuration_change,
|
|
53
|
+
logger: logger,
|
|
54
|
+
telemetry: telemetry,
|
|
55
|
+
)
|
|
50
56
|
end
|
|
51
57
|
|
|
52
|
-
def initialize(settings, agent_settings, logger:, telemetry:)
|
|
58
|
+
def initialize(settings, agent_settings, logger:, telemetry:, on_configuration_change: nil)
|
|
53
59
|
transport = Transport::HTTP.build(agent_settings: agent_settings, logger: logger)
|
|
54
60
|
@worker = Exposures::Worker.new(settings: settings, transport: transport, telemetry: telemetry, logger: logger)
|
|
55
61
|
|
|
@@ -60,12 +66,74 @@ module Datadog
|
|
|
60
66
|
@logger = logger
|
|
61
67
|
@settings = settings
|
|
62
68
|
@agent_settings = agent_settings
|
|
69
|
+
@on_configuration_change = on_configuration_change
|
|
63
70
|
@flag_eval_metrics_hook = create_flag_eval_metrics_hook
|
|
64
71
|
@flag_eval_evp_hook = create_flag_eval_evp_hook
|
|
65
72
|
@span_enrichment_hook = create_span_enrichment_hook
|
|
73
|
+
|
|
74
|
+
@configuration_mutex = Mutex.new
|
|
75
|
+
@reconfiguration_mutex = Mutex.new
|
|
76
|
+
@configuration_condition = ConditionVariable.new
|
|
77
|
+
@configuration_received = false
|
|
78
|
+
@configuration_shutdown = false
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def reconfigure!(configuration)
|
|
82
|
+
event = @reconfiguration_mutex.synchronize do
|
|
83
|
+
return if configuration_shutdown?
|
|
84
|
+
|
|
85
|
+
@engine.reconfigure!(configuration)
|
|
86
|
+
|
|
87
|
+
@configuration_mutex.synchronize do
|
|
88
|
+
return if @configuration_shutdown
|
|
89
|
+
|
|
90
|
+
previously_received = @configuration_received
|
|
91
|
+
@configuration_received = !configuration.nil?
|
|
92
|
+
@configuration_condition.broadcast
|
|
93
|
+
|
|
94
|
+
if @configuration_received
|
|
95
|
+
previously_received ? CONFIGURATION_CHANGED : CONFIGURATION_READY
|
|
96
|
+
elsif previously_received
|
|
97
|
+
CONFIGURATION_LOST
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
@on_configuration_change&.call(event) if event
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def wait_for_configuration(&cancelled)
|
|
106
|
+
timeout_seconds = @settings.feature_flags.initialization_timeout_ms / 1000.0
|
|
107
|
+
deadline = Core::Utils::Time.get_time + timeout_seconds
|
|
108
|
+
|
|
109
|
+
@configuration_mutex.synchronize do
|
|
110
|
+
loop do
|
|
111
|
+
return CONFIGURATION_SHUTDOWN if @configuration_shutdown || cancelled&.call
|
|
112
|
+
return CONFIGURATION_READY if @configuration_received
|
|
113
|
+
|
|
114
|
+
remaining = deadline - Core::Utils::Time.get_time
|
|
115
|
+
return CONFIGURATION_TIMEOUT unless remaining.positive?
|
|
116
|
+
|
|
117
|
+
@configuration_condition.wait(@configuration_mutex, remaining)
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
def wake_configuration_waiters
|
|
123
|
+
@configuration_mutex.synchronize { @configuration_condition.broadcast }
|
|
124
|
+
nil
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def configuration_received?
|
|
128
|
+
@configuration_mutex.synchronize { @configuration_received }
|
|
66
129
|
end
|
|
67
130
|
|
|
68
131
|
def shutdown!
|
|
132
|
+
@configuration_mutex.synchronize do
|
|
133
|
+
@configuration_shutdown = true
|
|
134
|
+
@configuration_condition.broadcast
|
|
135
|
+
end
|
|
136
|
+
|
|
69
137
|
@worker.graceful_shutdown
|
|
70
138
|
@flag_eval_evp_writer&.stop
|
|
71
139
|
# Symmetric teardown: drop any accumulated span-enrichment state and
|
|
@@ -75,6 +143,10 @@ module Datadog
|
|
|
75
143
|
|
|
76
144
|
private
|
|
77
145
|
|
|
146
|
+
def configuration_shutdown?
|
|
147
|
+
@configuration_mutex.synchronize { @configuration_shutdown }
|
|
148
|
+
end
|
|
149
|
+
|
|
78
150
|
def create_flag_eval_metrics_hook
|
|
79
151
|
return unless Hooks::FlagEvalMetricsHook.available?
|
|
80
152
|
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "uri"
|
|
4
|
+
|
|
5
|
+
module Datadog
|
|
6
|
+
module OpenFeature
|
|
7
|
+
module Configuration
|
|
8
|
+
# Validated endpoint for agentless Feature Flags configuration delivery.
|
|
9
|
+
class AgentlessEndpoint
|
|
10
|
+
DEFAULT_SITE = "datadoghq.com"
|
|
11
|
+
AGENTLESS_SUBDOMAIN = "ufc-server.ff-cdn"
|
|
12
|
+
CONFIGURATION_PATH = "/api/v2/feature-flagging/config/rules-based/server"
|
|
13
|
+
INVALID_SITE_CHARACTERS = /[\s\/?#@:]/
|
|
14
|
+
INTERNAL_WHITESPACE = /\s/
|
|
15
|
+
|
|
16
|
+
class << self
|
|
17
|
+
def build(site:, environment:, base_url: nil, logger: Datadog.logger)
|
|
18
|
+
if base_url
|
|
19
|
+
build_custom(base_url, logger)
|
|
20
|
+
else
|
|
21
|
+
build_managed(site, environment, logger)
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
private
|
|
26
|
+
|
|
27
|
+
def build_custom(base_url, logger)
|
|
28
|
+
unless base_url.ascii_only?
|
|
29
|
+
logger.warn("Feature Flags agentless base URL is invalid; agentless delivery is disabled")
|
|
30
|
+
return
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
if base_url.match?(INTERNAL_WHITESPACE)
|
|
34
|
+
logger.warn("Feature Flags agentless base URL contains whitespace; agentless delivery is disabled")
|
|
35
|
+
return
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
uri = URI.parse(base_url)
|
|
39
|
+
unless uri.is_a?(URI::HTTP) && uri.absolute? && uri.host
|
|
40
|
+
logger.warn("Feature Flags agentless base URL must be an absolute HTTP or HTTPS URL; agentless delivery is disabled")
|
|
41
|
+
return
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
uri.path = CONFIGURATION_PATH if uri.path.to_s.empty? || uri.path == "/"
|
|
45
|
+
new(uri, managed: false)
|
|
46
|
+
rescue URI::InvalidURIError
|
|
47
|
+
logger.warn("Feature Flags agentless base URL is invalid; agentless delivery is disabled")
|
|
48
|
+
nil
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def build_managed(site, environment, logger)
|
|
52
|
+
string_site = site.to_s
|
|
53
|
+
unless string_site.ascii_only?
|
|
54
|
+
logger.warn("Feature Flags site is invalid; agentless delivery is disabled")
|
|
55
|
+
return
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
normalized_site = string_site.strip.downcase
|
|
59
|
+
normalized_site = DEFAULT_SITE if normalized_site.empty?
|
|
60
|
+
if normalized_site.match?(INVALID_SITE_CHARACTERS)
|
|
61
|
+
logger.warn("Feature Flags site is invalid; agentless delivery is disabled")
|
|
62
|
+
return
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
uri = URI::HTTPS.build(
|
|
66
|
+
host: "#{AGENTLESS_SUBDOMAIN}.#{normalized_site}",
|
|
67
|
+
path: CONFIGURATION_PATH,
|
|
68
|
+
query: environment.nil? ? nil : URI.encode_www_form(dd_env: environment),
|
|
69
|
+
)
|
|
70
|
+
new(uri, managed: true)
|
|
71
|
+
rescue URI::InvalidComponentError
|
|
72
|
+
logger.warn("Feature Flags site is invalid; agentless delivery is disabled")
|
|
73
|
+
nil
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
attr_reader :uri
|
|
78
|
+
|
|
79
|
+
def initialize(uri, managed:)
|
|
80
|
+
@uri = uri
|
|
81
|
+
@managed = managed
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def managed?
|
|
85
|
+
@managed
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Datadog
|
|
4
|
+
module OpenFeature
|
|
5
|
+
module Configuration
|
|
6
|
+
module Source
|
|
7
|
+
class Resolution
|
|
8
|
+
attr_reader :source
|
|
9
|
+
|
|
10
|
+
def initialize(source, enabled:)
|
|
11
|
+
@source = source
|
|
12
|
+
@enabled = enabled
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def enabled?
|
|
16
|
+
@enabled
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "source/resolution"
|
|
4
|
+
|
|
5
|
+
module Datadog
|
|
6
|
+
module OpenFeature
|
|
7
|
+
module Configuration
|
|
8
|
+
module Source
|
|
9
|
+
AGENTLESS = "agentless"
|
|
10
|
+
REMOTE_CONFIG = "remote_config"
|
|
11
|
+
OFFLINE = "offline"
|
|
12
|
+
|
|
13
|
+
class << self
|
|
14
|
+
def resolve(settings, logger: Datadog.logger)
|
|
15
|
+
feature_flags = settings.feature_flags
|
|
16
|
+
source = resolve_source(feature_flags, legacy: settings.open_feature, logger: logger)
|
|
17
|
+
enabled = feature_flags.enabled && source != OFFLINE
|
|
18
|
+
|
|
19
|
+
Resolution.new(source, enabled: enabled)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
private
|
|
23
|
+
|
|
24
|
+
def resolve_source(settings, legacy:, logger:)
|
|
25
|
+
configured_source = settings.configuration_source
|
|
26
|
+
if !settings.using_default?(:configuration_source) && !configured_source.empty?
|
|
27
|
+
return configured_source if configured_source == AGENTLESS ||
|
|
28
|
+
configured_source == REMOTE_CONFIG ||
|
|
29
|
+
configured_source == OFFLINE
|
|
30
|
+
|
|
31
|
+
logger.warn("Unsupported Feature Flags configuration source; Feature Flags are disabled")
|
|
32
|
+
OFFLINE
|
|
33
|
+
elsif !legacy.using_default?(:enabled)
|
|
34
|
+
legacy.enabled ? REMOTE_CONFIG : OFFLINE
|
|
35
|
+
else
|
|
36
|
+
AGENTLESS
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
@@ -5,6 +5,25 @@ module Datadog
|
|
|
5
5
|
module Configuration
|
|
6
6
|
# A settings class for the OpenFeature component.
|
|
7
7
|
module Settings
|
|
8
|
+
DEFAULT_POLL_INTERVAL_SECONDS = 30
|
|
9
|
+
DEFAULT_REQUEST_TIMEOUT_SECONDS = 5
|
|
10
|
+
DEFAULT_INITIALIZATION_TIMEOUT_MS = 30_000
|
|
11
|
+
|
|
12
|
+
MAX_REQUEST_TIMEOUT_SECONDS = 300
|
|
13
|
+
MAX_INITIALIZATION_TIMEOUT_MS = 2_147_483_647
|
|
14
|
+
|
|
15
|
+
def self.configure_integer_option(option, environment_variable:, default:, setting_name:)
|
|
16
|
+
option.type :int
|
|
17
|
+
option.env environment_variable
|
|
18
|
+
option.env_parser do |value|
|
|
19
|
+
Integer(value, 10)
|
|
20
|
+
rescue ArgumentError
|
|
21
|
+
Datadog.logger.warn("#{setting_name} must be an integer; using the default")
|
|
22
|
+
default
|
|
23
|
+
end
|
|
24
|
+
option.default default
|
|
25
|
+
end
|
|
26
|
+
|
|
8
27
|
def self.extended(base)
|
|
9
28
|
base = base.singleton_class unless base.is_a?(Class)
|
|
10
29
|
add_settings!(base)
|
|
@@ -15,10 +34,19 @@ module Datadog
|
|
|
15
34
|
# Steep does not update `self` for this `class_eval` block.
|
|
16
35
|
# @type self: Datadog::Core::Configuration::Base::_DslContext
|
|
17
36
|
settings :open_feature do
|
|
37
|
+
# Deprecated switch retained for existing Remote Configuration adopters.
|
|
18
38
|
option :enabled do |o|
|
|
19
39
|
o.type :bool
|
|
20
40
|
o.env "DD_EXPERIMENTAL_FLAGGING_PROVIDER_ENABLED"
|
|
21
41
|
o.default false
|
|
42
|
+
o.after_set do |_, _, precedence|
|
|
43
|
+
next if precedence == Core::Configuration::Option::Precedence::DEFAULT
|
|
44
|
+
|
|
45
|
+
Datadog.logger.warn(
|
|
46
|
+
"DD_EXPERIMENTAL_FLAGGING_PROVIDER_ENABLED is deprecated; use " \
|
|
47
|
+
"DD_FEATURE_FLAGS_ENABLED and DD_FEATURE_FLAGS_CONFIGURATION_SOURCE instead"
|
|
48
|
+
)
|
|
49
|
+
end
|
|
22
50
|
end
|
|
23
51
|
|
|
24
52
|
# Opt-in gate for APM feature-flag span enrichment. When enabled,
|
|
@@ -42,6 +70,102 @@ module Datadog
|
|
|
42
70
|
o.default true
|
|
43
71
|
end
|
|
44
72
|
end
|
|
73
|
+
|
|
74
|
+
settings :feature_flags do
|
|
75
|
+
option :enabled do |o|
|
|
76
|
+
o.type :bool
|
|
77
|
+
o.env "DD_FEATURE_FLAGS_ENABLED"
|
|
78
|
+
o.default true
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
option :evaluation_telemetry_per_subject_opt_out_enabled do |o|
|
|
82
|
+
o.type :bool
|
|
83
|
+
o.env "DD_FEATURE_FLAGS_EVALUATION_TELEMETRY_PER_SUBJECT_OPT_OUT_ENABLED"
|
|
84
|
+
o.default false
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
option :configuration_source do |o|
|
|
88
|
+
o.type :string
|
|
89
|
+
o.env "DD_FEATURE_FLAGS_CONFIGURATION_SOURCE"
|
|
90
|
+
o.default "agentless"
|
|
91
|
+
o.setter do |value|
|
|
92
|
+
value.to_s.strip.downcase
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
settings :agentless do
|
|
97
|
+
option :base_url do |o|
|
|
98
|
+
o.type :string, nilable: true
|
|
99
|
+
o.env "DD_FEATURE_FLAGS_CONFIGURATION_SOURCE_AGENTLESS_BASE_URL"
|
|
100
|
+
o.skip_telemetry true
|
|
101
|
+
o.setter do |value|
|
|
102
|
+
next unless value
|
|
103
|
+
|
|
104
|
+
stripped_value = value.to_s.strip
|
|
105
|
+
stripped_value.empty? ? nil : stripped_value
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
option :poll_interval_seconds do |o|
|
|
110
|
+
Settings.configure_integer_option(
|
|
111
|
+
o,
|
|
112
|
+
environment_variable: "DD_FEATURE_FLAGS_CONFIGURATION_SOURCE_AGENTLESS_POLL_INTERVAL_SECONDS",
|
|
113
|
+
default: Settings::DEFAULT_POLL_INTERVAL_SECONDS,
|
|
114
|
+
setting_name: "Feature Flags agentless poll interval",
|
|
115
|
+
)
|
|
116
|
+
o.setter do |value|
|
|
117
|
+
if value.is_a?(Integer) && value > 0
|
|
118
|
+
value
|
|
119
|
+
else
|
|
120
|
+
Datadog.logger.warn(
|
|
121
|
+
"Feature Flags agentless poll interval must be positive; using the default"
|
|
122
|
+
)
|
|
123
|
+
Settings::DEFAULT_POLL_INTERVAL_SECONDS
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
option :request_timeout_seconds do |o|
|
|
129
|
+
Settings.configure_integer_option(
|
|
130
|
+
o,
|
|
131
|
+
environment_variable: "DD_FEATURE_FLAGS_CONFIGURATION_SOURCE_AGENTLESS_REQUEST_TIMEOUT_SECONDS",
|
|
132
|
+
default: Settings::DEFAULT_REQUEST_TIMEOUT_SECONDS,
|
|
133
|
+
setting_name: "Feature Flags agentless request timeout",
|
|
134
|
+
)
|
|
135
|
+
o.setter do |value|
|
|
136
|
+
if value.is_a?(Integer) && value > 0 && value <= Settings::MAX_REQUEST_TIMEOUT_SECONDS
|
|
137
|
+
value
|
|
138
|
+
else
|
|
139
|
+
Datadog.logger.warn(
|
|
140
|
+
"Feature Flags agentless request timeout must be within (0, " \
|
|
141
|
+
"#{Settings::MAX_REQUEST_TIMEOUT_SECONDS}]; using the default"
|
|
142
|
+
)
|
|
143
|
+
Settings::DEFAULT_REQUEST_TIMEOUT_SECONDS
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
option :initialization_timeout_ms do |o|
|
|
150
|
+
Settings.configure_integer_option(
|
|
151
|
+
o,
|
|
152
|
+
environment_variable: "DD_EXPERIMENTAL_FLAGGING_PROVIDER_INITIALIZATION_TIMEOUT_MS",
|
|
153
|
+
default: Settings::DEFAULT_INITIALIZATION_TIMEOUT_MS,
|
|
154
|
+
setting_name: "Feature Flags provider initialization timeout",
|
|
155
|
+
)
|
|
156
|
+
o.setter do |value|
|
|
157
|
+
if value.is_a?(Integer) && value > 0 && value <= Settings::MAX_INITIALIZATION_TIMEOUT_MS
|
|
158
|
+
value
|
|
159
|
+
else
|
|
160
|
+
Datadog.logger.warn(
|
|
161
|
+
"Feature Flags provider initialization timeout must be within (0, " \
|
|
162
|
+
"#{Settings::MAX_INITIALIZATION_TIMEOUT_MS}]; using the default"
|
|
163
|
+
)
|
|
164
|
+
Settings::DEFAULT_INITIALIZATION_TIMEOUT_MS
|
|
165
|
+
end
|
|
166
|
+
end
|
|
167
|
+
end
|
|
168
|
+
end
|
|
45
169
|
end
|
|
46
170
|
end
|
|
47
171
|
end
|
|
@@ -23,27 +23,42 @@ module Datadog
|
|
|
23
23
|
end
|
|
24
24
|
|
|
25
25
|
def fetch_value(flag_key, default_value:, expected_type:, evaluation_context: nil)
|
|
26
|
+
# Pre-bound to the safe default so the rescue below can still read it if the
|
|
27
|
+
# evaluator read itself raises.
|
|
28
|
+
observe_full_evaluation_data = false
|
|
29
|
+
# Snapshot the evaluator once: a concurrent reconfigure! must not retroactively
|
|
30
|
+
# apply a different environment's full-evaluation-data policy to this evaluation.
|
|
31
|
+
evaluator = @evaluator
|
|
32
|
+
observe_full_evaluation_data = evaluator.observe_full_evaluation_data == true
|
|
33
|
+
|
|
26
34
|
unless ALLOWED_TYPES.include?(expected_type)
|
|
27
35
|
message = "unknown type #{expected_type.inspect}, allowed types #{ALLOWED_TYPES.join(", ")}"
|
|
28
|
-
|
|
36
|
+
result = ResolutionDetails.build_error(
|
|
29
37
|
value: default_value, error_code: Ext::UNKNOWN_TYPE, error_message: message
|
|
30
38
|
)
|
|
39
|
+
|
|
40
|
+
return with_observe_full_evaluation_data(result, observe_full_evaluation_data)
|
|
31
41
|
end
|
|
32
42
|
|
|
33
43
|
context = evaluation_context&.fields.to_h
|
|
34
|
-
result =
|
|
44
|
+
result = evaluator.get_assignment(
|
|
35
45
|
flag_key, default_value: default_value, context: context, expected_type: expected_type
|
|
36
46
|
)
|
|
37
47
|
|
|
48
|
+
result = with_observe_full_evaluation_data(result, observe_full_evaluation_data)
|
|
49
|
+
|
|
38
50
|
@reporter.report(result, flag_key: flag_key, context: evaluation_context)
|
|
39
51
|
|
|
40
52
|
result
|
|
41
53
|
rescue => e
|
|
42
54
|
@telemetry.report(e, description: "OpenFeature: Failed to fetch flag value")
|
|
43
55
|
|
|
44
|
-
ResolutionDetails.build_error(
|
|
56
|
+
result = ResolutionDetails.build_error(
|
|
45
57
|
value: default_value, error_code: Ext::GENERAL, error_message: "#{e.class}: #{e.message}"
|
|
46
58
|
)
|
|
59
|
+
# `== true` is load-bearing: Steep types this local as `(nil | bool)` in a rescue
|
|
60
|
+
# body, and coercing at the use site is what narrows it to `bool`.
|
|
61
|
+
with_observe_full_evaluation_data(result, observe_full_evaluation_data == true)
|
|
47
62
|
end
|
|
48
63
|
|
|
49
64
|
# NOTE: In a currect implementation configuration is expected to be a raw
|
|
@@ -65,6 +80,17 @@ module Datadog
|
|
|
65
80
|
|
|
66
81
|
raise ReconfigurationError, "#{e.class}: #{e.message}"
|
|
67
82
|
end
|
|
83
|
+
|
|
84
|
+
private
|
|
85
|
+
|
|
86
|
+
# Stamps observe_full_evaluation_data onto the result metadata so the hook
|
|
87
|
+
# reads it from the event, not live config.
|
|
88
|
+
def with_observe_full_evaluation_data(result, observe_full_evaluation_data)
|
|
89
|
+
result = result.dup if result.frozen?
|
|
90
|
+
metadata = result.flag_metadata ||= {}
|
|
91
|
+
metadata[Ext::METADATA_OBSERVE_FULL_EVALUATION_DATA] = observe_full_evaluation_data
|
|
92
|
+
result
|
|
93
|
+
end
|
|
68
94
|
end
|
|
69
95
|
end
|
|
70
96
|
end
|
|
@@ -15,27 +15,34 @@ module Datadog
|
|
|
15
15
|
"#{flag_key}:#{context.targeting_key}"
|
|
16
16
|
end
|
|
17
17
|
|
|
18
|
+
# NOTE: The serial id is part of the value because it can appear or change on a
|
|
19
|
+
# configuration refresh while the allocation and the variant stay the same.
|
|
18
20
|
def cache_value(result, flag_key:, context:)
|
|
19
|
-
"#{result.allocation_key}:#{result.variant}"
|
|
21
|
+
"#{result.allocation_key}:#{result.variant}:#{result.serial_id}"
|
|
20
22
|
end
|
|
21
23
|
|
|
22
24
|
def build(result, flag_key:, context:)
|
|
23
|
-
{
|
|
25
|
+
event = {
|
|
24
26
|
timestamp: current_timestamp_ms,
|
|
25
27
|
allocation: {
|
|
26
|
-
key: result.allocation_key
|
|
28
|
+
key: result.allocation_key,
|
|
27
29
|
},
|
|
28
30
|
flag: {
|
|
29
|
-
key: flag_key
|
|
31
|
+
key: flag_key,
|
|
30
32
|
},
|
|
31
33
|
variant: {
|
|
32
|
-
key: result.variant
|
|
34
|
+
key: result.variant,
|
|
33
35
|
},
|
|
34
36
|
subject: {
|
|
35
37
|
id: context.targeting_key,
|
|
36
|
-
attributes: extract_attributes(context)
|
|
37
|
-
}
|
|
38
|
-
}
|
|
38
|
+
attributes: extract_attributes(context),
|
|
39
|
+
},
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
serial_id = result.serial_id
|
|
43
|
+
event[:serial_id] = serial_id unless serial_id.nil?
|
|
44
|
+
|
|
45
|
+
event.freeze
|
|
39
46
|
end
|
|
40
47
|
|
|
41
48
|
private
|
|
@@ -11,11 +11,30 @@ module Datadog
|
|
|
11
11
|
GENERAL = "GENERAL"
|
|
12
12
|
PROVIDER_FATAL = "PROVIDER_FATAL"
|
|
13
13
|
PROVIDER_NOT_READY = "PROVIDER_NOT_READY"
|
|
14
|
+
FLAG_NOT_FOUND = "FLAG_NOT_FOUND"
|
|
15
|
+
TYPE_MISMATCH = "TYPE_MISMATCH"
|
|
16
|
+
TARGETING_KEY_MISSING = "TARGETING_KEY_MISSING"
|
|
17
|
+
INVALID_CONTEXT = "INVALID_CONTEXT"
|
|
18
|
+
|
|
19
|
+
STANDARD_ERROR_CODES = [
|
|
20
|
+
PROVIDER_NOT_READY,
|
|
21
|
+
FLAG_NOT_FOUND,
|
|
22
|
+
PARSE_ERROR,
|
|
23
|
+
TYPE_MISMATCH,
|
|
24
|
+
TARGETING_KEY_MISSING,
|
|
25
|
+
INVALID_CONTEXT,
|
|
26
|
+
PROVIDER_FATAL,
|
|
27
|
+
GENERAL,
|
|
28
|
+
].freeze
|
|
14
29
|
|
|
15
30
|
# Flag-metadata key under which the provider threads the assignment's
|
|
16
31
|
# allocation key to the flag-evaluation hooks. The wire string is the
|
|
17
32
|
# value so the writer (provider) and readers (EVP/metrics hooks) can't drift.
|
|
18
33
|
METADATA_ALLOCATION_KEY = "__dd_allocation_key"
|
|
34
|
+
|
|
35
|
+
# Stamped from the UFC the evaluation ran against; the hook reads only this
|
|
36
|
+
# key, never live config.
|
|
37
|
+
METADATA_OBSERVE_FULL_EVALUATION_DATA = "__dd_observe_full_evaluation_data"
|
|
19
38
|
end
|
|
20
39
|
end
|
|
21
40
|
end
|