diff --git a/lib/datadog/core/configuration/ext.rb b/lib/datadog/core/configuration/ext.rb index eacbbded6d0..3300213da2d 100644 --- a/lib/datadog/core/configuration/ext.rb +++ b/lib/datadog/core/configuration/ext.rb @@ -3,6 +3,8 @@ module Datadog module Core module Configuration + # Constants for configuration settings + # e.g. Env vars, default values, enums, etc... module Ext # @public_api module Diagnostics diff --git a/lib/datadog/core/configuration/settings.rb b/lib/datadog/core/configuration/settings.rb index 1e8c1be3360..6e90dba52fb 100644 --- a/lib/datadog/core/configuration/settings.rb +++ b/lib/datadog/core/configuration/settings.rb @@ -8,18 +8,22 @@ require_relative '../runtime/ext' require_relative '../telemetry/ext' require_relative '../../profiling/ext' -require_relative '../../tracing/configuration/ext' + +require_relative '../../tracing/configuration/settings' module Datadog module Core module Configuration - # Global configuration settings for the trace library. + # Global configuration settings for the Datadog library. # @public_api # rubocop:disable Metrics/BlockLength - # rubocop:disable Layout/LineLength class Settings include Base + # TODO: Tracing should manage its own settings. + # Keep this extension here for now to keep things working. + extend Datadog::Tracing::Configuration::Settings + # @!visibility private def initialize(*_) super @@ -408,372 +412,6 @@ def initialize(*_) end end - # Tracer specific configurations. - # @public_api - settings :tracing do - # Legacy [App Analytics](https://docs.datadoghq.com/tracing/legacy_app_analytics/) configuration. - # - # @configure_with {Datadog::Tracing} - # @deprecated Use [Trace Retention and Ingestion](https://docs.datadoghq.com/tracing/trace_retention_and_ingestion/) - # controls. - # @public_api - settings :analytics do - # @default `DD_TRACE_ANALYTICS_ENABLED` environment variable, otherwise `nil` - # @return [Boolean,nil] - option :enabled do |o| - o.default { env_to_bool(Tracing::Configuration::Ext::Analytics::ENV_TRACE_ANALYTICS_ENABLED, nil) } - o.lazy - end - end - - # [Distributed Tracing](https://docs.datadoghq.com/tracing/setup_overview/setup/ruby/#distributed-tracing) propagation - # style configuration. - # - # The supported formats are: - # * `Datadog`: Datadog propagation format, described by [Distributed Tracing](https://docs.datadoghq.com/tracing/setup_overview/setup/ruby/#distributed-tracing). - # * `b3multi`: B3 Propagation using multiple headers, described by [openzipkin/b3-propagation](https://github.com/openzipkin/b3-propagation#multiple-headers). - # * `b3`: B3 Propagation using a single header, described by [openzipkin/b3-propagation](https://github.com/openzipkin/b3-propagation#single-header). - # - # @public_api - settings :distributed_tracing do - # An ordered list of what data propagation styles the tracer will use to extract distributed tracing propagation - # data from incoming requests and messages. - # - # The tracer will try to find distributed headers in the order they are present in the list provided to this option. - # The first format to have valid data present will be used. - # - # @default `DD_TRACE_PROPAGATION_STYLE_EXTRACT` environment variable (comma-separated list), - # otherwise `['Datadog','b3multi','b3']`. - # @return [Array] - option :propagation_extract_style do |o| - o.default do - # DEV-2.0: Change default value to `tracecontext, Datadog`. - # Look for all headers by default - env_to_list( - [Tracing::Configuration::Ext::Distributed::ENV_PROPAGATION_STYLE_EXTRACT, - Tracing::Configuration::Ext::Distributed::ENV_PROPAGATION_STYLE_EXTRACT_OLD], - [ - Tracing::Configuration::Ext::Distributed::PROPAGATION_STYLE_DATADOG, - Tracing::Configuration::Ext::Distributed::PROPAGATION_STYLE_B3_MULTI_HEADER, - Tracing::Configuration::Ext::Distributed::PROPAGATION_STYLE_B3_SINGLE_HEADER - ], - comma_separated_only: true - ) - end - - o.on_set do |styles| - # Modernize B3 options - # DEV-2.0: Can be removed with the removal of deprecated B3 constants. - styles.map! do |style| - case style - when Tracing::Configuration::Ext::Distributed::PROPAGATION_STYLE_B3 - Tracing::Configuration::Ext::Distributed::PROPAGATION_STYLE_B3_MULTI_HEADER - when Tracing::Configuration::Ext::Distributed::PROPAGATION_STYLE_B3_SINGLE_HEADER_OLD - Tracing::Configuration::Ext::Distributed::PROPAGATION_STYLE_B3_SINGLE_HEADER - else - style - end - end - end - - o.lazy - end - - # The data propagation styles the tracer will use to inject distributed tracing propagation - # data into outgoing requests and messages. - # - # The tracer will inject data from all styles specified in this option. - # - # @default `DD_TRACE_PROPAGATION_STYLE_INJECT` environment variable (comma-separated list), otherwise `['Datadog']`. - # @return [Array] - option :propagation_inject_style do |o| - o.default do - # DEV-2.0: Change default value to `tracecontext, Datadog`. - env_to_list( - [Tracing::Configuration::Ext::Distributed::ENV_PROPAGATION_STYLE_INJECT, - Tracing::Configuration::Ext::Distributed::ENV_PROPAGATION_STYLE_INJECT_OLD], - [Tracing::Configuration::Ext::Distributed::PROPAGATION_STYLE_DATADOG], - comma_separated_only: true # Only inject Datadog headers by default - ) - end - - o.on_set do |styles| - # Modernize B3 options - # DEV-2.0: Can be removed with the removal of deprecated B3 constants. - styles.map! do |style| - case style - when Tracing::Configuration::Ext::Distributed::PROPAGATION_STYLE_B3 - Tracing::Configuration::Ext::Distributed::PROPAGATION_STYLE_B3_MULTI_HEADER - when Tracing::Configuration::Ext::Distributed::PROPAGATION_STYLE_B3_SINGLE_HEADER_OLD - Tracing::Configuration::Ext::Distributed::PROPAGATION_STYLE_B3_SINGLE_HEADER - else - style - end - end - end - - o.lazy - end - end - - # Enable trace collection and span generation. - # - # You can use this option to disable tracing without having to - # remove the library as a whole. - # - # @default `DD_TRACE_ENABLED` environment variable, otherwise `true` - # @return [Boolean] - option :enabled do |o| - o.default { env_to_bool(Tracing::Configuration::Ext::ENV_ENABLED, true) } - o.lazy - end - - # A custom tracer instance. - # - # It must respect the contract of {Datadog::Tracing::Tracer}. - # It's recommended to delegate methods to {Datadog::Tracing::Tracer} to ease the implementation - # of a custom tracer. - # - # This option will not return the live tracer instance: it only holds a custom tracing instance, if any. - # - # For internal use only. - # - # @default `nil` - # @return [Object,nil] - option :instance - - # Automatic correlation between tracing and logging. - # @see https://docs.datadoghq.com/tracing/setup_overview/setup/ruby/#trace-correlation - # @return [Boolean] - option :log_injection do |o| - o.default { env_to_bool(Tracing::Configuration::Ext::Correlation::ENV_LOGS_INJECTION_ENABLED, true) } - o.lazy - end - - # Configures an alternative trace transport behavior, where - # traces can be sent to the agent and backend before all spans - # have finished. - # - # This is useful for long-running jobs or very large traces. - # - # The trace flame graph will display the partial trace as it is received and constantly - # update with new spans as they are flushed. - # @public_api - settings :partial_flush do - # Enable partial trace flushing. - # - # @default `false` - # @return [Boolean] - option :enabled, default: false - - # Minimum number of finished spans required in a single unfinished trace before - # the tracer will consider that trace for partial flushing. - # - # This option helps preserve a minimum amount of batching in the - # flushing process, reducing network overhead. - # - # This threshold only applies to unfinished traces. Traces that have finished - # are always flushed immediately. - # - # @default 500 - # @return [Integer] - option :min_spans_threshold, default: 500 - end - - # Enables {https://docs.datadoghq.com/tracing/trace_retention_and_ingestion/#datadog-intelligent-retention-filter - # Datadog intelligent retention filter}. - # @default `true` - # @return [Boolean,nil] - option :priority_sampling - - option :report_hostname do |o| - o.default { env_to_bool(Tracing::Configuration::Ext::NET::ENV_REPORT_HOSTNAME, false) } - o.lazy - end - - # A custom sampler instance. - # The object must respect the {Datadog::Tracing::Sampling::Sampler} interface. - # @default `nil` - # @return [Object,nil] - option :sampler - - # Client-side sampling configuration. - # @see https://docs.datadoghq.com/tracing/trace_ingestion/mechanisms/ - # @public_api - settings :sampling do - # Default sampling rate for the tracer. - # - # If `nil`, the trace uses an automatic sampling strategy that tries to ensure - # the collection of traces that are considered important (e.g. traces with an error, traces - # for resources not seen recently). - # - # @default `DD_TRACE_SAMPLE_RATE` environment variable, otherwise `nil`. - # @return [Float,nil] - option :default_rate do |o| - o.default { env_to_float(Tracing::Configuration::Ext::Sampling::ENV_SAMPLE_RATE, nil) } - o.lazy - end - - # Rate limit for number of spans per second. - # - # Spans created above the limit will contribute to service metrics, but won't - # have their payload stored. - # - # @default `DD_TRACE_RATE_LIMIT` environment variable, otherwise 100. - # @return [Numeric,nil] - option :rate_limit do |o| - o.default { env_to_float(Tracing::Configuration::Ext::Sampling::ENV_RATE_LIMIT, 100) } - o.lazy - end - - # Single span sampling rules. - # These rules allow a span to be kept when its encompassing trace is dropped. - # - # The syntax for single span sampling rules can be found here: - # TODO: - # - # @default `DD_SPAN_SAMPLING_RULES` environment variable. - # Otherwise, `ENV_SPAN_SAMPLING_RULES_FILE` environment variable. - # Otherwise `nil`. - # @return [String,nil] - # @public_api - option :span_rules do |o| - o.default do - rules = ENV[Tracing::Configuration::Ext::Sampling::Span::ENV_SPAN_SAMPLING_RULES] - rules_file = ENV[Tracing::Configuration::Ext::Sampling::Span::ENV_SPAN_SAMPLING_RULES_FILE] - - if rules - if rules_file - Datadog.logger.warn( - 'Both DD_SPAN_SAMPLING_RULES and DD_SPAN_SAMPLING_RULES_FILE were provided: only ' \ - 'DD_SPAN_SAMPLING_RULES will be used. Please do not provide DD_SPAN_SAMPLING_RULES_FILE when ' \ - 'also providing DD_SPAN_SAMPLING_RULES as their configuration conflicts. ' \ - "DD_SPAN_SAMPLING_RULES_FILE=#{rules_file} DD_SPAN_SAMPLING_RULES=#{rules}" - ) - end - rules - elsif rules_file - begin - File.read(rules_file) - rescue => e - # `File#read` errors have clear and actionable messages, no need to add extra exception info. - Datadog.logger.warn( - "Cannot read span sampling rules file `#{rules_file}`: #{e.message}." \ - 'No span sampling rules will be applied.' - ) - nil - end - end - end - o.lazy - end - end - - # [Continuous Integration Visibility](https://docs.datadoghq.com/continuous_integration/) configuration. - # @public_api - settings :test_mode do - # Enable test mode. This allows the tracer to collect spans from test runs. - # - # It also prevents the tracer from collecting spans in a production environment. Only use in a test environment. - # - # @default `DD_TRACE_TEST_MODE_ENABLED` environment variable, otherwise `false` - # @return [Boolean] - option :enabled do |o| - o.default { env_to_bool(Tracing::Configuration::Ext::Test::ENV_MODE_ENABLED, false) } - o.lazy - end - - option :trace_flush do |o| - o.default { nil } - o.lazy - end - - option :writer_options do |o| - o.default { {} } - o.lazy - end - end - - # @see file:docs/GettingStarted.md#configuring-the-transport-layer Configuring the transport layer - # - # A {Proc} that configures a custom tracer transport. - # @yield Receives a {Datadog::Transport::HTTP} that can be modified with custom adapters and settings. - # @yieldparam [Datadog::Transport::HTTP] t transport to be configured. - # @default `nil` - # @return [Proc,nil] - option :transport_options, default: nil - - # A custom writer instance. - # The object must respect the {Datadog::Tracing::Writer} interface. - # - # This option is recommended for internal use only. - # - # @default `nil` - # @return [Object,nil] - option :writer - - # A custom {Hash} with keyword options to be passed to {Datadog::Tracing::Writer#initialize}. - # - # This option is recommended for internal use only. - # - # @default `{}` - # @return [Hash,nil] - option :writer_options, default: ->(_i) { {} }, lazy: true - - # Client IP configuration - # @public_api - settings :client_ip do - # Whether client IP collection is enabled. When enabled client IPs from HTTP requests will - # be reported in traces. - # - # Usage of the DD_TRACE_CLIENT_IP_HEADER_DISABLED environment variable is deprecated. - # - # @see https://docs.datadoghq.com/tracing/configure_data_security#configuring-a-client-ip-header - # - # @default `DD_TRACE_CLIENT_IP_ENABLED` environment variable, otherwise `false`. - # @return [Boolean] - option :enabled do |o| - o.default do - disabled = env_to_bool(Tracing::Configuration::Ext::ClientIp::ENV_DISABLED) - - enabled = if disabled.nil? - false - else - Datadog.logger.warn { "#{Tracing::Configuration::Ext::ClientIp::ENV_DISABLED} environment variable is deprecated, found set to #{disabled}, use #{Tracing::Configuration::Ext::ClientIp::ENV_ENABLED}=#{!disabled}" } - - !disabled - end - - # ENABLED env var takes precedence over deprecated DISABLED - env_to_bool(Tracing::Configuration::Ext::ClientIp::ENV_ENABLED, enabled) - end - o.lazy - end - - # An optional name of a custom header to resolve the client IP from. - # - # @default `DD_TRACE_CLIENT_IP_HEADER` environment variable, otherwise `nil`. - # @return [String,nil] - option :header_name do |o| - o.default { ENV.fetch(Tracing::Configuration::Ext::ClientIp::ENV_HEADER_NAME, nil) } - o.lazy - end - end - - # Maximum size for the `x-datadog-tags` distributed trace tags header. - # - # If the serialized size of distributed trace tags is larger than this value, it will - # not be parsed if incoming, nor exported if outgoing. An error message will be logged - # in this case. - # - # @default `DD_TRACE_X_DATADOG_TAGS_MAX_LENGTH` environment variable, otherwise `512` - # @return [Integer] - option :x_datadog_tags_max_length do |o| - o.default { env_to_int(Tracing::Configuration::Ext::Distributed::ENV_X_DATADOG_TAGS_MAX_LENGTH, 512) } - o.lazy - end - end - # The `version` tag in Datadog. Use it to enable [Deployment Tracking](https://docs.datadoghq.com/tracing/deployment_tracking/). # @see https://docs.datadoghq.com/getting_started/tagging/unified_service_tagging # @default `DD_VERSION` environment variable, otherwise `nils` @@ -799,7 +437,6 @@ def initialize(*_) end end # rubocop:enable Metrics/BlockLength - # rubocop:enable Layout/LineLength end end end diff --git a/lib/datadog/tracing/configuration/ext.rb b/lib/datadog/tracing/configuration/ext.rb index 3940527f832..5dc2032d3fd 100644 --- a/lib/datadog/tracing/configuration/ext.rb +++ b/lib/datadog/tracing/configuration/ext.rb @@ -3,6 +3,8 @@ module Datadog module Tracing module Configuration + # Constants for configuration settings + # e.g. Env vars, default values, enums, etc... module Ext ENV_ENABLED = 'DD_TRACE_ENABLED'.freeze diff --git a/lib/datadog/tracing/configuration/settings.rb b/lib/datadog/tracing/configuration/settings.rb new file mode 100644 index 00000000000..a4ad022022a --- /dev/null +++ b/lib/datadog/tracing/configuration/settings.rb @@ -0,0 +1,395 @@ +# typed: false + +require_relative '../../tracing/configuration/ext' + +module Datadog + module Tracing + module Configuration + # Configuration settings for tracing. + # @public_api + # rubocop:disable Metrics/AbcSize + # rubocop:disable Metrics/BlockLength + # rubocop:disable Metrics/MethodLength + # rubocop:disable Layout/LineLength + module Settings + def self.extended(base) + base.class_eval do + # Tracer specific configurations. + # @public_api + settings :tracing do + # Legacy [App Analytics](https://docs.datadoghq.com/tracing/legacy_app_analytics/) configuration. + # + # @configure_with {Datadog::Tracing} + # @deprecated Use [Trace Retention and Ingestion](https://docs.datadoghq.com/tracing/trace_retention_and_ingestion/) + # controls. + # @public_api + settings :analytics do + # @default `DD_TRACE_ANALYTICS_ENABLED` environment variable, otherwise `nil` + # @return [Boolean,nil] + option :enabled do |o| + o.default { env_to_bool(Tracing::Configuration::Ext::Analytics::ENV_TRACE_ANALYTICS_ENABLED, nil) } + o.lazy + end + end + + # [Distributed Tracing](https://docs.datadoghq.com/tracing/setup_overview/setup/ruby/#distributed-tracing) propagation + # style configuration. + # + # The supported formats are: + # * `Datadog`: Datadog propagation format, described by [Distributed Tracing](https://docs.datadoghq.com/tracing/setup_overview/setup/ruby/#distributed-tracing). + # * `b3multi`: B3 Propagation using multiple headers, described by [openzipkin/b3-propagation](https://github.com/openzipkin/b3-propagation#multiple-headers). + # * `b3`: B3 Propagation using a single header, described by [openzipkin/b3-propagation](https://github.com/openzipkin/b3-propagation#single-header). + # + # @public_api + settings :distributed_tracing do + # An ordered list of what data propagation styles the tracer will use to extract distributed tracing propagation + # data from incoming requests and messages. + # + # The tracer will try to find distributed headers in the order they are present in the list provided to this option. + # The first format to have valid data present will be used. + # + # @default `DD_TRACE_PROPAGATION_STYLE_EXTRACT` environment variable (comma-separated list), + # otherwise `['Datadog','b3multi','b3']`. + # @return [Array] + option :propagation_extract_style do |o| + o.default do + # DEV-2.0: Change default value to `tracecontext, Datadog`. + # Look for all headers by default + env_to_list( + [ + Tracing::Configuration::Ext::Distributed::ENV_PROPAGATION_STYLE_EXTRACT, + Tracing::Configuration::Ext::Distributed::ENV_PROPAGATION_STYLE_EXTRACT_OLD + ], + [ + Tracing::Configuration::Ext::Distributed::PROPAGATION_STYLE_DATADOG, + Tracing::Configuration::Ext::Distributed::PROPAGATION_STYLE_B3_MULTI_HEADER, + Tracing::Configuration::Ext::Distributed::PROPAGATION_STYLE_B3_SINGLE_HEADER + ], + comma_separated_only: true + ) + end + + o.on_set do |styles| + # Modernize B3 options + # DEV-2.0: Can be removed with the removal of deprecated B3 constants. + styles.map! do |style| + case style + when Tracing::Configuration::Ext::Distributed::PROPAGATION_STYLE_B3 + Tracing::Configuration::Ext::Distributed::PROPAGATION_STYLE_B3_MULTI_HEADER + when Tracing::Configuration::Ext::Distributed::PROPAGATION_STYLE_B3_SINGLE_HEADER_OLD + Tracing::Configuration::Ext::Distributed::PROPAGATION_STYLE_B3_SINGLE_HEADER + else + style + end + end + end + + o.lazy + end + + # The data propagation styles the tracer will use to inject distributed tracing propagation + # data into outgoing requests and messages. + # + # The tracer will inject data from all styles specified in this option. + # + # @default `DD_TRACE_PROPAGATION_STYLE_INJECT` environment variable (comma-separated list), otherwise `['Datadog']`. + # @return [Array] + option :propagation_inject_style do |o| + o.default do + # DEV-2.0: Change default value to `tracecontext, Datadog`. + env_to_list( + [ + Tracing::Configuration::Ext::Distributed::ENV_PROPAGATION_STYLE_INJECT, + Tracing::Configuration::Ext::Distributed::ENV_PROPAGATION_STYLE_INJECT_OLD + ], + [Tracing::Configuration::Ext::Distributed::PROPAGATION_STYLE_DATADOG], + comma_separated_only: true # Only inject Datadog headers by default + ) + end + + o.on_set do |styles| + # Modernize B3 options + # DEV-2.0: Can be removed with the removal of deprecated B3 constants. + styles.map! do |style| + case style + when Tracing::Configuration::Ext::Distributed::PROPAGATION_STYLE_B3 + Tracing::Configuration::Ext::Distributed::PROPAGATION_STYLE_B3_MULTI_HEADER + when Tracing::Configuration::Ext::Distributed::PROPAGATION_STYLE_B3_SINGLE_HEADER_OLD + Tracing::Configuration::Ext::Distributed::PROPAGATION_STYLE_B3_SINGLE_HEADER + else + style + end + end + end + + o.lazy + end + end + + # Enable trace collection and span generation. + # + # You can use this option to disable tracing without having to + # remove the library as a whole. + # + # @default `DD_TRACE_ENABLED` environment variable, otherwise `true` + # @return [Boolean] + option :enabled do |o| + o.default { env_to_bool(Tracing::Configuration::Ext::ENV_ENABLED, true) } + o.lazy + end + + # A custom tracer instance. + # + # It must respect the contract of {Datadog::Tracing::Tracer}. + # It's recommended to delegate methods to {Datadog::Tracing::Tracer} to ease the implementation + # of a custom tracer. + # + # This option will not return the live tracer instance: it only holds a custom tracing instance, if any. + # + # For internal use only. + # + # @default `nil` + # @return [Object,nil] + option :instance + + # Automatic correlation between tracing and logging. + # @see https://docs.datadoghq.com/tracing/setup_overview/setup/ruby/#trace-correlation + # @return [Boolean] + option :log_injection do |o| + o.default { env_to_bool(Tracing::Configuration::Ext::Correlation::ENV_LOGS_INJECTION_ENABLED, true) } + o.lazy + end + + # Configures an alternative trace transport behavior, where + # traces can be sent to the agent and backend before all spans + # have finished. + # + # This is useful for long-running jobs or very large traces. + # + # The trace flame graph will display the partial trace as it is received and constantly + # update with new spans as they are flushed. + # @public_api + settings :partial_flush do + # Enable partial trace flushing. + # + # @default `false` + # @return [Boolean] + option :enabled, default: false + + # Minimum number of finished spans required in a single unfinished trace before + # the tracer will consider that trace for partial flushing. + # + # This option helps preserve a minimum amount of batching in the + # flushing process, reducing network overhead. + # + # This threshold only applies to unfinished traces. Traces that have finished + # are always flushed immediately. + # + # @default 500 + # @return [Integer] + option :min_spans_threshold, default: 500 + end + + # Enables {https://docs.datadoghq.com/tracing/trace_retention_and_ingestion/#datadog-intelligent-retention-filter + # Datadog intelligent retention filter}. + # @default `true` + # @return [Boolean,nil] + option :priority_sampling + + option :report_hostname do |o| + o.default { env_to_bool(Tracing::Configuration::Ext::NET::ENV_REPORT_HOSTNAME, false) } + o.lazy + end + + # A custom sampler instance. + # The object must respect the {Datadog::Tracing::Sampling::Sampler} interface. + # @default `nil` + # @return [Object,nil] + option :sampler + + # Client-side sampling configuration. + # @see https://docs.datadoghq.com/tracing/trace_ingestion/mechanisms/ + # @public_api + settings :sampling do + # Default sampling rate for the tracer. + # + # If `nil`, the trace uses an automatic sampling strategy that tries to ensure + # the collection of traces that are considered important (e.g. traces with an error, traces + # for resources not seen recently). + # + # @default `DD_TRACE_SAMPLE_RATE` environment variable, otherwise `nil`. + # @return [Float,nil] + option :default_rate do |o| + o.default { env_to_float(Tracing::Configuration::Ext::Sampling::ENV_SAMPLE_RATE, nil) } + o.lazy + end + + # Rate limit for number of spans per second. + # + # Spans created above the limit will contribute to service metrics, but won't + # have their payload stored. + # + # @default `DD_TRACE_RATE_LIMIT` environment variable, otherwise 100. + # @return [Numeric,nil] + option :rate_limit do |o| + o.default { env_to_float(Tracing::Configuration::Ext::Sampling::ENV_RATE_LIMIT, 100) } + o.lazy + end + + # Single span sampling rules. + # These rules allow a span to be kept when its encompassing trace is dropped. + # + # The syntax for single span sampling rules can be found here: + # TODO: + # + # @default `DD_SPAN_SAMPLING_RULES` environment variable. + # Otherwise, `ENV_SPAN_SAMPLING_RULES_FILE` environment variable. + # Otherwise `nil`. + # @return [String,nil] + # @public_api + option :span_rules do |o| + o.default do + rules = ENV[Tracing::Configuration::Ext::Sampling::Span::ENV_SPAN_SAMPLING_RULES] + rules_file = ENV[Tracing::Configuration::Ext::Sampling::Span::ENV_SPAN_SAMPLING_RULES_FILE] + + if rules + if rules_file + Datadog.logger.warn( + 'Both DD_SPAN_SAMPLING_RULES and DD_SPAN_SAMPLING_RULES_FILE were provided: only ' \ + 'DD_SPAN_SAMPLING_RULES will be used. Please do not provide DD_SPAN_SAMPLING_RULES_FILE when ' \ + 'also providing DD_SPAN_SAMPLING_RULES as their configuration conflicts. ' \ + "DD_SPAN_SAMPLING_RULES_FILE=#{rules_file} DD_SPAN_SAMPLING_RULES=#{rules}" + ) + end + rules + elsif rules_file + begin + File.read(rules_file) + rescue => e + # `File#read` errors have clear and actionable messages, no need to add extra exception info. + Datadog.logger.warn( + "Cannot read span sampling rules file `#{rules_file}`: #{e.message}." \ + 'No span sampling rules will be applied.' + ) + nil + end + end + end + o.lazy + end + end + + # [Continuous Integration Visibility](https://docs.datadoghq.com/continuous_integration/) configuration. + # @public_api + settings :test_mode do + # Enable test mode. This allows the tracer to collect spans from test runs. + # + # It also prevents the tracer from collecting spans in a production environment. Only use in a test environment. + # + # @default `DD_TRACE_TEST_MODE_ENABLED` environment variable, otherwise `false` + # @return [Boolean] + option :enabled do |o| + o.default { env_to_bool(Tracing::Configuration::Ext::Test::ENV_MODE_ENABLED, false) } + o.lazy + end + + option :trace_flush do |o| + o.default { nil } + o.lazy + end + + option :writer_options do |o| + o.default { {} } + o.lazy + end + end + + # @see file:docs/GettingStarted.md#configuring-the-transport-layer Configuring the transport layer + # + # A {Proc} that configures a custom tracer transport. + # @yield Receives a {Datadog::Transport::HTTP} that can be modified with custom adapters and settings. + # @yieldparam [Datadog::Transport::HTTP] t transport to be configured. + # @default `nil` + # @return [Proc,nil] + option :transport_options, default: nil + + # A custom writer instance. + # The object must respect the {Datadog::Tracing::Writer} interface. + # + # This option is recommended for internal use only. + # + # @default `nil` + # @return [Object,nil] + option :writer + + # A custom {Hash} with keyword options to be passed to {Datadog::Tracing::Writer#initialize}. + # + # This option is recommended for internal use only. + # + # @default `{}` + # @return [Hash,nil] + option :writer_options, default: ->(_i) { {} }, lazy: true + + # Client IP configuration + # @public_api + settings :client_ip do + # Whether client IP collection is enabled. When enabled client IPs from HTTP requests will + # be reported in traces. + # + # Usage of the DD_TRACE_CLIENT_IP_HEADER_DISABLED environment variable is deprecated. + # + # @see https://docs.datadoghq.com/tracing/configure_data_security#configuring-a-client-ip-header + # + # @default `DD_TRACE_CLIENT_IP_ENABLED` environment variable, otherwise `false`. + # @return [Boolean] + option :enabled do |o| + o.default do + disabled = env_to_bool(Tracing::Configuration::Ext::ClientIp::ENV_DISABLED) + + enabled = if disabled.nil? + false + else + Datadog.logger.warn { "#{Tracing::Configuration::Ext::ClientIp::ENV_DISABLED} environment variable is deprecated, found set to #{disabled}, use #{Tracing::Configuration::Ext::ClientIp::ENV_ENABLED}=#{!disabled}" } + + !disabled + end + + # ENABLED env var takes precedence over deprecated DISABLED + env_to_bool(Tracing::Configuration::Ext::ClientIp::ENV_ENABLED, enabled) + end + o.lazy + end + + # An optional name of a custom header to resolve the client IP from. + # + # @default `DD_TRACE_CLIENT_IP_HEADER` environment variable, otherwise `nil`. + # @return [String,nil] + option :header_name do |o| + o.default { ENV.fetch(Tracing::Configuration::Ext::ClientIp::ENV_HEADER_NAME, nil) } + o.lazy + end + end + + # Maximum size for the `x-datadog-tags` distributed trace tags header. + # + # If the serialized size of distributed trace tags is larger than this value, it will + # not be parsed if incoming, nor exported if outgoing. An error message will be logged + # in this case. + # + # @default `DD_TRACE_X_DATADOG_TAGS_MAX_LENGTH` environment variable, otherwise `512` + # @return [Integer] + option :x_datadog_tags_max_length do |o| + o.default { env_to_int(Tracing::Configuration::Ext::Distributed::ENV_X_DATADOG_TAGS_MAX_LENGTH, 512) } + o.lazy + end + end + end + end + end + # rubocop:enable Metrics/AbcSize + # rubocop:enable Metrics/BlockLength + # rubocop:enable Metrics/MethodLength + # rubocop:enable Layout/LineLength + end + end +end diff --git a/spec/datadog/core/configuration/settings_spec.rb b/spec/datadog/core/configuration/settings_spec.rb index 4654bf326a9..d58c6c263d1 100644 --- a/spec/datadog/core/configuration/settings_spec.rb +++ b/spec/datadog/core/configuration/settings_spec.rb @@ -10,11 +10,6 @@ require 'datadog/core/runtime/ext' require 'datadog/core/utils/time' require 'datadog/profiling/ext' -require 'datadog/tracing/configuration/ext' -require 'datadog/tracing/flush' -require 'datadog/tracing/sampling/priority_sampler' -require 'datadog/tracing/tracer' -require 'datadog/tracing/writer' RSpec.describe Datadog::Core::Configuration::Settings do subject(:settings) { described_class.new(options) } @@ -934,6 +929,7 @@ end end + # TODO: Migrate this to Tracing describe '#tracer' do describe '#port' do subject(:port) { settings.agent.port } @@ -954,641 +950,6 @@ end end - describe '#tracing' do - describe '#analytics' do - describe '#enabled' do - subject(:enabled) { settings.tracing.analytics.enabled } - - context "when #{Datadog::Tracing::Configuration::Ext::Analytics::ENV_TRACE_ANALYTICS_ENABLED}" do - around do |example| - ClimateControl.modify( - Datadog::Tracing::Configuration::Ext::Analytics::ENV_TRACE_ANALYTICS_ENABLED => environment - ) do - example.run - end - end - - context 'is not defined' do - let(:environment) { nil } - - it { is_expected.to be nil } - end - - context 'is defined' do - let(:environment) { 'true' } - - it { is_expected.to be true } - end - end - end - - describe '#enabled=' do - after { settings.runtime_metrics.reset! } - - it 'changes the #enabled setting' do - expect { settings.tracing.analytics.enabled = true } - .to change { settings.tracing.analytics.enabled } - .from(nil) - .to(true) - end - end - end - - describe '#distributed_tracing' do - describe '#propagation_extract_style' do - subject(:propagation_extract_style) { settings.tracing.distributed_tracing.propagation_extract_style } - - around do |example| - ClimateControl.modify(var_name => var_value) do - example.run - end - end - - context 'when DD_TRACE_PROPAGATION_STYLE_EXTRACT' do - let(:var_name) { 'DD_TRACE_PROPAGATION_STYLE_EXTRACT' } - - context 'is not defined' do - let(:var_value) { nil } - - it do - is_expected.to eq( - [ - Datadog::Tracing::Configuration::Ext::Distributed::PROPAGATION_STYLE_DATADOG, - Datadog::Tracing::Configuration::Ext::Distributed::PROPAGATION_STYLE_B3_MULTI_HEADER, - Datadog::Tracing::Configuration::Ext::Distributed::PROPAGATION_STYLE_B3_SINGLE_HEADER - ] - ) - end - end - - context 'is defined' do - let(:var_value) { 'b3multi,b3' } - - it do - is_expected.to eq( - [ - Datadog::Tracing::Configuration::Ext::Distributed::PROPAGATION_STYLE_B3_MULTI_HEADER, - Datadog::Tracing::Configuration::Ext::Distributed::PROPAGATION_STYLE_B3_SINGLE_HEADER - ] - ) - end - end - - context 'is set to deprecated style names' do - let(:var_value) { 'B3,B3 single header' } - - it 'translates to new names' do - is_expected.to eq( - [ - Datadog::Tracing::Configuration::Ext::Distributed::PROPAGATION_STYLE_B3_MULTI_HEADER, - Datadog::Tracing::Configuration::Ext::Distributed::PROPAGATION_STYLE_B3_SINGLE_HEADER - ] - ) - end - end - end - - context 'with deprecated DD_PROPAGATION_STYLE_EXTRACT' do - let(:var_name) { 'DD_PROPAGATION_STYLE_EXTRACT' } - - context 'is defined' do - let(:var_value) { 'b3multi,b3' } - - it do - is_expected.to eq( - [ - Datadog::Tracing::Configuration::Ext::Distributed::PROPAGATION_STYLE_B3_MULTI_HEADER, - Datadog::Tracing::Configuration::Ext::Distributed::PROPAGATION_STYLE_B3_SINGLE_HEADER - ] - ) - end - - include_examples 'records deprecated action', 'DD_PROPAGATION_STYLE_EXTRACT environment variable is deprecated' - end - end - end - - describe '#propagation_inject_style' do - subject(:propagation_inject_style) { settings.tracing.distributed_tracing.propagation_inject_style } - - around do |example| - ClimateControl.modify(var_name => var_value) do - example.run - end - end - - context 'with DD_TRACE_PROPAGATION_STYLE_INJECT' do - let(:var_name) { 'DD_TRACE_PROPAGATION_STYLE_INJECT' } - - context 'is not defined' do - let(:var_value) { nil } - - it { is_expected.to eq([Datadog::Tracing::Configuration::Ext::Distributed::PROPAGATION_STYLE_DATADOG]) } - end - - context 'is defined' do - let(:var_value) { 'Datadog,b3' } - - it do - is_expected.to eq( - [ - Datadog::Tracing::Configuration::Ext::Distributed::PROPAGATION_STYLE_DATADOG, - Datadog::Tracing::Configuration::Ext::Distributed::PROPAGATION_STYLE_B3_SINGLE_HEADER - ] - ) - end - end - - context 'is set to deprecated style names' do - let(:var_value) { 'B3,B3 single header' } - - it 'translates to new names' do - is_expected.to eq( - [ - Datadog::Tracing::Configuration::Ext::Distributed::PROPAGATION_STYLE_B3_MULTI_HEADER, - Datadog::Tracing::Configuration::Ext::Distributed::PROPAGATION_STYLE_B3_SINGLE_HEADER - ] - ) - end - end - end - - context 'with deprecated DD_PROPAGATION_STYLE_INJECT' do - let(:var_name) { 'DD_PROPAGATION_STYLE_INJECT' } - - context 'is defined' do - let(:var_value) { 'Datadog,b3' } - - it do - is_expected.to eq( - [ - Datadog::Tracing::Configuration::Ext::Distributed::PROPAGATION_STYLE_DATADOG, - Datadog::Tracing::Configuration::Ext::Distributed::PROPAGATION_STYLE_B3_SINGLE_HEADER - ] - ) - end - - include_examples 'records deprecated action', 'DD_PROPAGATION_STYLE_INJECT environment variable is deprecated' - end - end - end - end - - describe '#enabled' do - subject(:enabled) { settings.tracing.enabled } - - it { is_expected.to be true } - - context "when #{Datadog::Tracing::Configuration::Ext::ENV_ENABLED}" do - around do |example| - ClimateControl.modify(Datadog::Tracing::Configuration::Ext::ENV_ENABLED => enable) do - example.run - end - end - - context 'is not defined' do - let(:enable) { nil } - - it { is_expected.to be true } - end - - context 'is set to true' do - let(:enable) { 'true' } - - it { is_expected.to be true } - end - - context 'is set to false' do - let(:enable) { 'false' } - - it { is_expected.to be false } - end - end - end - - describe '#enabled=' do - it 'updates the #enabled setting' do - expect { settings.tracing.enabled = false } - .to change { settings.tracing.enabled } - .from(true) - .to(false) - end - end - - describe '#instance' do - subject(:instance) { settings.tracing.instance } - - it { is_expected.to be nil } - end - - describe '#instance=' do - let(:tracer) { instance_double(Datadog::Tracing::Tracer) } - - it 'updates the #instance setting' do - expect { settings.tracing.instance = tracer } - .to change { settings.tracing.instance } - .from(nil) - .to(tracer) - end - end - - describe '#log_injection' do - subject(:log_injection) { settings.tracing.log_injection } - - context "when #{Datadog::Tracing::Configuration::Ext::Correlation::ENV_LOGS_INJECTION_ENABLED}" do - around do |example| - ClimateControl.modify( - Datadog::Tracing::Configuration::Ext::Correlation::ENV_LOGS_INJECTION_ENABLED => log_injection_env - ) do - example.run - end - end - - context 'is not defined' do - let(:log_injection_env) { nil } - - it { is_expected.to be(true) } - end - - context 'is defined' do - let(:log_injection_env) { 'false' } - - it { is_expected.to be(false) } - end - end - end - - describe '#partial_flush' do - describe '#enabled' do - subject(:enabled) { settings.tracing.partial_flush.enabled } - - it { is_expected.to be false } - end - - describe '#enabled=' do - it 'updates the #enabled setting' do - expect { settings.tracing.partial_flush.enabled = true } - .to change { settings.tracing.partial_flush.enabled } - .from(false) - .to(true) - end - end - - describe '#min_spans_threshold' do - subject(:min_spans_threshold) { settings.tracing.partial_flush.min_spans_threshold } - - it { is_expected.to eq(500) } - end - - describe '#min_spans_threshold=' do - let(:value) { 1234 } - - it 'updates the #min_spans_before_partial_flush setting' do - expect { settings.tracing.partial_flush.min_spans_threshold = value } - .to change { settings.tracing.partial_flush.min_spans_threshold } - .from(500) - .to(value) - end - end - end - - describe '#priority_sampling' do - subject(:priority_sampling) { settings.tracing.priority_sampling } - - it { is_expected.to be nil } - end - - describe '#priority_sampling=' do - it 'updates the #priority_sampling setting' do - expect { settings.tracing.priority_sampling = true } - .to change { settings.tracing.priority_sampling } - .from(nil) - .to(true) - end - end - - describe '#report_hostname' do - subject(:report_hostname) { settings.tracing.report_hostname } - - context "when #{Datadog::Tracing::Configuration::Ext::NET::ENV_REPORT_HOSTNAME}" do - around do |example| - ClimateControl.modify(Datadog::Tracing::Configuration::Ext::NET::ENV_REPORT_HOSTNAME => environment) do - example.run - end - end - - context 'is not defined' do - let(:environment) { nil } - - it { is_expected.to be false } - end - - context 'is defined' do - let(:environment) { 'true' } - - it { is_expected.to be true } - end - end - end - - describe '#report_hostname=' do - it 'changes the #report_hostname setting' do - expect { settings.tracing.report_hostname = true } - .to change { settings.tracing.report_hostname } - .from(false) - .to(true) - end - end - - describe '#sampler' do - subject(:sampler) { settings.tracing.sampler } - - it { is_expected.to be nil } - end - - describe '#sampler=' do - let(:sampler) { instance_double(Datadog::Tracing::Sampling::PrioritySampler) } - - it 'updates the #sampler setting' do - expect { settings.tracing.sampler = sampler } - .to change { settings.tracing.sampler } - .from(nil) - .to(sampler) - end - end - - describe '#sampling' do - describe '#rate_limit' do - subject(:rate_limit) { settings.tracing.sampling.rate_limit } - - context 'default' do - it { is_expected.to eq(100) } - end - - context 'when ENV is provided' do - around do |example| - ClimateControl.modify(Datadog::Tracing::Configuration::Ext::Sampling::ENV_RATE_LIMIT => '20.0') do - example.run - end - end - - it { is_expected.to eq(20.0) } - end - end - - describe '#default_rate' do - subject(:default_rate) { settings.tracing.sampling.default_rate } - - context 'default' do - it { is_expected.to be nil } - end - - context 'when ENV is provided' do - around do |example| - ClimateControl.modify(Datadog::Tracing::Configuration::Ext::Sampling::ENV_SAMPLE_RATE => '0.5') do - example.run - end - end - - it { is_expected.to eq(0.5) } - end - end - - describe '#span_rules' do - subject(:rules) { settings.tracing.sampling.span_rules } - - context 'default' do - it { is_expected.to be nil } - end - - context 'when DD_SPAN_SAMPLING_RULES is provided' do - around do |example| - ClimateControl.modify( - Datadog::Tracing::Configuration::Ext::Sampling::Span::ENV_SPAN_SAMPLING_RULES => '{}' - ) do - example.run - end - end - - it { is_expected.to eq('{}') } - - context 'and DD_SPAN_SAMPLING_RULES_FILE is also provided' do - around do |example| - ClimateControl.modify( - Datadog::Tracing::Configuration::Ext::Sampling::Span::ENV_SPAN_SAMPLING_RULES_FILE => 'path' - ) do - example.run - end - end - - it 'emits a conflict warning and returns DD_SPAN_SAMPLING_RULES' do - expect(Datadog.logger).to receive(:warn).with(include('configuration conflict')) - is_expected.to eq('{}') - end - end - end - - context 'when DD_SPAN_SAMPLING_RULES_FILE is provided' do - around do |example| - Tempfile.open('DD_SPAN_SAMPLING_RULES_FILE') do |f| - f.write('{from:"file"}') - f.flush - - ClimateControl.modify( - Datadog::Tracing::Configuration::Ext::Sampling::Span::ENV_SPAN_SAMPLING_RULES_FILE => f.path - ) do - example.run - end - end - end - - it { is_expected.to eq('{from:"file"}') } - end - end - end - - describe '#test_mode' do - describe '#enabled' do - subject(:enabled) { settings.tracing.test_mode.enabled } - - it { is_expected.to be false } - - context "when #{Datadog::Tracing::Configuration::Ext::Test::ENV_MODE_ENABLED}" do - around do |example| - ClimateControl.modify(Datadog::Tracing::Configuration::Ext::Test::ENV_MODE_ENABLED => enable) do - example.run - end - end - - context 'is not defined' do - let(:enable) { nil } - - it { is_expected.to be false } - end - - context 'is set to true' do - let(:enable) { 'true' } - - it { is_expected.to be true } - end - - context 'is set to false' do - let(:enable) { 'false' } - - it { is_expected.to be false } - end - end - end - - describe '#trace_flush' do - subject(:trace_flush) { settings.tracing.test_mode.trace_flush } - - context 'default' do - it { is_expected.to be nil } - end - end - - describe '#trace_flush=' do - let(:trace_flush) { instance_double(Datadog::Tracing::Flush::Finished) } - - it 'updates the #trace_flush setting' do - expect { settings.tracing.test_mode.trace_flush = trace_flush } - .to change { settings.tracing.test_mode.trace_flush } - .from(nil) - .to(trace_flush) - end - end - - describe '#enabled=' do - it 'updates the #enabled setting' do - expect { settings.tracing.test_mode.enabled = true } - .to change { settings.tracing.test_mode.enabled } - .from(false) - .to(true) - end - end - - describe '#writer_options' do - subject(:writer_options) { settings.tracing.test_mode.writer_options } - - it { is_expected.to eq({}) } - - context 'when modified' do - it 'does not modify the default by reference' do - settings.tracing.test_mode.writer_options[:foo] = :bar - expect(settings.tracing.test_mode.writer_options).to_not be_empty - expect(settings.tracing.test_mode.options[:writer_options].default_value).to be_empty - end - end - end - - describe '#writer_options=' do - let(:options) { { priority_sampling: true } } - - it 'updates the #writer_options setting' do - expect { settings.tracing.test_mode.writer_options = options } - .to change { settings.tracing.test_mode.writer_options } - .from({}) - .to(options) - end - end - end - - describe '#transport_options' do - subject(:transport_options) { settings.tracing.transport_options } - - it { is_expected.to be nil } - end - - describe '#transport_options=' do - let(:config_proc) { proc { |t| t.adapter :test } } - - it 'updates the #transport_options setting' do - expect { settings.tracing.transport_options = config_proc } - .to change { settings.tracing.transport_options } - .from(nil) - .to(config_proc) - end - end - - describe '#writer' do - subject(:writer) { settings.tracing.writer } - - it { is_expected.to be nil } - end - - describe '#writer=' do - let(:writer) { instance_double(Datadog::Tracing::Writer) } - - it 'updates the #writer setting' do - expect { settings.tracing.writer = writer } - .to change { settings.tracing.writer } - .from(nil) - .to(writer) - end - end - - describe '#writer_options' do - subject(:writer_options) { settings.tracing.writer_options } - - it { is_expected.to eq({}) } - - context 'when modified' do - it 'does not modify the default by reference' do - settings.tracing.writer_options[:foo] = :bar - expect(settings.tracing.writer_options).to_not be_empty - expect(settings.tracing.options[:writer_options].default_value).to be_empty - end - end - end - - describe '#writer_options=' do - let(:options) { { priority_sampling: true } } - - it 'updates the #writer_options setting' do - expect { settings.tracing.writer_options = options } - .to change { settings.tracing.writer_options } - .from({}) - .to(options) - end - end - - describe '#x_datadog_tags_max_length' do - subject { settings.tracing.x_datadog_tags_max_length } - - context "when #{Datadog::Tracing::Configuration::Ext::Distributed::ENV_X_DATADOG_TAGS_MAX_LENGTH}" do - around do |example| - ClimateControl.modify( - Datadog::Tracing::Configuration::Ext::Distributed::ENV_X_DATADOG_TAGS_MAX_LENGTH => env_var - ) do - example.run - end - end - - context 'is not defined' do - let(:env_var) { nil } - - it { is_expected.to eq(512) } - end - - context 'is defined' do - let(:env_var) { '123' } - - it { is_expected.to eq(123) } - end - end - end - - describe '#x_datadog_tags_max_length=' do - it 'updates the #x_datadog_tags_max_length setting' do - expect { settings.tracing.x_datadog_tags_max_length = 123 } - .to change { settings.tracing.x_datadog_tags_max_length } - .from(512) - .to(123) - end - end - end - describe '#version' do subject(:version) { settings.version } diff --git a/spec/datadog/tracing/configuration/settings_spec.rb b/spec/datadog/tracing/configuration/settings_spec.rb new file mode 100644 index 00000000000..584062ce79b --- /dev/null +++ b/spec/datadog/tracing/configuration/settings_spec.rb @@ -0,0 +1,656 @@ +# typed: false + +require 'spec_helper' + +require 'securerandom' + +require 'datadog/core/configuration/settings' +require 'datadog/tracing/configuration/ext' +require 'datadog/tracing/flush' +require 'datadog/tracing/sampling/priority_sampler' +require 'datadog/tracing/tracer' +require 'datadog/tracing/writer' + +RSpec.describe Datadog::Tracing::Configuration::Settings do + # TODO: Core::Configuration::Settings directly extends Tracing::Configuration::Settings + # In the future, have tracing add this behavior itself. For now, + # just use the core metrics class to drive the tests. + subject(:settings) { Datadog::Core::Configuration::Settings.new(options) } + + let(:options) { {} } + + describe '#tracing' do + describe '#analytics' do + describe '#enabled' do + subject(:enabled) { settings.tracing.analytics.enabled } + + context "when #{Datadog::Tracing::Configuration::Ext::Analytics::ENV_TRACE_ANALYTICS_ENABLED}" do + around do |example| + ClimateControl.modify( + Datadog::Tracing::Configuration::Ext::Analytics::ENV_TRACE_ANALYTICS_ENABLED => environment + ) do + example.run + end + end + + context 'is not defined' do + let(:environment) { nil } + + it { is_expected.to be nil } + end + + context 'is defined' do + let(:environment) { 'true' } + + it { is_expected.to be true } + end + end + end + + describe '#enabled=' do + after { settings.runtime_metrics.reset! } + + it 'changes the #enabled setting' do + expect { settings.tracing.analytics.enabled = true } + .to change { settings.tracing.analytics.enabled } + .from(nil) + .to(true) + end + end + end + + describe '#distributed_tracing' do + describe '#propagation_extract_style' do + subject(:propagation_extract_style) { settings.tracing.distributed_tracing.propagation_extract_style } + + around do |example| + ClimateControl.modify(var_name => var_value) do + example.run + end + end + + context 'when DD_TRACE_PROPAGATION_STYLE_EXTRACT' do + let(:var_name) { 'DD_TRACE_PROPAGATION_STYLE_EXTRACT' } + + context 'is not defined' do + let(:var_value) { nil } + + it do + is_expected.to eq( + [ + Datadog::Tracing::Configuration::Ext::Distributed::PROPAGATION_STYLE_DATADOG, + Datadog::Tracing::Configuration::Ext::Distributed::PROPAGATION_STYLE_B3_MULTI_HEADER, + Datadog::Tracing::Configuration::Ext::Distributed::PROPAGATION_STYLE_B3_SINGLE_HEADER + ] + ) + end + end + + context 'is defined' do + let(:var_value) { 'b3multi,b3' } + + it do + is_expected.to eq( + [ + Datadog::Tracing::Configuration::Ext::Distributed::PROPAGATION_STYLE_B3_MULTI_HEADER, + Datadog::Tracing::Configuration::Ext::Distributed::PROPAGATION_STYLE_B3_SINGLE_HEADER + ] + ) + end + end + + context 'is set to deprecated style names' do + let(:var_value) { 'B3,B3 single header' } + + it 'translates to new names' do + is_expected.to eq( + [ + Datadog::Tracing::Configuration::Ext::Distributed::PROPAGATION_STYLE_B3_MULTI_HEADER, + Datadog::Tracing::Configuration::Ext::Distributed::PROPAGATION_STYLE_B3_SINGLE_HEADER + ] + ) + end + end + end + + context 'with deprecated DD_PROPAGATION_STYLE_EXTRACT' do + let(:var_name) { 'DD_PROPAGATION_STYLE_EXTRACT' } + + context 'is defined' do + let(:var_value) { 'b3multi,b3' } + + it do + is_expected.to eq( + [ + Datadog::Tracing::Configuration::Ext::Distributed::PROPAGATION_STYLE_B3_MULTI_HEADER, + Datadog::Tracing::Configuration::Ext::Distributed::PROPAGATION_STYLE_B3_SINGLE_HEADER + ] + ) + end + + include_examples 'records deprecated action', 'DD_PROPAGATION_STYLE_EXTRACT environment variable is deprecated' + end + end + end + + describe '#propagation_inject_style' do + subject(:propagation_inject_style) { settings.tracing.distributed_tracing.propagation_inject_style } + + around do |example| + ClimateControl.modify(var_name => var_value) do + example.run + end + end + + context 'with DD_TRACE_PROPAGATION_STYLE_INJECT' do + let(:var_name) { 'DD_TRACE_PROPAGATION_STYLE_INJECT' } + + context 'is not defined' do + let(:var_value) { nil } + + it { is_expected.to eq([Datadog::Tracing::Configuration::Ext::Distributed::PROPAGATION_STYLE_DATADOG]) } + end + + context 'is defined' do + let(:var_value) { 'Datadog,b3' } + + it do + is_expected.to eq( + [ + Datadog::Tracing::Configuration::Ext::Distributed::PROPAGATION_STYLE_DATADOG, + Datadog::Tracing::Configuration::Ext::Distributed::PROPAGATION_STYLE_B3_SINGLE_HEADER + ] + ) + end + end + + context 'is set to deprecated style names' do + let(:var_value) { 'B3,B3 single header' } + + it 'translates to new names' do + is_expected.to eq( + [ + Datadog::Tracing::Configuration::Ext::Distributed::PROPAGATION_STYLE_B3_MULTI_HEADER, + Datadog::Tracing::Configuration::Ext::Distributed::PROPAGATION_STYLE_B3_SINGLE_HEADER + ] + ) + end + end + end + + context 'with deprecated DD_PROPAGATION_STYLE_INJECT' do + let(:var_name) { 'DD_PROPAGATION_STYLE_INJECT' } + + context 'is defined' do + let(:var_value) { 'Datadog,b3' } + + it do + is_expected.to eq( + [ + Datadog::Tracing::Configuration::Ext::Distributed::PROPAGATION_STYLE_DATADOG, + Datadog::Tracing::Configuration::Ext::Distributed::PROPAGATION_STYLE_B3_SINGLE_HEADER + ] + ) + end + + include_examples 'records deprecated action', 'DD_PROPAGATION_STYLE_INJECT environment variable is deprecated' + end + end + end + end + + describe '#enabled' do + subject(:enabled) { settings.tracing.enabled } + + it { is_expected.to be true } + + context "when #{Datadog::Tracing::Configuration::Ext::ENV_ENABLED}" do + around do |example| + ClimateControl.modify(Datadog::Tracing::Configuration::Ext::ENV_ENABLED => enable) do + example.run + end + end + + context 'is not defined' do + let(:enable) { nil } + + it { is_expected.to be true } + end + + context 'is set to true' do + let(:enable) { 'true' } + + it { is_expected.to be true } + end + + context 'is set to false' do + let(:enable) { 'false' } + + it { is_expected.to be false } + end + end + end + + describe '#enabled=' do + it 'updates the #enabled setting' do + expect { settings.tracing.enabled = false } + .to change { settings.tracing.enabled } + .from(true) + .to(false) + end + end + + describe '#instance' do + subject(:instance) { settings.tracing.instance } + + it { is_expected.to be nil } + end + + describe '#instance=' do + let(:tracer) { instance_double(Datadog::Tracing::Tracer) } + + it 'updates the #instance setting' do + expect { settings.tracing.instance = tracer } + .to change { settings.tracing.instance } + .from(nil) + .to(tracer) + end + end + + describe '#log_injection' do + subject(:log_injection) { settings.tracing.log_injection } + + context "when #{Datadog::Tracing::Configuration::Ext::Correlation::ENV_LOGS_INJECTION_ENABLED}" do + around do |example| + ClimateControl.modify( + Datadog::Tracing::Configuration::Ext::Correlation::ENV_LOGS_INJECTION_ENABLED => log_injection_env + ) do + example.run + end + end + + context 'is not defined' do + let(:log_injection_env) { nil } + + it { is_expected.to be(true) } + end + + context 'is defined' do + let(:log_injection_env) { 'false' } + + it { is_expected.to be(false) } + end + end + end + + describe '#partial_flush' do + describe '#enabled' do + subject(:enabled) { settings.tracing.partial_flush.enabled } + + it { is_expected.to be false } + end + + describe '#enabled=' do + it 'updates the #enabled setting' do + expect { settings.tracing.partial_flush.enabled = true } + .to change { settings.tracing.partial_flush.enabled } + .from(false) + .to(true) + end + end + + describe '#min_spans_threshold' do + subject(:min_spans_threshold) { settings.tracing.partial_flush.min_spans_threshold } + + it { is_expected.to eq(500) } + end + + describe '#min_spans_threshold=' do + let(:value) { 1234 } + + it 'updates the #min_spans_before_partial_flush setting' do + expect { settings.tracing.partial_flush.min_spans_threshold = value } + .to change { settings.tracing.partial_flush.min_spans_threshold } + .from(500) + .to(value) + end + end + end + + describe '#priority_sampling' do + subject(:priority_sampling) { settings.tracing.priority_sampling } + + it { is_expected.to be nil } + end + + describe '#priority_sampling=' do + it 'updates the #priority_sampling setting' do + expect { settings.tracing.priority_sampling = true } + .to change { settings.tracing.priority_sampling } + .from(nil) + .to(true) + end + end + + describe '#report_hostname' do + subject(:report_hostname) { settings.tracing.report_hostname } + + context "when #{Datadog::Tracing::Configuration::Ext::NET::ENV_REPORT_HOSTNAME}" do + around do |example| + ClimateControl.modify(Datadog::Tracing::Configuration::Ext::NET::ENV_REPORT_HOSTNAME => environment) do + example.run + end + end + + context 'is not defined' do + let(:environment) { nil } + + it { is_expected.to be false } + end + + context 'is defined' do + let(:environment) { 'true' } + + it { is_expected.to be true } + end + end + end + + describe '#report_hostname=' do + it 'changes the #report_hostname setting' do + expect { settings.tracing.report_hostname = true } + .to change { settings.tracing.report_hostname } + .from(false) + .to(true) + end + end + + describe '#sampler' do + subject(:sampler) { settings.tracing.sampler } + + it { is_expected.to be nil } + end + + describe '#sampler=' do + let(:sampler) { instance_double(Datadog::Tracing::Sampling::PrioritySampler) } + + it 'updates the #sampler setting' do + expect { settings.tracing.sampler = sampler } + .to change { settings.tracing.sampler } + .from(nil) + .to(sampler) + end + end + + describe '#sampling' do + describe '#rate_limit' do + subject(:rate_limit) { settings.tracing.sampling.rate_limit } + + context 'default' do + it { is_expected.to eq(100) } + end + + context 'when ENV is provided' do + around do |example| + ClimateControl.modify(Datadog::Tracing::Configuration::Ext::Sampling::ENV_RATE_LIMIT => '20.0') do + example.run + end + end + + it { is_expected.to eq(20.0) } + end + end + + describe '#default_rate' do + subject(:default_rate) { settings.tracing.sampling.default_rate } + + context 'default' do + it { is_expected.to be nil } + end + + context 'when ENV is provided' do + around do |example| + ClimateControl.modify(Datadog::Tracing::Configuration::Ext::Sampling::ENV_SAMPLE_RATE => '0.5') do + example.run + end + end + + it { is_expected.to eq(0.5) } + end + end + + describe '#span_rules' do + subject(:rules) { settings.tracing.sampling.span_rules } + + context 'default' do + it { is_expected.to be nil } + end + + context 'when DD_SPAN_SAMPLING_RULES is provided' do + around do |example| + ClimateControl.modify( + Datadog::Tracing::Configuration::Ext::Sampling::Span::ENV_SPAN_SAMPLING_RULES => '{}' + ) do + example.run + end + end + + it { is_expected.to eq('{}') } + + context 'and DD_SPAN_SAMPLING_RULES_FILE is also provided' do + around do |example| + ClimateControl.modify( + Datadog::Tracing::Configuration::Ext::Sampling::Span::ENV_SPAN_SAMPLING_RULES_FILE => 'path' + ) do + example.run + end + end + + it 'emits a conflict warning and returns DD_SPAN_SAMPLING_RULES' do + expect(Datadog.logger).to receive(:warn).with(include('configuration conflict')) + is_expected.to eq('{}') + end + end + end + + context 'when DD_SPAN_SAMPLING_RULES_FILE is provided' do + around do |example| + Tempfile.open('DD_SPAN_SAMPLING_RULES_FILE') do |f| + f.write('{from:"file"}') + f.flush + + ClimateControl.modify( + Datadog::Tracing::Configuration::Ext::Sampling::Span::ENV_SPAN_SAMPLING_RULES_FILE => f.path + ) do + example.run + end + end + end + + it { is_expected.to eq('{from:"file"}') } + end + end + end + + describe '#test_mode' do + describe '#enabled' do + subject(:enabled) { settings.tracing.test_mode.enabled } + + it { is_expected.to be false } + + context "when #{Datadog::Tracing::Configuration::Ext::Test::ENV_MODE_ENABLED}" do + around do |example| + ClimateControl.modify(Datadog::Tracing::Configuration::Ext::Test::ENV_MODE_ENABLED => enable) do + example.run + end + end + + context 'is not defined' do + let(:enable) { nil } + + it { is_expected.to be false } + end + + context 'is set to true' do + let(:enable) { 'true' } + + it { is_expected.to be true } + end + + context 'is set to false' do + let(:enable) { 'false' } + + it { is_expected.to be false } + end + end + end + + describe '#trace_flush' do + subject(:trace_flush) { settings.tracing.test_mode.trace_flush } + + context 'default' do + it { is_expected.to be nil } + end + end + + describe '#trace_flush=' do + let(:trace_flush) { instance_double(Datadog::Tracing::Flush::Finished) } + + it 'updates the #trace_flush setting' do + expect { settings.tracing.test_mode.trace_flush = trace_flush } + .to change { settings.tracing.test_mode.trace_flush } + .from(nil) + .to(trace_flush) + end + end + + describe '#enabled=' do + it 'updates the #enabled setting' do + expect { settings.tracing.test_mode.enabled = true } + .to change { settings.tracing.test_mode.enabled } + .from(false) + .to(true) + end + end + + describe '#writer_options' do + subject(:writer_options) { settings.tracing.test_mode.writer_options } + + it { is_expected.to eq({}) } + + context 'when modified' do + it 'does not modify the default by reference' do + settings.tracing.test_mode.writer_options[:foo] = :bar + expect(settings.tracing.test_mode.writer_options).to_not be_empty + expect(settings.tracing.test_mode.options[:writer_options].default_value).to be_empty + end + end + end + + describe '#writer_options=' do + let(:options) { { priority_sampling: true } } + + it 'updates the #writer_options setting' do + expect { settings.tracing.test_mode.writer_options = options } + .to change { settings.tracing.test_mode.writer_options } + .from({}) + .to(options) + end + end + end + + describe '#transport_options' do + subject(:transport_options) { settings.tracing.transport_options } + + it { is_expected.to be nil } + end + + describe '#transport_options=' do + let(:config_proc) { proc { |t| t.adapter :test } } + + it 'updates the #transport_options setting' do + expect { settings.tracing.transport_options = config_proc } + .to change { settings.tracing.transport_options } + .from(nil) + .to(config_proc) + end + end + + describe '#writer' do + subject(:writer) { settings.tracing.writer } + + it { is_expected.to be nil } + end + + describe '#writer=' do + let(:writer) { instance_double(Datadog::Tracing::Writer) } + + it 'updates the #writer setting' do + expect { settings.tracing.writer = writer } + .to change { settings.tracing.writer } + .from(nil) + .to(writer) + end + end + + describe '#writer_options' do + subject(:writer_options) { settings.tracing.writer_options } + + it { is_expected.to eq({}) } + + context 'when modified' do + it 'does not modify the default by reference' do + settings.tracing.writer_options[:foo] = :bar + expect(settings.tracing.writer_options).to_not be_empty + expect(settings.tracing.options[:writer_options].default_value).to be_empty + end + end + end + + describe '#writer_options=' do + let(:options) { { priority_sampling: true } } + + it 'updates the #writer_options setting' do + expect { settings.tracing.writer_options = options } + .to change { settings.tracing.writer_options } + .from({}) + .to(options) + end + end + + describe '#x_datadog_tags_max_length' do + subject { settings.tracing.x_datadog_tags_max_length } + + context "when #{Datadog::Tracing::Configuration::Ext::Distributed::ENV_X_DATADOG_TAGS_MAX_LENGTH}" do + around do |example| + ClimateControl.modify( + Datadog::Tracing::Configuration::Ext::Distributed::ENV_X_DATADOG_TAGS_MAX_LENGTH => env_var + ) do + example.run + end + end + + context 'is not defined' do + let(:env_var) { nil } + + it { is_expected.to eq(512) } + end + + context 'is defined' do + let(:env_var) { '123' } + + it { is_expected.to eq(123) } + end + end + end + + describe '#x_datadog_tags_max_length=' do + it 'updates the #x_datadog_tags_max_length setting' do + expect { settings.tracing.x_datadog_tags_max_length = 123 } + .to change { settings.tracing.x_datadog_tags_max_length } + .from(512) + .to(123) + end + end + end +end