diff --git a/.github/forced-tests-list.json b/.github/forced-tests-list.json index 077404aaa41..10e48d04251 100644 --- a/.github/forced-tests-list.json +++ b/.github/forced-tests-list.json @@ -1,3 +1,6 @@ { - + "SCA_STANDALONE": + [ + "tests/appsec/test_asm_standalone.py::Test_SCAStandalone_Telemetry" + ] } \ No newline at end of file diff --git a/.github/workflows/system-tests.yml b/.github/workflows/system-tests.yml index d8c8b03534d..fd9bd41393c 100644 --- a/.github/workflows/system-tests.yml +++ b/.github/workflows/system-tests.yml @@ -282,6 +282,9 @@ jobs: - library: ruby app: rails70 scenario: DEBUGGER_PII_REDACTION + - library: ruby + app: rails70 + scenario: SCA_STANDALONE - library: ruby app: rack scenario: SAMPLING diff --git a/lib/datadog/appsec/configuration/settings.rb b/lib/datadog/appsec/configuration/settings.rb index e8ed0a8240a..e5dbecfb0e1 100644 --- a/lib/datadog/appsec/configuration/settings.rb +++ b/lib/datadog/appsec/configuration/settings.rb @@ -197,14 +197,6 @@ def self.add_settings!(base) o.type :bool, nilable: true o.env 'DD_APPSEC_SCA_ENABLED' end - - settings :standalone do - option :enabled do |o| - o.type :bool - o.env 'DD_EXPERIMENTAL_APPSEC_STANDALONE_ENABLED' - o.default false - end - end end end end diff --git a/lib/datadog/appsec/contrib/rack/request_middleware.rb b/lib/datadog/appsec/contrib/rack/request_middleware.rb index cbb232c00e3..bd27505c4da 100644 --- a/lib/datadog/appsec/contrib/rack/request_middleware.rb +++ b/lib/datadog/appsec/contrib/rack/request_middleware.rb @@ -151,8 +151,6 @@ def add_appsec_tags(processor, scope) return unless trace && span span.set_metric(Datadog::AppSec::Ext::TAG_APPSEC_ENABLED, 1) - # We add this tag when ASM standalone is enabled to make sure we don't bill APM - span.set_metric(Datadog::AppSec::Ext::TAG_APM_ENABLED, 0) if Datadog.configuration.appsec.standalone.enabled span.set_tag('_dd.runtime_family', 'ruby') span.set_tag('_dd.appsec.waf.version', Datadog::AppSec::WAF::VERSION::BASE_STRING) diff --git a/lib/datadog/appsec/ext.rb b/lib/datadog/appsec/ext.rb index 30c21b7d240..0f8dddd446f 100644 --- a/lib/datadog/appsec/ext.rb +++ b/lib/datadog/appsec/ext.rb @@ -7,7 +7,6 @@ module Ext SCOPE_KEY = 'datadog.appsec.scope' TAG_APPSEC_ENABLED = '_dd.appsec.enabled' - TAG_APM_ENABLED = '_dd.apm.enabled' TAG_DISTRIBUTED_APPSEC_EVENT = '_dd.p.appsec' end end diff --git a/lib/datadog/appsec/utils.rb b/lib/datadog/appsec/utils.rb index b38ec5b96f5..8e4083533db 100644 --- a/lib/datadog/appsec/utils.rb +++ b/lib/datadog/appsec/utils.rb @@ -1,7 +1,5 @@ # frozen_string_literal: true -require_relative 'utils/trace_operation' - module Datadog module AppSec # Utilities for AppSec diff --git a/lib/datadog/appsec/utils/trace_operation.rb b/lib/datadog/appsec/utils/trace_operation.rb deleted file mode 100644 index 19f2b0b2187..00000000000 --- a/lib/datadog/appsec/utils/trace_operation.rb +++ /dev/null @@ -1,15 +0,0 @@ -# frozen_string_literal: true - -module Datadog - module AppSec - module Utils - # Utility class to to AppSec-specific trace operations - class TraceOperation - def self.appsec_standalone_reject?(trace) - Datadog.configuration.appsec.standalone.enabled && - (trace.nil? || trace.get_tag(Datadog::AppSec::Ext::TAG_DISTRIBUTED_APPSEC_EVENT) != '1') - end - end - end - end -end diff --git a/lib/datadog/core/remote/transport/http.rb b/lib/datadog/core/remote/transport/http.rb index 190a9c45646..c972236b2b3 100644 --- a/lib/datadog/core/remote/transport/http.rb +++ b/lib/datadog/core/remote/transport/http.rb @@ -122,7 +122,7 @@ def default_headers headers[Datadog::Core::Transport::Ext::HTTP::HEADER_CONTAINER_ID] = container_id unless container_id.nil? # Sending this header to the agent will disable metrics computation (and billing) on the agent side # by pretending it has already been done on the library side. - if Datadog.configuration.appsec.standalone.enabled + if Datadog.configuration.tracing.non_billing.enabled headers[Datadog::Core::Transport::Ext::HTTP::HEADER_CLIENT_COMPUTED_STATS] = 'yes' end end diff --git a/lib/datadog/tracing/component.rb b/lib/datadog/tracing/component.rb index 34744e53ef6..e99d49123df 100644 --- a/lib/datadog/tracing/component.rb +++ b/lib/datadog/tracing/component.rb @@ -73,12 +73,11 @@ def build_sampler(settings) return sampler end - # AppSec events are sent to the backend using traces. - # Standalone ASM billing means that we don't want to charge clients for APM traces, - # so we want to send the minimum amount of traces possible (idealy only traces that contains security events), - # but for features such as API Security, we need to send at least one trace per minute, + # This sampler sends the minimum amount of traces possible, + # but to show the service on the service catalog, we need to send at least one trace per minute, # to keep the service alive on the backend side. - if settings.appsec.standalone.enabled + # Traces can still be force-kept (e.g. those containing AppSec events). + if settings.tracing.non_billing.enabled post_sampler = Tracing::Sampling::RuleSampler.new( [Tracing::Sampling::SimpleRule.new(sample_rate: 1.0)], rate_limiter: Datadog::Core::TokenBucket.new(1.0 / 60, 1.0), diff --git a/lib/datadog/tracing/configuration/ext.rb b/lib/datadog/tracing/configuration/ext.rb index 5823d2f9e53..86ef005348f 100644 --- a/lib/datadog/tracing/configuration/ext.rb +++ b/lib/datadog/tracing/configuration/ext.rb @@ -12,6 +12,7 @@ module Ext ENV_OTEL_TRACES_EXPORTER = 'OTEL_TRACES_EXPORTER' ENV_HEADER_TAGS = 'DD_TRACE_HEADER_TAGS' ENV_TRACE_ID_128_BIT_GENERATION_ENABLED = 'DD_TRACE_128_BIT_TRACEID_GENERATION_ENABLED' + ENV_APM_ENABLED = 'DD_EXPERIMENTAL_APPSEC_STANDALONE_ENABLED' # Temporary until RFC decides final name # @public_api module SpanAttributeSchema diff --git a/lib/datadog/tracing/configuration/settings.rb b/lib/datadog/tracing/configuration/settings.rb index 4b94b6d9eeb..389d1f164db 100644 --- a/lib/datadog/tracing/configuration/settings.rb +++ b/lib/datadog/tracing/configuration/settings.rb @@ -150,6 +150,45 @@ def self.extended(base) end end + # Configures tracing non-billing mode configuration + # + # This rate-limit traces to 1 per minute, to keep the service alive without billing it. + # The RFC defines the environment variable as DD_TRACE_APM_ENABLED, we are following a similar name. + # As of late November, the RFC is not approved yet but should be soon, hence why we are still + # using DD_EXPERIMENTAL_APPSEC_STANDALONE_ENABLED. DD_TRACE_APM_ENABLED will most likely change. + # As we already have a way to completely disable traces, we are using 'non_billing' terminology to + # make it clear that this is a non-billing mode, which does NOT completely disables tracing. + # + # Currently, the env var is DD_EXPERIMENTAL_APPSEC_STANDALONE_ENABLED + # which enables non-billing mode when set to `true`. But the future env var will + # enables non-billing mode when set to `false`. so we will have to invert the values + # returned by the env_parser block. + # + # @public_api + settings :non_billing do + # When set to true (or env var set to false) + # sets the rate limit to 1 trace per minute, and prevents billing by adding tags + # + # @default `DD_TRACE_APM_ENABLED` environment variable, otherwise `true` + # @return [Boolean] + option :enabled do |o| + o.env Tracing::Configuration::Ext::ENV_APM_ENABLED + o.default false + o.type :bool + o.env_parser do |value| + value = value&.downcase + if ['false', '0'].include?(value) + false + elsif ['true', '1'].include?(value) + true + else + Datadog.logger.warn("Unsupported value for 'non-billing' mode: #{value}. Traces will be sent to Datadog.") + nil + end + end + end + end + # Comma-separated, case-insensitive list of header names that are reported in incoming and outgoing HTTP requests. # # Each header in the list can either be: diff --git a/lib/datadog/tracing/contrib/ethon/easy_patch.rb b/lib/datadog/tracing/contrib/ethon/easy_patch.rb index 72e2c104f6b..b47d6650c96 100644 --- a/lib/datadog/tracing/contrib/ethon/easy_patch.rb +++ b/lib/datadog/tracing/contrib/ethon/easy_patch.rb @@ -110,11 +110,14 @@ def datadog_before_request(continue_from: nil) datadog_tag_request - if Datadog::AppSec::Utils::TraceOperation.appsec_standalone_reject?(datadog_trace) + if datadog_trace.non_billing_reject? datadog_trace.sampling_priority = Tracing::Sampling::Ext::Priority::AUTO_REJECT end - if datadog_configuration[:distributed_tracing] + unless Tracing::Distributed::Helpers.should_skip_distributed_tracing?( + datadog_configuration, + trace: datadog_trace + ) @datadog_original_headers ||= {} Contrib::HTTP.inject(datadog_trace, @datadog_original_headers) self.headers = @datadog_original_headers diff --git a/lib/datadog/tracing/contrib/excon/middleware.rb b/lib/datadog/tracing/contrib/excon/middleware.rb index 9bb3f8629ef..a640f720660 100644 --- a/lib/datadog/tracing/contrib/excon/middleware.rb +++ b/lib/datadog/tracing/contrib/excon/middleware.rb @@ -30,10 +30,11 @@ def request_call(datum) trace = Tracing.active_trace datum[:datadog_span] = span annotate!(span, datum) - if Datadog::AppSec::Utils::TraceOperation.appsec_standalone_reject?(trace) - trace.sampling_priority = Tracing::Sampling::Ext::Priority::AUTO_REJECT + trace.sampling_priority = Tracing::Sampling::Ext::Priority::AUTO_REJECT if trace.non_billing_reject? + if Tracing.enabled? && + !Tracing::Distributed::Helpers.should_skip_distributed_tracing?(@options, trace: trace) + propagate!(trace, span, datum) end - propagate!(trace, span, datum) if distributed_tracing? span end diff --git a/lib/datadog/tracing/contrib/faraday/middleware.rb b/lib/datadog/tracing/contrib/faraday/middleware.rb index 0795ba29b2c..fe8d8770d9c 100644 --- a/lib/datadog/tracing/contrib/faraday/middleware.rb +++ b/lib/datadog/tracing/contrib/faraday/middleware.rb @@ -29,10 +29,11 @@ def call(env) Tracing.trace(Ext::SPAN_REQUEST, on_error: request_options[:on_error]) do |span, trace| annotate!(span, env, request_options) - if Datadog::AppSec::Utils::TraceOperation.appsec_standalone_reject?(trace) - trace.sampling_priority = Tracing::Sampling::Ext::Priority::AUTO_REJECT + trace.sampling_priority = Tracing::Sampling::Ext::Priority::AUTO_REJECT if trace.non_billing_reject? + if Tracing.enabled? && + !Tracing::Distributed::Helpers.should_skip_distributed_tracing?(request_options, trace: trace) + propagate!(trace, span, env) end - propagate!(trace, span, env) if request_options[:distributed_tracing] && Tracing.enabled? app.call(env).on_complete { |resp| handle_response(span, resp, request_options) } end end diff --git a/lib/datadog/tracing/contrib/grpc/datadog_interceptor.rb b/lib/datadog/tracing/contrib/grpc/datadog_interceptor.rb index d85095b5599..f3158746471 100644 --- a/lib/datadog/tracing/contrib/grpc/datadog_interceptor.rb +++ b/lib/datadog/tracing/contrib/grpc/datadog_interceptor.rb @@ -52,10 +52,6 @@ def analytics_enabled? Contrib::Analytics.enabled?(datadog_configuration[:analytics_enabled]) end - def distributed_tracing? - Datadog.configuration_for(self, :distributed_tracing) || datadog_configuration[:distributed_tracing] - end - def analytics_sample_rate datadog_configuration[:analytics_sample_rate] end diff --git a/lib/datadog/tracing/contrib/grpc/datadog_interceptor/client.rb b/lib/datadog/tracing/contrib/grpc/datadog_interceptor/client.rb index eac66872a2b..17c32232381 100644 --- a/lib/datadog/tracing/contrib/grpc/datadog_interceptor/client.rb +++ b/lib/datadog/tracing/contrib/grpc/datadog_interceptor/client.rb @@ -81,7 +81,14 @@ def annotate!(trace, span, keywords, formatter) # Set analytics sample rate Contrib::Analytics.set_sample_rate(span, analytics_sample_rate) if analytics_enabled? - GRPC.inject(trace, metadata) if distributed_tracing? + trace.sampling_priority = Tracing::Sampling::Ext::Priority::AUTO_REJECT if trace.non_billing_reject? + + unless Tracing::Distributed::Helpers.should_skip_distributed_tracing?( + datadog_configuration, + client_config: Datadog.configuration_for(self) + ) + GRPC.inject(trace, metadata) + end Contrib::SpanAttributeSchema.set_peer_service!(span, Ext::PEER_SERVICE_SOURCES) rescue StandardError => e Datadog.logger.debug("GRPC client trace failed: #{e}") diff --git a/lib/datadog/tracing/contrib/http/circuit_breaker.rb b/lib/datadog/tracing/contrib/http/circuit_breaker.rb index d35ceda5a3e..11f1db27d65 100644 --- a/lib/datadog/tracing/contrib/http/circuit_breaker.rb +++ b/lib/datadog/tracing/contrib/http/circuit_breaker.rb @@ -27,21 +27,6 @@ def internal_request?(request) !!(request[Datadog::Core::Transport::Ext::HTTP::HEADER_META_TRACER_VERSION] || request[Datadog::Core::Transport::Ext::HTTP::HEADER_DD_INTERNAL_UNTRACED_REQUEST]) end - - def should_skip_distributed_tracing?(client_config) - if Datadog.configuration.appsec.standalone.enabled - # Skip distributed tracing so that we don't bill distributed traces in case of absence of - # upstream ASM event (_dd.p.appsec:1) and no local security event (which sets _dd.p.appsec:1 locally). - # If there is an ASM event, we still have to check if distributed tracing is enabled or not - return true unless Tracing.active_trace - - return true if Tracing.active_trace.get_tag(Datadog::AppSec::Ext::TAG_DISTRIBUTED_APPSEC_EVENT) != '1' - end - - return !client_config[:distributed_tracing] if client_config && client_config.key?(:distributed_tracing) - - !Datadog.configuration.tracing[:http][:distributed_tracing] - end end end end diff --git a/lib/datadog/tracing/contrib/http/instrumentation.rb b/lib/datadog/tracing/contrib/http/instrumentation.rb index b913a7d41dd..d736e78c023 100644 --- a/lib/datadog/tracing/contrib/http/instrumentation.rb +++ b/lib/datadog/tracing/contrib/http/instrumentation.rb @@ -35,11 +35,15 @@ def request(req, body = nil, &block) span.type = Tracing::Metadata::Ext::HTTP::TYPE_OUTBOUND span.resource = req.method - if Datadog::AppSec::Utils::TraceOperation.appsec_standalone_reject?(trace) - trace.sampling_priority = Tracing::Sampling::Ext::Priority::AUTO_REJECT - end - - if Tracing.enabled? && !Contrib::HTTP.should_skip_distributed_tracing?(client_config) + trace.sampling_priority = Tracing::Sampling::Ext::Priority::AUTO_REJECT if trace.non_billing_reject? + + app_config = Datadog.configuration.tracing[:http] + if Tracing.enabled? && + !Tracing::Distributed::Helpers.should_skip_distributed_tracing?( + app_config, + client_config: client_config, + trace: trace + ) Contrib::HTTP.inject(trace, req) end diff --git a/lib/datadog/tracing/contrib/httpclient/instrumentation.rb b/lib/datadog/tracing/contrib/httpclient/instrumentation.rb index 15c218bf333..3a3e71b7d2d 100644 --- a/lib/datadog/tracing/contrib/httpclient/instrumentation.rb +++ b/lib/datadog/tracing/contrib/httpclient/instrumentation.rb @@ -30,11 +30,15 @@ def do_get_block(req, proxy, conn, &block) span.service = service_name(host, request_options, client_config) span.type = Tracing::Metadata::Ext::HTTP::TYPE_OUTBOUND - if Datadog::AppSec::Utils::TraceOperation.appsec_standalone_reject?(trace) - trace.sampling_priority = Tracing::Sampling::Ext::Priority::AUTO_REJECT - end - - if Tracing.enabled? && !should_skip_distributed_tracing?(client_config) + trace.sampling_priority = Tracing::Sampling::Ext::Priority::AUTO_REJECT if trace.non_billing_reject? + + app_config = Datadog.configuration.tracing[:httpclient] + if Tracing.enabled? && + !Tracing::Distributed::Helpers.should_skip_distributed_tracing?( + app_config, + client_config: client_config, + trace: trace + ) Contrib::HTTP.inject(trace, req.header) end @@ -123,12 +127,6 @@ def analytics_enabled?(request_options) Contrib::Analytics.enabled?(request_options[:analytics_enabled]) end - def should_skip_distributed_tracing?(client_config) - return !client_config[:distributed_tracing] if client_config && client_config.key?(:distributed_tracing) - - !Datadog.configuration.tracing[:httpclient][:distributed_tracing] - end - def set_analytics_sample_rate(span, request_options) return unless analytics_enabled?(request_options) diff --git a/lib/datadog/tracing/contrib/httprb/instrumentation.rb b/lib/datadog/tracing/contrib/httprb/instrumentation.rb index 7d0a11e7ff9..6e75a133500 100644 --- a/lib/datadog/tracing/contrib/httprb/instrumentation.rb +++ b/lib/datadog/tracing/contrib/httprb/instrumentation.rb @@ -30,12 +30,18 @@ def perform(req, options) span.service = service_name(host, request_options, client_config) span.type = Tracing::Metadata::Ext::HTTP::TYPE_OUTBOUND - if Datadog::AppSec::Utils::TraceOperation.appsec_standalone_reject?(trace) - trace.sampling_priority = Tracing::Sampling::Ext::Priority::AUTO_REJECT + trace.sampling_priority = Tracing::Sampling::Ext::Priority::AUTO_REJECT if trace.non_billing_reject? + + app_config = Datadog.configuration.tracing[:httprb] + if Tracing.enabled? && + !Tracing::Distributed::Helpers.should_skip_distributed_tracing?( + app_config, + client_config: client_config, + trace: trace + ) + Contrib::HTTP.inject(trace, req) end - Contrib::HTTP.inject(trace, req) if Tracing.enabled? && !should_skip_distributed_tracing?(client_config) - # Add additional request specific tags to the span. annotate_span_with_request!(span, req, request_options) rescue StandardError => e @@ -135,12 +141,6 @@ def logger Datadog.logger end - def should_skip_distributed_tracing?(client_config) - return !client_config[:distributed_tracing] if client_config && client_config.key?(:distributed_tracing) - - !Datadog.configuration.tracing[:httprb][:distributed_tracing] - end - def set_analytics_sample_rate(span, request_options) return unless analytics_enabled?(request_options) diff --git a/lib/datadog/tracing/contrib/rest_client/request_patch.rb b/lib/datadog/tracing/contrib/rest_client/request_patch.rb index 4f340c5356d..df0ee1ddf15 100644 --- a/lib/datadog/tracing/contrib/rest_client/request_patch.rb +++ b/lib/datadog/tracing/contrib/rest_client/request_patch.rb @@ -25,10 +25,11 @@ def execute(&block) return super(&block) unless Tracing.enabled? datadog_trace_request(uri) do |_span, trace| - if Datadog::AppSec::Utils::TraceOperation.appsec_standalone_reject?(trace) - trace.sampling_priority = Tracing::Sampling::Ext::Priority::AUTO_REJECT + trace.sampling_priority = Tracing::Sampling::Ext::Priority::AUTO_REJECT if trace.non_billing_reject? + + unless Tracing::Distributed::Helpers.should_skip_distributed_tracing?(datadog_configuration, trace: trace) + Contrib::HTTP.inject(trace, processed_headers) end - Contrib::HTTP.inject(trace, processed_headers) if datadog_configuration[:distributed_tracing] super(&block) end diff --git a/lib/datadog/tracing/contrib/sidekiq/client_tracer.rb b/lib/datadog/tracing/contrib/sidekiq/client_tracer.rb index f57fde8a101..c6643bed50d 100644 --- a/lib/datadog/tracing/contrib/sidekiq/client_tracer.rb +++ b/lib/datadog/tracing/contrib/sidekiq/client_tracer.rb @@ -24,7 +24,12 @@ def call(worker_class, job, queue, redis_pool) resource = job_resource(job) Datadog::Tracing.trace(Ext::SPAN_PUSH, service: @sidekiq_service) do |span, trace_op| - Sidekiq.inject(trace_op, job) if configuration[:distributed_tracing] + trace_op.sampling_priority = Tracing::Sampling::Ext::Priority::AUTO_REJECT if trace_op.non_billing_reject? + + if Tracing.enabled? && + !Tracing::Distributed::Helpers.should_skip_distributed_tracing?(configuration, trace: trace_op) + Sidekiq.inject(trace_op, job) + end span.resource = resource diff --git a/lib/datadog/tracing/distributed/helpers.rb b/lib/datadog/tracing/distributed/helpers.rb index 17bab2dfaaa..7d3667be445 100644 --- a/lib/datadog/tracing/distributed/helpers.rb +++ b/lib/datadog/tracing/distributed/helpers.rb @@ -59,6 +59,17 @@ def self.parse_hex_id(value) num end + + def self.should_skip_distributed_tracing?(app_config, client_config: nil, trace: nil) + if ::Datadog.configuration.tracing.non_billing.enabled + return true unless trace + return true if trace.non_billing_reject? + end + + return !client_config[:distributed_tracing] if client_config && client_config.key?(:distributed_tracing) + + !app_config[:distributed_tracing] + end end end end diff --git a/lib/datadog/tracing/metadata/ext.rb b/lib/datadog/tracing/metadata/ext.rb index 95cf3d4e7f0..3b80891d8f3 100644 --- a/lib/datadog/tracing/metadata/ext.rb +++ b/lib/datadog/tracing/metadata/ext.rb @@ -31,6 +31,9 @@ module Ext # See Datadog-internal "RFC: Identifying which spans have profiling enabled " for details TAG_PROFILING_ENABLED = '_dd.profiling.enabled' + # Set to '0' if 'non-billing' mode is enabled, not present otherwise. + TAG_APM_ENABLED = '_dd.apm.enabled' + # Defines constants for trace analytics # @public_api module Analytics diff --git a/lib/datadog/tracing/trace_operation.rb b/lib/datadog/tracing/trace_operation.rb index eb85182af75..7c54c2d5f77 100644 --- a/lib/datadog/tracing/trace_operation.rb +++ b/lib/datadog/tracing/trace_operation.rb @@ -71,6 +71,7 @@ def initialize( sampling_priority: nil, service: nil, profiling_enabled: nil, + non_billing_enabled: nil, tags: nil, metrics: nil, trace_state: nil, @@ -98,6 +99,7 @@ def initialize( @sampling_priority = sampling_priority @service = service @profiling_enabled = profiling_enabled + @non_billing_enabled = non_billing_enabled @trace_state = trace_state @trace_state_unknown_fields = trace_state_unknown_fields @tracer = tracer @@ -373,6 +375,14 @@ def fork_clone ) end + # When APM is running in 'non-billing' mode, we should skip distributed tracing + # unless specific distributed tags are present. These tags can come from upstream + # services, or from the service itself. + # For now, only '_dd.p.appsec=1' is supported. + def non_billing_reject? + @non_billing_enabled && get_tag(Datadog::AppSec::Ext::TAG_DISTRIBUTED_APPSEC_EVENT) != '1' + end + # Callback behavior class Events include Tracing::Events @@ -510,6 +520,7 @@ def build_trace(spans, partial = false) metrics: metrics, root_span_id: !partial ? root_span && root_span.id : nil, profiling_enabled: @profiling_enabled, + non_billing_enabled: @non_billing_enabled, ) end diff --git a/lib/datadog/tracing/trace_segment.rb b/lib/datadog/tracing/trace_segment.rb index 6d0903d9a9d..7e05c8122a1 100644 --- a/lib/datadog/tracing/trace_segment.rb +++ b/lib/datadog/tracing/trace_segment.rb @@ -34,7 +34,8 @@ class TraceSegment :sampling_decision_maker, :sampling_priority, :service, - :profiling_enabled + :profiling_enabled, + :non_billing_enabled # rubocop:disable Metrics/CyclomaticComplexity # rubocop:disable Metrics/PerceivedComplexity @@ -58,7 +59,8 @@ def initialize( service: nil, tags: nil, metrics: nil, - profiling_enabled: nil + profiling_enabled: nil, + non_billing_enabled: nil ) @id = id @root_span_id = root_span_id @@ -85,6 +87,7 @@ def initialize( @sampling_priority = sampling_priority || sampling_priority_tag @service = Core::Utils::SafeDup.frozen_or_dup(service || service_tag) @profiling_enabled = profiling_enabled + @non_billing_enabled = non_billing_enabled end # rubocop:enable Metrics/PerceivedComplexity # rubocop:enable Metrics/CyclomaticComplexity diff --git a/lib/datadog/tracing/tracer.rb b/lib/datadog/tracing/tracer.rb index a6da0e98199..5206bc7f99b 100644 --- a/lib/datadog/tracing/tracer.rb +++ b/lib/datadog/tracing/tracer.rb @@ -333,6 +333,7 @@ def build_trace(digest = nil) TraceOperation.new( hostname: hostname, profiling_enabled: profiling_enabled, + non_billing_enabled: non_billing_enabled, id: digest.trace_id, origin: digest.trace_origin, parent_span_id: digest.span_id, @@ -348,6 +349,7 @@ def build_trace(digest = nil) TraceOperation.new( hostname: hostname, profiling_enabled: profiling_enabled, + non_billing_enabled: non_billing_enabled, remote_parent: false, tracer: self ) @@ -541,6 +543,10 @@ def profiling_enabled @profiling_enabled ||= !!(defined?(Datadog::Profiling) && Datadog::Profiling.respond_to?(:enabled?) && Datadog::Profiling.enabled?) end + + def non_billing_enabled + @non_billing_enabled ||= Datadog.configuration.tracing.non_billing.enabled + end end end end diff --git a/lib/datadog/tracing/transport/http.rb b/lib/datadog/tracing/transport/http.rb index 190dc31e408..a3b953d0b77 100644 --- a/lib/datadog/tracing/transport/http.rb +++ b/lib/datadog/tracing/transport/http.rb @@ -75,7 +75,7 @@ def default_headers container_id = Datadog::Core::Environment::Container.container_id headers[Datadog::Core::Transport::Ext::HTTP::HEADER_CONTAINER_ID] = container_id unless container_id.nil? # Pretend that stats computation are already done by the client - if Datadog.configuration.appsec.standalone.enabled + if Datadog.configuration.tracing.non_billing.enabled headers[Datadog::Core::Transport::Ext::HTTP::HEADER_CLIENT_COMPUTED_STATS] = 'yes' end end diff --git a/lib/datadog/tracing/transport/trace_formatter.rb b/lib/datadog/tracing/transport/trace_formatter.rb index 2140ccebdd0..df634b46a32 100644 --- a/lib/datadog/tracing/transport/trace_formatter.rb +++ b/lib/datadog/tracing/transport/trace_formatter.rb @@ -59,6 +59,7 @@ def format! tag_high_order_trace_id! tag_sampling_priority! tag_profiling_enabled! + tag_non_billing_enabled! if first_span tag_git_repository_url! @@ -196,6 +197,14 @@ def tag_profiling_enabled! ) end + def tag_non_billing_enabled! + return unless trace.non_billing_enabled + + root_span.set_metric( + Tracing::Metadata::Ext::TAG_APM_ENABLED, 0 + ) + end + def tag_git_repository_url! return if git_repository_url.nil? diff --git a/sig/datadog/appsec/ext.rbs b/sig/datadog/appsec/ext.rbs index 2ac545ba1d3..94021af2f29 100644 --- a/sig/datadog/appsec/ext.rbs +++ b/sig/datadog/appsec/ext.rbs @@ -5,7 +5,6 @@ module Datadog SCOPE_KEY: String TAG_APPSEC_ENABLED: String - TAG_APM_ENABLED: String TAG_DISTRIBUTED_APPSEC_EVENT: String end end diff --git a/sig/datadog/appsec/utils/trace_operation.rbs b/sig/datadog/appsec/utils/trace_operation.rbs deleted file mode 100644 index cd7a86680a1..00000000000 --- a/sig/datadog/appsec/utils/trace_operation.rbs +++ /dev/null @@ -1,9 +0,0 @@ -module Datadog - module AppSec - module Utils - class TraceOperation - def self.appsec_standalone_reject?: (Datadog::Tracing::TraceOperation trace) -> bool - end - end - end -end diff --git a/sig/datadog/tracing/configuration/ext.rbs b/sig/datadog/tracing/configuration/ext.rbs index 01c18cd981f..80dc1bbe365 100644 --- a/sig/datadog/tracing/configuration/ext.rbs +++ b/sig/datadog/tracing/configuration/ext.rbs @@ -5,6 +5,7 @@ module Datadog ENV_ENABLED: "DD_TRACE_ENABLED" ENV_TRACE_ID_128_BIT_GENERATION_ENABLED: "DD_TRACE_128_BIT_TRACEID_GENERATION_ENABLED" + ENV_APM_ENABLED: "DD_EXPERIMENTAL_APPSEC_STANDALONE_ENABLED" # Temporary until RFC decides the final name module SpanAttributeSchema ENV_GLOBAL_DEFAULT_SERVICE_NAME_ENABLED: "DD_TRACE_REMOVE_INTEGRATION_SERVICE_NAMES_ENABLED" ENV_PEER_SERVICE_MAPPING: "DD_TRACE_PEER_SERVICE_MAPPING" diff --git a/sig/datadog/tracing/contrib/http/circuit_breaker.rbs b/sig/datadog/tracing/contrib/http/circuit_breaker.rbs index 62ecc351a8a..bc1a05213ff 100644 --- a/sig/datadog/tracing/contrib/http/circuit_breaker.rbs +++ b/sig/datadog/tracing/contrib/http/circuit_breaker.rbs @@ -5,8 +5,6 @@ module Datadog module CircuitBreaker def should_skip_tracing?: (untyped request) -> (true | false) def internal_request?: (untyped request) -> bool - - def should_skip_distributed_tracing?: (untyped client_config) -> untyped end end end diff --git a/sig/datadog/tracing/contrib/httpclient/instrumentation.rbs b/sig/datadog/tracing/contrib/httpclient/instrumentation.rbs index 44a3a3c40d2..ce0f5210536 100644 --- a/sig/datadog/tracing/contrib/httpclient/instrumentation.rbs +++ b/sig/datadog/tracing/contrib/httpclient/instrumentation.rbs @@ -23,8 +23,6 @@ module Datadog def logger: () -> untyped - def should_skip_distributed_tracing?: (untyped client_config) -> untyped - def set_analytics_sample_rate: (untyped span, untyped request_options) -> (nil | untyped) end end diff --git a/sig/datadog/tracing/contrib/httprb/instrumentation.rbs b/sig/datadog/tracing/contrib/httprb/instrumentation.rbs index 1fad4e2b94e..16a4ba2133f 100644 --- a/sig/datadog/tracing/contrib/httprb/instrumentation.rbs +++ b/sig/datadog/tracing/contrib/httprb/instrumentation.rbs @@ -23,8 +23,6 @@ module Datadog def logger: () -> untyped - def should_skip_distributed_tracing?: (untyped client_config) -> untyped - def set_analytics_sample_rate: (untyped span, untyped request_options) -> (nil | untyped) end end diff --git a/sig/datadog/tracing/metadata/ext.rbs b/sig/datadog/tracing/metadata/ext.rbs index 9820be2b123..d347c7abb48 100644 --- a/sig/datadog/tracing/metadata/ext.rbs +++ b/sig/datadog/tracing/metadata/ext.rbs @@ -8,6 +8,8 @@ module Datadog TAG_PEER_SERVICE: ::String TAG_KIND: ::String TAG_TOP_LEVEL: ::String + TAG_PROFILING_ENABLED: ::String + TAG_APM_ENABLED: ::String module Analytics DEFAULT_SAMPLE_RATE: ::Float diff --git a/sig/datadog/tracing/trace_operation.rbs b/sig/datadog/tracing/trace_operation.rbs index e434c9872d6..336b5902410 100644 --- a/sig/datadog/tracing/trace_operation.rbs +++ b/sig/datadog/tracing/trace_operation.rbs @@ -23,7 +23,7 @@ module Datadog attr_writer sampled: untyped attr_writer service: untyped - def initialize: (?agent_sample_rate: untyped?, ?events: untyped?, ?hostname: untyped?, ?id: untyped?, ?max_length: untyped, ?name: untyped?, ?origin: untyped?, ?parent_span_id: untyped?, ?rate_limiter_rate: untyped?, ?resource: untyped?, ?rule_sample_rate: untyped?, ?sample_rate: untyped?, ?sampled: untyped?, ?sampling_priority: untyped?, ?service: untyped?, ?tags: untyped?, ?metrics: untyped?, ?remote_parent: untyped?) -> void + def initialize: (?agent_sample_rate: untyped?, ?events: untyped?, ?hostname: untyped?, ?id: untyped?, ?max_length: untyped, ?name: untyped?, ?origin: untyped?, ?parent_span_id: untyped?, ?rate_limiter_rate: untyped?, ?resource: untyped?, ?rule_sample_rate: untyped?, ?sample_rate: untyped?, ?sampled: untyped?, ?sampling_priority: untyped?, ?service: untyped?, ?profiling_enabled: bool?, ?non_billing_enabled: bool?, ?tags: untyped?, ?metrics: untyped?, ?remote_parent: untyped?) -> void def full?: () -> untyped def finished_span_count: () -> untyped def finished?: () -> untyped @@ -40,6 +40,7 @@ module Datadog def flush!: () { (untyped) -> untyped } -> untyped def to_digest: () -> untyped def fork_clone: () -> untyped + def non_billing_reject?: () -> bool class Events include Tracing::Events diff --git a/sig/datadog/tracing/trace_segment.rbs b/sig/datadog/tracing/trace_segment.rbs index 41f81d3114f..8c6702d8bae 100644 --- a/sig/datadog/tracing/trace_segment.rbs +++ b/sig/datadog/tracing/trace_segment.rbs @@ -21,8 +21,10 @@ module Datadog attr_reader sampling_decision_maker: untyped attr_reader sampling_priority: untyped attr_reader service: untyped + attr_reader profiling_enabled: bool + attr_reader non_billing_enabled: bool - def initialize: (untyped spans, ?agent_sample_rate: untyped?, ?hostname: untyped?, ?id: untyped?, ?lang: untyped?, ?name: untyped?, ?origin: untyped?, ?process_id: untyped?, ?rate_limiter_rate: untyped?, ?resource: untyped?, ?root_span_id: untyped?, ?rule_sample_rate: untyped?, ?runtime_id: untyped?, ?sample_rate: untyped?, ?sampling_priority: untyped?, ?service: untyped?, ?tags: untyped?, ?metrics: untyped?) -> void + def initialize: (untyped spans, ?agent_sample_rate: untyped?, ?hostname: untyped?, ?id: untyped?, ?lang: untyped?, ?name: untyped?, ?origin: untyped?, ?process_id: untyped?, ?rate_limiter_rate: untyped?, ?resource: untyped?, ?root_span_id: untyped?, ?rule_sample_rate: untyped?, ?runtime_id: untyped?, ?sample_rate: untyped?, ?sampling_priority: untyped?, ?service: untyped?, ?tags: untyped?, ?metrics: untyped?, ?profiling_enabled: bool?, ?non_billing_enabled: bool?) -> void def any?: () -> untyped def count: () -> untyped def empty?: () -> untyped diff --git a/sig/datadog/tracing/tracer.rbs b/sig/datadog/tracing/tracer.rbs index a642e3cb7ab..6755c6200dd 100644 --- a/sig/datadog/tracing/tracer.rbs +++ b/sig/datadog/tracing/tracer.rbs @@ -6,6 +6,10 @@ module Datadog def active_span: (?untyped? key) -> Datadog::Tracing::Span def active_correlation: (?untyped? key) -> Struct[untyped] # Datadog::Correlation::Identifier + + private + + def non_billing_enabled: () -> bool end end end diff --git a/sig/datadog/tracing/transport/trace_formatter.rbs b/sig/datadog/tracing/transport/trace_formatter.rbs index cb8e14c6987..1ea75edf8cb 100644 --- a/sig/datadog/tracing/transport/trace_formatter.rbs +++ b/sig/datadog/tracing/transport/trace_formatter.rbs @@ -41,6 +41,10 @@ module Datadog def tag_sampling_priority!: () -> (nil | untyped) def tag_high_order_trace_id!: () -> (nil | untyped) + + def tag_profiling_enabled!: () -> (nil | untyped) + + def tag_non_billing_enabled!: () -> (nil | untyped) def tag_git_repository_url!: () -> (nil | untyped) diff --git a/spec/datadog/appsec/configuration/settings_spec.rb b/spec/datadog/appsec/configuration/settings_spec.rb index 3d8115bc3fc..a19a0a94550 100644 --- a/spec/datadog/appsec/configuration/settings_spec.rb +++ b/spec/datadog/appsec/configuration/settings_spec.rb @@ -757,45 +757,5 @@ def patcher end end end - - describe 'standalone' do - describe '#enabled' do - subject(:enabled) { settings.appsec.standalone.enabled } - - context 'when DD_EXPERIMENTAL_APPSEC_STANDALONE_ENABLED' do - around do |example| - ClimateControl.modify('DD_EXPERIMENTAL_APPSEC_STANDALONE_ENABLED' => appsec_standalone_enabled) do - example.run - end - end - - context 'is not defined' do - let(:appsec_standalone_enabled) { nil } - - it { is_expected.to eq false } - end - - context 'is defined' do - let(:appsec_standalone_enabled) { 'true' } - - it { is_expected.to eq(true) } - end - end - end - - describe '#enabled=' do - subject(:set_appsec_standalone_enabled) { settings.appsec.standalone.enabled = appsec_standalone_enabled } - - [true, false].each do |value| - context "when given #{value}" do - let(:appsec_standalone_enabled) { value } - - before { set_appsec_standalone_enabled } - - it { expect(settings.appsec.standalone.enabled).to eq(value) } - end - end - end - end end end diff --git a/spec/datadog/appsec/contrib/rack/integration_test_spec.rb b/spec/datadog/appsec/contrib/rack/integration_test_spec.rb index 325541ed0b1..42f32893264 100644 --- a/spec/datadog/appsec/contrib/rack/integration_test_spec.rb +++ b/spec/datadog/appsec/contrib/rack/integration_test_spec.rb @@ -46,7 +46,7 @@ let(:tracing_enabled) { true } let(:appsec_enabled) { true } - let(:appsec_standalone_enabled) { false } + let(:tracing_non_billing_enabled) { false } let(:remote_enabled) { false } let(:appsec_ip_passlist) { [] } let(:appsec_ip_denylist) { [] } @@ -194,7 +194,7 @@ c.appsec.instrument :rack - c.appsec.standalone.enabled = appsec_standalone_enabled + c.tracing.non_billing.enabled = tracing_non_billing_enabled c.appsec.waf_timeout = 10_000_000 # in us c.appsec.ip_passlist = appsec_ip_passlist c.appsec.ip_denylist = appsec_ip_denylist diff --git a/spec/datadog/appsec/contrib/rails/integration_test_spec.rb b/spec/datadog/appsec/contrib/rails/integration_test_spec.rb index b564e477c9f..c0d58dff871 100644 --- a/spec/datadog/appsec/contrib/rails/integration_test_spec.rb +++ b/spec/datadog/appsec/contrib/rails/integration_test_spec.rb @@ -62,7 +62,7 @@ let(:appsec_instrument_rack) { false } - let(:appsec_standalone_enabled) { false } + let(:tracing_non_billing_enabled) { false } let(:appsec_ip_denylist) { [] } let(:appsec_user_id_denylist) { [] } let(:appsec_ruleset) { :recommended } @@ -154,7 +154,7 @@ c.appsec.instrument :rails c.appsec.instrument :rack if appsec_instrument_rack - c.appsec.standalone.enabled = appsec_standalone_enabled + c.tracing.non_billing.enabled = tracing_non_billing_enabled c.appsec.waf_timeout = 10_000_000 # in us c.appsec.ip_denylist = appsec_ip_denylist c.appsec.user_id_denylist = appsec_user_id_denylist diff --git a/spec/datadog/appsec/contrib/sinatra/integration_test_spec.rb b/spec/datadog/appsec/contrib/sinatra/integration_test_spec.rb index e9f25a12b15..98248e0673e 100644 --- a/spec/datadog/appsec/contrib/sinatra/integration_test_spec.rb +++ b/spec/datadog/appsec/contrib/sinatra/integration_test_spec.rb @@ -72,7 +72,7 @@ let(:tracing_enabled) { true } let(:appsec_enabled) { true } - let(:appsec_standalone_enabled) { false } + let(:tracing_non_billing_enabled) { false } let(:appsec_ip_denylist) { [] } let(:appsec_user_id_denylist) { [] } let(:appsec_ruleset) { :recommended } @@ -161,7 +161,7 @@ c.appsec.instrument :sinatra # TODO: test with c.appsec.instrument :rack - c.appsec.standalone.enabled = appsec_standalone_enabled + c.tracing.non_billing.enabled = tracing_non_billing_enabled c.appsec.waf_timeout = 10_000_000 # in us c.appsec.ip_denylist = appsec_ip_denylist c.appsec.user_id_denylist = appsec_user_id_denylist diff --git a/spec/datadog/appsec/contrib/support/integration/shared_examples.rb b/spec/datadog/appsec/contrib/support/integration/shared_examples.rb index bcf82aaa8aa..43470856d81 100644 --- a/spec/datadog/appsec/contrib/support/integration/shared_examples.rb +++ b/spec/datadog/appsec/contrib/support/integration/shared_examples.rb @@ -220,7 +220,7 @@ RSpec.shared_examples 'appsec standalone billing' do subject(:response) { get url, params, env } - let(:appsec_standalone_enabled) { true } + let(:tracing_non_billing_enabled) { true } let(:url) { '/requestdownstream' } let(:params) { {} } diff --git a/spec/datadog/appsec/utils/trace_operation_spec.rb b/spec/datadog/appsec/utils/trace_operation_spec.rb deleted file mode 100644 index 15692054506..00000000000 --- a/spec/datadog/appsec/utils/trace_operation_spec.rb +++ /dev/null @@ -1,40 +0,0 @@ -require 'datadog/appsec/spec_helper' -require 'datadog/appsec/utils/trace_operation' - -RSpec.describe Datadog::AppSec::Utils::TraceOperation do - describe '#appsec_standalone_reject?' do - subject(:appsec_standalone_reject?) do - described_class.appsec_standalone_reject?(trace_op) - end - - let(:trace_op) { Datadog::Tracing::TraceOperation.new(**options) } - let(:options) { {} } - let(:appsec_standalone) { false } - let(:distributed_appsec_event) { '0' } - - before do - allow(Datadog.configuration.appsec.standalone).to receive(:enabled).and_return(appsec_standalone) - trace_op.set_tag(Datadog::AppSec::Ext::TAG_DISTRIBUTED_APPSEC_EVENT, distributed_appsec_event) if trace_op - end - - it { is_expected.to be false } - - context 'when AppSec standalone is enabled' do - let(:appsec_standalone) { true } - - it { is_expected.to be true } - - context 'without a trace' do - let(:trace_op) { nil } - - it { is_expected.to be true } - end - - context 'with a distributed AppSec event' do - let(:distributed_appsec_event) { '1' } - - it { is_expected.to be false } - end - end - end -end diff --git a/spec/datadog/core/remote/transport/http_spec.rb b/spec/datadog/core/remote/transport/http_spec.rb index 077d0cc6d98..4dd2957420b 100644 --- a/spec/datadog/core/remote/transport/http_spec.rb +++ b/spec/datadog/core/remote/transport/http_spec.rb @@ -75,7 +75,7 @@ it { expect(transport.client.api.headers).to_not include('Datadog-Client-Computed-Stats') } context 'with ASM standalone enabled' do - before { expect(Datadog.configuration.appsec.standalone).to receive(:enabled).and_return(true) } + before { expect(Datadog.configuration.tracing.non_billing).to receive(:enabled).and_return(true) } it { expect(transport.client.api.headers['Datadog-Client-Computed-Stats']).to eq('yes') } end @@ -213,8 +213,8 @@ it { expect(transport.client.api.headers).to_not include('Datadog-Client-Computed-Stats') } - context 'with ASM standalone enabled' do - before { expect(Datadog.configuration.appsec.standalone).to receive(:enabled).and_return(true) } + context 'with non-billing mode enabled' do + before { expect(Datadog.configuration.tracing.non_billing).to receive(:enabled).and_return(true) } it { expect(transport.client.api.headers['Datadog-Client-Computed-Stats']).to eq('yes') } end diff --git a/spec/datadog/tracing/configuration/settings_spec.rb b/spec/datadog/tracing/configuration/settings_spec.rb index ff94d55e670..545374ada52 100644 --- a/spec/datadog/tracing/configuration/settings_spec.rb +++ b/spec/datadog/tracing/configuration/settings_spec.rb @@ -351,6 +351,49 @@ def propagation_style_inject end end + describe 'non_billing' do + describe '#enabled' do + subject(:enabled) { settings.tracing.non_billing.enabled } + + it { is_expected.to be false } + + context 'when DD_EXPERIMENTAL_APPSEC_STANDALONE_ENABLED' do + around do |example| + ClimateControl.modify('DD_EXPERIMENTAL_APPSEC_STANDALONE_ENABLED' => appsec_standalone_enabled) do + example.run + end + end + + context 'is not defined' do + let(:appsec_standalone_enabled) { nil } + + it { is_expected.to eq false } + end + + context 'is set to true' do + let(:appsec_standalone_enabled) { 'true' } + + it { is_expected.to be true } + end + + context 'is set to false' do + let(:appsec_standalone_enabled) { 'false' } + + it { is_expected.to be false } + end + end + end + + describe '#enabled=' do + it 'updates the #enabled setting' do + expect { settings.tracing.non_billing.enabled = true } + .to change { settings.tracing.non_billing.enabled } + .from(false) + .to(true) + end + end + end + describe '#header_tags' do subject(:header_tags) { settings.tracing.header_tags } diff --git a/spec/datadog/tracing/contrib/ethon/easy_patch_spec.rb b/spec/datadog/tracing/contrib/ethon/easy_patch_spec.rb index f1ad802e935..07f00873871 100644 --- a/spec/datadog/tracing/contrib/ethon/easy_patch_spec.rb +++ b/spec/datadog/tracing/contrib/ethon/easy_patch_spec.rb @@ -115,6 +115,17 @@ it_behaves_like 'environment service name', 'DD_TRACE_ETHON_SERVICE_NAME' do let(:span) { span_op } end + + context 'with non-billing mode' do + before do + allow_any_instance_of(Datadog::Tracing::TraceOperation).to receive(:non_billing_reject?).and_return(true) + end + + it do + subject + expect(Datadog::Tracing.active_trace.sampling_priority).to eq(0) + end + end end describe '#complete' do diff --git a/spec/datadog/tracing/contrib/excon/instrumentation_spec.rb b/spec/datadog/tracing/contrib/excon/instrumentation_spec.rb index 411abc43d8e..5d1374791e3 100644 --- a/spec/datadog/tracing/contrib/excon/instrumentation_spec.rb +++ b/spec/datadog/tracing/contrib/excon/instrumentation_spec.rb @@ -364,6 +364,31 @@ end end + context 'with non-billing mode' do + subject!(:response) do + expect_any_instance_of(described_class).to receive(:request_call) + .and_wrap_original do |m, *args| + allow_any_instance_of(Datadog::Tracing::TraceOperation).to receive(:non_billing_reject?).and_return(true) + m.call(*args).tap do |datum| + # Assert request headers + span = datum[:datadog_span] + headers = datum[:headers] + expect(headers).to include( + 'x-datadog-trace-id' => low_order_trace_id(span.trace_id).to_s, + 'x-datadog-parent-id' => span.id.to_s, + 'x-datadog-sampling-priority' => '0' + ) + end + end + + connection.get(path: '/success') + end + + it do + subject + end + end + context 'global service name' do subject(:get) { connection.get(path: '/success') } diff --git a/spec/datadog/tracing/contrib/faraday/middleware_spec.rb b/spec/datadog/tracing/contrib/faraday/middleware_spec.rb index 808d4e8cd82..8c27b0fb3b7 100644 --- a/spec/datadog/tracing/contrib/faraday/middleware_spec.rb +++ b/spec/datadog/tracing/contrib/faraday/middleware_spec.rb @@ -410,6 +410,25 @@ end end + context 'when non-billing mode is enabled' do + subject(:response) { client.get('/success') } + + before do + Datadog.configure do |c| + c.tracing.non_billing.enabled = true + end + # This cannot happen in actual apps but we do this to + # verify that sampling priority is set to 0 through distributed tracing without mocking an agent + allow(Datadog::Tracing::Distributed::Helpers).to receive(:should_skip_distributed_tracing?).and_return(false) + end + + let(:headers) { response.env.request_headers } + + it do + expect(headers).to include('x-datadog-sampling-priority' => '0') + end + end + context 'global service name' do let(:service_name) { 'faraday-global' } diff --git a/spec/datadog/tracing/contrib/grpc/datadog_interceptor/client_spec.rb b/spec/datadog/tracing/contrib/grpc/datadog_interceptor/client_spec.rb index de8b3926be3..aa69f4b07fe 100644 --- a/spec/datadog/tracing/contrib/grpc/datadog_interceptor/client_spec.rb +++ b/spec/datadog/tracing/contrib/grpc/datadog_interceptor/client_spec.rb @@ -17,10 +17,19 @@ let(:peer) { "#{host}:#{port}" } let(:host) { 'host.name' } let(:port) { 0 } + let(:tracing_non_billing_enabled) { false } + let(:force_execute_distributed_tracing) { false } before do Datadog.configure do |c| c.tracing.instrument :grpc, configuration_options + c.tracing.non_billing.enabled = tracing_non_billing_enabled + end + + if force_execute_distributed_tracing + # This cannot happen in actual apps but we do this to + # verify that sampling priority is set to 0 through distributed tracing without mocking an agent + allow(Datadog::Tracing::Distributed::Helpers).to receive(:should_skip_distributed_tracing?).and_return(false) end end @@ -117,6 +126,20 @@ it 'injects distribution data in gRPC metadata' do expect(keywords[:metadata].keys).to include('x-datadog-trace-id', 'x-datadog-parent-id', 'x-datadog-tags') end + + context 'with non-billing mode' do + # We cannot get the trace as it is sent and flushed. + # But we can verify non-billing mode through distributed tracing + + # Not sure why, putting a before block here has no effect + let(:tracing_non_billing_enabled) { true } + let(:force_execute_distributed_tracing) { true } + + it { + expect(keywords[:metadata].keys).to include('x-datadog-sampling-priority') + expect(keywords[:metadata]['x-datadog-sampling-priority']).to eq('0') + } + end end end diff --git a/spec/datadog/tracing/contrib/http/circuit_breaker_spec.rb b/spec/datadog/tracing/contrib/http/circuit_breaker_spec.rb index 851ccddb86d..4d656c7ed87 100644 --- a/spec/datadog/tracing/contrib/http/circuit_breaker_spec.rb +++ b/spec/datadog/tracing/contrib/http/circuit_breaker_spec.rb @@ -91,68 +91,4 @@ end end end - - describe '#should_skip_distributed_tracing?' do - subject(:should_skip_distributed_tracing?) { circuit_breaker.should_skip_distributed_tracing?(client_config) } - - let(:client_config) { nil } - let(:distributed_tracing) { true } - let(:appsec_standalone) { false } - let(:active_trace) { nil } - let(:distributed_appsec_event) { nil } - - before do - allow(Datadog.configuration.tracing[:http]).to receive(:[]).with(:distributed_tracing).and_return(distributed_tracing) - allow(Datadog.configuration.appsec.standalone).to receive(:enabled).and_return(appsec_standalone) - allow(Datadog::Tracing).to receive(:active_trace).and_return(active_trace) - allow(active_trace).to receive(:get_tag).with('_dd.p.appsec').and_return(distributed_appsec_event) if active_trace - end - - context 'when distributed tracing is enabled' do - it { is_expected.to be false } - end - - context 'when distributed tracing is disabled' do - let(:distributed_tracing) { false } - - it { is_expected.to be true } - end - - context 'when appsec standalone is enabled' do - let(:appsec_standalone) { true } - - context 'when there is no active trace' do - it { is_expected.to be true } - end - - context 'when there is an active trace' do - let(:active_trace) { instance_double(Datadog::Tracing::TraceOperation) } - - context 'when the active trace has no distributed appsec event' do - it { is_expected.to be true } - end - - context 'when the active trace has a distributed appsec event' do - # This should act like standalone appsec is disabled, as it does not return in the - # `if Datadog.configuration.appsec.standalone.enabled` block - # so we're only testing the "no client config, distributed tracing enabled" case here - let(:distributed_appsec_event) { '1' } - - it { is_expected.to be false } - end - end - end - - context 'given a client config with distributed_tracing disabled' do - let(:client_config) { { distributed_tracing: false } } - - it { is_expected.to be true } - end - - context 'given a client config with distributed_tracing enabled' do - let(:client_config) { { distributed_tracing: true } } - - it { is_expected.to be false } - end - end end diff --git a/spec/datadog/tracing/contrib/httpclient/instrumentation_spec.rb b/spec/datadog/tracing/contrib/httpclient/instrumentation_spec.rb index 4405748fbac..fa1baa821ce 100644 --- a/spec/datadog/tracing/contrib/httpclient/instrumentation_spec.rb +++ b/spec/datadog/tracing/contrib/httpclient/instrumentation_spec.rb @@ -233,6 +233,21 @@ it 'propogrates the trace id header' do expect(http_response.headers['X-Datadog-Trace-Id']).to eq(low_order_trace_id(span.trace_id).to_s) end + + context 'with non-billing mode' do + before do + Datadog.configure do |c| + c.tracing.non_billing.enabled = true + end + # This cannot happen in actual apps but we do this to + # verify that sampling priority is set to 0 through distributed tracing without mocking an agent + allow(Datadog::Tracing::Distributed::Helpers).to receive(:should_skip_distributed_tracing?).and_return(false) + end + + it 'propagates sampling priority with value 0' do + expect(response.headers['X-Datadog-Sampling-Priority']).to eq('0') + end + end end context 'distributed tracing disabled' do diff --git a/spec/datadog/tracing/contrib/httprb/instrumentation_spec.rb b/spec/datadog/tracing/contrib/httprb/instrumentation_spec.rb index 485c599fa53..dec406de442 100644 --- a/spec/datadog/tracing/contrib/httprb/instrumentation_spec.rb +++ b/spec/datadog/tracing/contrib/httprb/instrumentation_spec.rb @@ -236,6 +236,21 @@ it 'propagates the trace id header' do expect(http_response.headers['x-datadog-trace-id']).to eq(low_order_trace_id(span.trace_id).to_s) end + + context 'with non-billing mode' do + before do + Datadog.configure do |c| + c.tracing.non_billing.enabled = true + end + # This cannot happen in actual apps but we do this to + # verify that sampling priority is set to 0 without mocking an agent + allow(Datadog::Tracing::Distributed::Helpers).to receive(:should_skip_distributed_tracing?).and_return(false) + end + + it 'propagates sampling priority with value 0' do + expect(response.headers['X-Datadog-Sampling-Priority']).to eq('0') + end + end end context 'distributed tracing disabled' do diff --git a/spec/datadog/tracing/contrib/rest_client/request_patch_spec.rb b/spec/datadog/tracing/contrib/rest_client/request_patch_spec.rb index 889363cf201..e5f59ff812e 100644 --- a/spec/datadog/tracing/contrib/rest_client/request_patch_spec.rb +++ b/spec/datadog/tracing/contrib/rest_client/request_patch_spec.rb @@ -328,6 +328,22 @@ .to have_been_made end end + + context 'with non-billing mode' do + before do + Datadog.configure do |c| + c.tracing.non_billing.enabled = true + end + # This cannot happen in actual apps but we do this to + # verify that sampling priority is set to 0 through distributed tracing without mocking an agent + allow(Datadog::Tracing::Distributed::Helpers).to receive(:should_skip_distributed_tracing?).and_return(false) + end + + it 'propagates sampling priority with value 0' do + request + expect(a_request(:get, url).with(headers: { 'X-Datadog-Sampling-Priority' => '0' })).to have_been_made + end + end end context 'distributed tracing disabled' do diff --git a/spec/datadog/tracing/contrib/sidekiq/distributed_tracing_spec.rb b/spec/datadog/tracing/contrib/sidekiq/distributed_tracing_spec.rb index 15d7575585b..28f43d085eb 100644 --- a/spec/datadog/tracing/contrib/sidekiq/distributed_tracing_spec.rb +++ b/spec/datadog/tracing/contrib/sidekiq/distributed_tracing_spec.rb @@ -63,6 +63,25 @@ def perform; end expect(job['x-datadog-tags']).to eq("_dd.p.dm=-0,_dd.p.tid=#{high_order_hex_trace_id(span.trace_id)}") expect(job).not_to include 'x-datadog-origin' end + + context 'with non-billing mode' do + before do + Datadog.configure do |c| + c.tracing.non_billing.enabled = true + end + # This cannot happen in actual apps but we do this to + # verify that sampling priority is set to 0 through distributed tracing without mocking an agent + allow(Datadog::Tracing::Distributed::Helpers).to receive(:should_skip_distributed_tracing?).and_return(false) + end + + it 'propagates sampling priority with value 0' do + EmptyWorker.perform_async + + job = EmptyWorker.jobs.first + + expect(job['x-datadog-sampling-priority']).to eq('0') + end + end end context 'when receiving' do diff --git a/spec/datadog/tracing/trace_operation_spec.rb b/spec/datadog/tracing/trace_operation_spec.rb index d168a99f73c..a5d3244e120 100644 --- a/spec/datadog/tracing/trace_operation_spec.rb +++ b/spec/datadog/tracing/trace_operation_spec.rb @@ -2579,6 +2579,35 @@ def span end end + describe '#non_billing_reject?' do + subject(:non_billing_reject?) do + trace_op.non_billing_reject? + end + + let(:trace_op) { described_class.new(**options) } + let(:options) { { non_billing_enabled: non_billing_enabled } } + let(:non_billing_enabled) { false } + let(:distributed_appsec_event) { '0' } + + before do + trace_op.set_tag(Datadog::AppSec::Ext::TAG_DISTRIBUTED_APPSEC_EVENT, distributed_appsec_event) + end + + it { is_expected.to be false } + + context 'when non-billing is enabled' do + let(:non_billing_enabled) { true } + + it { is_expected.to be true } + + context 'with a distributed AppSec event' do + let(:distributed_appsec_event) { '1' } + + it { is_expected.to be false } + end + end + end + describe 'integration tests' do context 'service_entry attributes' do context 'when service not given' do diff --git a/spec/datadog/tracing/transport/http_spec.rb b/spec/datadog/tracing/transport/http_spec.rb index f7af5db609c..20803a23978 100644 --- a/spec/datadog/tracing/transport/http_spec.rb +++ b/spec/datadog/tracing/transport/http_spec.rb @@ -181,17 +181,19 @@ end end - context 'when Datadog.configuration.appsec.standalone.enabled' do - before { expect(Datadog.configuration.appsec.standalone).to receive(:enabled).and_return(asm_standalone_enabled) } + context 'when Datadog.configuration.tracing.non_billing.enabled' do + before do + expect(Datadog.configuration.tracing.non_billing).to receive(:enabled).and_return(tracing_non_billing_enabled) + end context 'is true' do - let(:asm_standalone_enabled) { true } + let(:tracing_non_billing_enabled) { true } it { is_expected.to include(Datadog::Core::Transport::Ext::HTTP::HEADER_CLIENT_COMPUTED_STATS => 'yes') } end context 'is false' do - let(:asm_standalone_enabled) { false } + let(:tracing_non_billing_enabled) { false } it { is_expected.to_not include(Datadog::Core::Transport::Ext::HTTP::HEADER_CLIENT_COMPUTED_STATS) } end