diff --git a/ddtrace/settings/_config.py b/ddtrace/settings/_config.py index 35d2849884d..0072986286e 100644 --- a/ddtrace/settings/_config.py +++ b/ddtrace/settings/_config.py @@ -16,8 +16,6 @@ from ddtrace.internal.serverless import in_gcp_function from ddtrace.internal.telemetry import telemetry_writer from ddtrace.internal.utils.cache import cachedmethod -from ddtrace.internal.utils.deprecations import DDTraceDeprecationWarning -from ddtrace.vendor.debtcollector import deprecate from .._trace.pin import Pin from ..internal import gitmetadata @@ -264,9 +262,11 @@ def _parse_global_tags(s): def _default_config() -> Dict[str, _ConfigItem]: return { + # Remove the _trace_sample_rate property, _trace_sampling_rules should be the source of truth "_trace_sample_rate": _ConfigItem( default=1.0, - envs=[("DD_TRACE_SAMPLE_RATE", float)], + # trace_sample_rate is placeholder, this code will be removed up after v3.0 + envs=[("trace_sample_rate", float)], ), "_trace_sampling_rules": _ConfigItem( default=lambda: "", @@ -352,14 +352,6 @@ def __init__(self): self._from_endpoint = ENDPOINT_FETCHED_CONFIG self._config = _default_config() - sample_rate = os.getenv("DD_TRACE_SAMPLE_RATE") - if sample_rate is not None: - deprecate( - "DD_TRACE_SAMPLE_RATE is deprecated", - message="Please use DD_TRACE_SAMPLING_RULES instead.", - removal_version="3.0.0", - ) - # Use a dict as underlying storing mechanism for integration configs self._integration_configs = {} @@ -368,9 +360,6 @@ def __init__(self): rate_limit = os.getenv("DD_TRACE_RATE_LIMIT") if rate_limit is not None and self._trace_sampling_rules in ("", "[]"): - # This warning will be logged when DD_TRACE_SAMPLE_RATE is set. This is intentional. - # Even though DD_TRACE_SAMPLE_RATE is treated as a global trace sampling rule, this configuration - # is deprecated. We should always encourage users to set DD_TRACE_SAMPLING_RULES instead. log.warning( "DD_TRACE_RATE_LIMIT is set to %s and DD_TRACE_SAMPLING_RULES is not set. " "Tracer rate limiting is only applied to spans that match tracer sampling rules. " @@ -388,13 +377,9 @@ def __init__(self): ) self._trace_api = _get_config("DD_TRACE_API_VERSION") if self._trace_api == "v0.3": - deprecate( - "DD_TRACE_API_VERSION=v0.3 is deprecated", - message="Traces will be submitted to the v0.4/traces agent endpoint instead.", - removal_version="3.0.0", - category=DDTraceDeprecationWarning, + log.error( + "Setting DD_TRACE_API_VERSION to ``v0.3`` is not supported. The default ``v0.5`` format will be used.", ) - self._trace_api = "v0.4" self._trace_writer_buffer_size = _get_config("DD_TRACE_WRITER_BUFFER_SIZE_BYTES", DEFAULT_BUFFER_SIZE, int) self._trace_writer_payload_size = _get_config( "DD_TRACE_WRITER_MAX_PAYLOAD_SIZE_BYTES", DEFAULT_MAX_PAYLOAD_SIZE, int @@ -418,18 +403,8 @@ def __init__(self): self._span_traceback_max_size = _get_config("DD_TRACE_SPAN_TRACEBACK_MAX_SIZE", 30, int) - # Master switch for turning on and off trace search by default - # this weird invocation of getenv is meant to read the DD_ANALYTICS_ENABLED - # legacy environment variable. It should be removed in the future - self._analytics_enabled = _get_config(["DD_TRACE_ANALYTICS_ENABLED", "DD_ANALYTICS_ENABLED"], False, asbool) - if self._analytics_enabled: - deprecate( - "Datadog App Analytics is deprecated and will be removed in a future version. " - "App Analytics can be enabled via DD_TRACE_ANALYTICS_ENABLED and DD_ANALYTICS_ENABLED " - "environment variables and ddtrace.config.analytics_enabled configuration. " - "These configurations will also be removed.", - category=DDTraceDeprecationWarning, - ) + # DD_ANALYTICS_ENABLED is not longer supported, remove this functionatiy from all integrations in the future + self._analytics_enabled = False self._client_ip_header = _get_config("DD_TRACE_CLIENT_IP_HEADER") self._retrieve_client_ip = _get_config("DD_TRACE_CLIENT_IP_ENABLED", False, asbool) @@ -477,14 +452,6 @@ def __init__(self): self._128_bit_trace_id_enabled = _get_config("DD_TRACE_128_BIT_TRACEID_GENERATION_ENABLED", True, asbool) self._128_bit_trace_id_logging_enabled = _get_config("DD_TRACE_128_BIT_TRACEID_LOGGING_ENABLED", False, asbool) - if self._128_bit_trace_id_logging_enabled: - deprecate( - "Using DD_TRACE_128_BIT_TRACEID_LOGGING_ENABLED is deprecated.", - message="Log injection format is now configured automatically.", - removal_version="3.0.0", - category=DDTraceDeprecationWarning, - ) - self._sampling_rules = _get_config("DD_SPAN_SAMPLING_RULES") self._sampling_rules_file = _get_config("DD_SPAN_SAMPLING_RULES_FILE") @@ -536,18 +503,7 @@ def __init__(self): ["DD_TRACE_COMPUTE_STATS", "DD_TRACE_STATS_COMPUTATION_ENABLED"], trace_compute_stats_default, asbool ) self._data_streams_enabled = _get_config("DD_DATA_STREAMS_ENABLED", False, asbool) - - legacy_client_tag_enabled = _get_config("DD_HTTP_CLIENT_TAG_QUERY_STRING") - if legacy_client_tag_enabled is None: - self._http_client_tag_query_string = _get_config("DD_TRACE_HTTP_CLIENT_TAG_QUERY_STRING", "true") - else: - deprecate( - "DD_HTTP_CLIENT_TAG_QUERY_STRING is deprecated", - message="Please use DD_TRACE_HTTP_CLIENT_TAG_QUERY_STRING instead.", - removal_version="3.0.0", - category=DDTraceDeprecationWarning, - ) - self._http_client_tag_query_string = legacy_client_tag_enabled.lower() + self._http_client_tag_query_string = _get_config("DD_TRACE_HTTP_CLIENT_TAG_QUERY_STRING", "true") dd_trace_obfuscation_query_string_regexp = _get_config( "DD_TRACE_OBFUSCATION_QUERY_STRING_REGEXP", DD_TRACE_OBFUSCATION_QUERY_STRING_REGEXP_DEFAULT @@ -577,15 +533,8 @@ def __init__(self): # https://github.com/open-telemetry/opentelemetry-python/blob/v1.16.0/opentelemetry-api/src/opentelemetry/context/__init__.py#L53 os.environ["OTEL_PYTHON_CONTEXT"] = "ddcontextvars_context" self._subscriptions = [] # type: List[Tuple[List[str], Callable[[Config, List[str]], None]]] - self._span_aggregator_rlock = _get_config("DD_TRACE_SPAN_AGGREGATOR_RLOCK", True, asbool) - if self._span_aggregator_rlock is False: - deprecate( - "DD_TRACE_SPAN_AGGREGATOR_RLOCK is deprecated", - message="Soon the ddtrace library will only support using threading.Rlock to " - "aggregate and encode span data. If you need to disable the re-entrant lock and " - "revert to using threading.Lock, please contact Datadog support.", - removal_version="3.0.0", - ) + # Disabled Span Aggregator Rlock is not supported. Remove this configuration in the future + self._span_aggregator_rlock = True self._trace_methods = _get_config("DD_TRACE_METHODS") diff --git a/ddtrace/settings/_otel_remapper.py b/ddtrace/settings/_otel_remapper.py index ec238e8a3cb..e495f783cd3 100644 --- a/ddtrace/settings/_otel_remapper.py +++ b/ddtrace/settings/_otel_remapper.py @@ -52,12 +52,16 @@ def _remap_traces_sampler(otel_value: str) -> Optional[str]: otel_value, ) otel_value = f"parentbased_{otel_value}" + rate = None if otel_value == "parentbased_always_on": - return "1.0" + rate = "1.0" elif otel_value == "parentbased_always_off": - return "0.0" + rate = "0.0" elif otel_value == "parentbased_traceidratio": - return os.environ.get("OTEL_TRACES_SAMPLER_ARG", "1") + rate = os.environ.get("OTEL_TRACES_SAMPLER_ARG", "1") + + if rate is not None: + return f'[{{"sample_rate":{rate}}}]' return None @@ -130,7 +134,7 @@ def _remap_default(otel_value: str) -> Optional[str]: "OTEL_SERVICE_NAME": ("DD_SERVICE", _remap_default), "OTEL_LOG_LEVEL": ("DD_TRACE_DEBUG", _remap_otel_log_level), "OTEL_PROPAGATORS": ("DD_TRACE_PROPAGATION_STYLE", _remap_otel_propagators), - "OTEL_TRACES_SAMPLER": ("DD_TRACE_SAMPLE_RATE", _remap_traces_sampler), + "OTEL_TRACES_SAMPLER": ("DD_TRACE_SAMPLING_RULES", _remap_traces_sampler), "OTEL_TRACES_EXPORTER": ("DD_TRACE_ENABLED", _remap_traces_exporter), "OTEL_METRICS_EXPORTER": ("DD_RUNTIME_METRICS_ENABLED", _remap_metrics_exporter), "OTEL_LOGS_EXPORTER": ("", _validate_logs_exporter), # Does not set a DDTRACE environment variable. diff --git a/ddtrace/settings/config.py b/ddtrace/settings/config.py deleted file mode 100644 index 00c0ee9917c..00000000000 --- a/ddtrace/settings/config.py +++ /dev/null @@ -1,11 +0,0 @@ -from ddtrace.internal.utils.deprecations import DDTraceDeprecationWarning -from ddtrace.settings._config import * # noqa: F403 -from ddtrace.vendor.debtcollector import deprecate - - -deprecate( - "The ddtrace.settings.config module is deprecated", - message="Access the global configuration using ``ddtrace.config``.", - category=DDTraceDeprecationWarning, - removal_version="3.0.0", -) diff --git a/ddtrace/settings/integration.py b/ddtrace/settings/integration.py index 354e99f7625..eef7f5c81c6 100644 --- a/ddtrace/settings/integration.py +++ b/ddtrace/settings/integration.py @@ -1,13 +1,8 @@ import os from typing import Optional # noqa:F401 -from typing import Tuple # noqa:F401 - -from ddtrace.internal.utils.deprecations import DDTraceDeprecationWarning -from ddtrace.vendor.debtcollector import deprecate from .._hooks import Hooks from ..internal.utils.attrdict import AttrDict -from ..internal.utils.formats import asbool from .http import HttpConfig @@ -43,9 +38,10 @@ def __init__(self, global_config, name, *args, **kwargs): object.__setattr__(self, "hooks", Hooks()) object.__setattr__(self, "http", HttpConfig()) - analytics_enabled, analytics_sample_rate = self._get_analytics_settings() - self.setdefault("analytics_enabled", analytics_enabled) - self.setdefault("analytics_sample_rate", float(analytics_sample_rate)) + # Trace Analytics was removed in v3.0.0 + # TODO(munir): Remove all references to analytics_enabled and analytics_sample_rate + self.setdefault("analytics_enabled", False) + self.setdefault("analytics_sample_rate", 1.0) service = os.getenv( "DD_%s_SERVICE" % name.upper(), default=os.getenv( @@ -65,33 +61,6 @@ def __init__(self, global_config, name, *args, **kwargs): self.get_http_tag_query_string(getattr(self, "default_http_tag_query_string", None)), ) - def _get_analytics_settings(self): - # type: () -> Tuple[Optional[bool], float] - # Set default analytics configuration, default is disabled - # DEV: Default to `None` which means do not set this key - # Inject environment variables for integration - env = "DD_TRACE_%s_ANALYTICS_ENABLED" % self.integration_name.upper() - legacy_env = "DD_%s_ANALYTICS_ENABLED" % self.integration_name.upper() - analytics_enabled = asbool(os.getenv(env, os.getenv(legacy_env, default=None))) - - if analytics_enabled: - deprecate( - "Datadog App Analytics is deprecated. " - f"App Analytics can be enabled via {env} and {legacy_env} " - f"environment variables and the ddtrace.config.{self.integration_name}.analytics_enabled configuration." - " This feature and its associated configurations will be removed in a future release.", - category=DDTraceDeprecationWarning, - ) - - analytics_sample_rate = float( - os.getenv( - "DD_TRACE_%s_ANALYTICS_SAMPLE_RATE" % self.integration_name.upper(), - os.getenv("DD_%s_ANALYTICS_SAMPLE_RATE" % self.integration_name.upper(), default=1.0), - ) - ) - - return analytics_enabled, analytics_sample_rate - def get_http_tag_query_string(self, value): if self.global_config._http_tag_query_string: dd_http_server_tag_query_string = value if value else os.getenv("DD_HTTP_SERVER_TAG_QUERY_STRING", "true") diff --git a/docs/advanced_usage.rst b/docs/advanced_usage.rst index 5fe21321680..e6ead60c1f5 100644 --- a/docs/advanced_usage.rst +++ b/docs/advanced_usage.rst @@ -1,28 +1,6 @@ Advanced Usage ============== -.. _agentconfiguration: - -Agent Configuration -------------------- - -If the Datadog Agent is on a separate host from your application, you can modify -the default ``ddtrace.tracer`` object to utilize another hostname and port. Here -is a small example showcasing this:: - - from ddtrace.trace import tracer - - tracer.configure(hostname=, port=, https=) - -By default, these will be set to ``localhost``, ``8126``, and ``False`` respectively. - -You can also use a Unix Domain Socket to connect to the agent:: - - from ddtrace.trace import tracer - - tracer.configure(uds_path="/path/to/socket") - - .. _context: @@ -223,7 +201,7 @@ provider can be used. It must implement the :class:`ddtrace.trace.BaseContextProvider` interface and can be configured with:: - tracer.configure(context_provider=MyContextProvider) + tracer.configure(context_provider=MyContextProvider()) .. _disttracing: diff --git a/docs/configuration.rst b/docs/configuration.rst index f45ac992582..6f5c87a945e 100644 --- a/docs/configuration.rst +++ b/docs/configuration.rst @@ -817,6 +817,7 @@ Sampling version_added: v0.33.0: v2.15.0: Only applied when DD_TRACE_SAMPLE_RATE, DD_TRACE_SAMPLING_RULES, or DD_SPAN_SAMPLING_RULE are set. + v3.0.0: Only applied when DD_TRACE_SAMPLING_RULES or DD_SPAN_SAMPLING_RULE are set. DD_TRACE_SAMPLING_RULES: type: JSON array diff --git a/releasenotes/notes/remove-deprecated-tracing-configs-c6711b57037576f6.yaml b/releasenotes/notes/remove-deprecated-tracing-configs-c6711b57037576f6.yaml new file mode 100644 index 00000000000..b47613d504e --- /dev/null +++ b/releasenotes/notes/remove-deprecated-tracing-configs-c6711b57037576f6.yaml @@ -0,0 +1,10 @@ +--- +upgrade: + - | + configurations: Drops support for deprecated tracing configurations. The following configurations are no longer supported: + - DD_TRACE_SAMPLE_RATE, use DD_TRACE_SAMPLING_RULES instead. + - DD_TRACE_API_VERSION=v0.3, the default ``v0.5`` version is used instead. + - DD_ANALYTICS_ENABLED, Datadog Analytics is no longer supported. + - DD_TRACE_ANALYTICS_ENABLED, Datadog Analytics is no longer supported. + - DD_HTTP_CLIENT_TAG_QUERY_STRING, DD_TRACE_HTTP_CLIENT_TAG_QUERY_STRING should be used instead. + - DD_TRACE_SPAN_AGGREGATOR_RLOCK, disabling the span aggregator rlock is no longer supported. diff --git a/tests/appsec/iast/test_processor.py b/tests/appsec/iast/test_processor.py index 3bb5eaa5015..4f9b912ffc2 100644 --- a/tests/appsec/iast/test_processor.py +++ b/tests/appsec/iast/test_processor.py @@ -51,7 +51,7 @@ def test_appsec_iast_processor_ensure_span_is_manual_keep(iast_context_defaults, test_appsec_iast_processor_ensure_span_is_manual_keep. This test throws 'finished span not connected to a trace' log error """ - with override_env(dict(DD_TRACE_SAMPLE_RATE=sampling_rate)): + with override_env({"DD_TRACE_SAMPLING_RULES": '[{"sample_rate":%s]"}]' % (sampling_rate,)}): oce.reconfigure() tracer = DummyTracer(iast_enabled=True) @@ -59,7 +59,6 @@ def test_appsec_iast_processor_ensure_span_is_manual_keep(iast_context_defaults, tracer._on_span_finish(span) result = span.get_tag(IAST.JSON) - assert len(json.loads(result)["vulnerabilities"]) == 1 assert span.get_metric(_SAMPLING_PRIORITY_KEY) is USER_KEEP diff --git a/tests/integration/test_settings.py b/tests/integration/test_settings.py index 249b0211bb4..ba9bcd66f37 100644 --- a/tests/integration/test_settings.py +++ b/tests/integration/test_settings.py @@ -20,7 +20,7 @@ def test_setting_origin_environment(test_agent_session, run_python_code_in_subpr env = os.environ.copy() env.update( { - "DD_TRACE_SAMPLE_RATE": "0.1", + "DD_TRACE_SAMPLING_RULES": '[{"sample_rate":0.1}]', "DD_LOGS_INJECTION": "true", "DD_TRACE_HEADER_TAGS": "X-Header-Tag-1:header_tag_1,X-Header-Tag-2:header_tag_2", "DD_TAGS": "team:apm,component:web", @@ -39,11 +39,11 @@ def test_setting_origin_environment(test_agent_session, run_python_code_in_subpr assert status == 0, err events = test_agent_session.get_events(subprocess=True) - events_trace_sample_rate = _get_telemetry_config_items(events, "DD_TRACE_SAMPLE_RATE") + events_trace_sample_rate = _get_telemetry_config_items(events, "DD_TRACE_SAMPLING_RULES") assert { - "name": "DD_TRACE_SAMPLE_RATE", - "value": 0.1, + "name": "DD_TRACE_SAMPLING_RULES", + "value": '[{"sample_rate":0.1}]', "origin": "env_var", } in events_trace_sample_rate @@ -69,7 +69,6 @@ def test_setting_origin_code(test_agent_session, run_python_code_in_subprocess): env = os.environ.copy() env.update( { - "DD_TRACE_SAMPLE_RATE": "0.1", "DD_LOGS_INJECTION": "true", "DD_TRACE_HEADER_TAGS": "X-Header-Tag-1:header_tag_1,X-Header-Tag-2:header_tag_2", "DD_TAGS": "team:apm,component:web", @@ -81,7 +80,6 @@ def test_setting_origin_code(test_agent_session, run_python_code_in_subprocess): """ from ddtrace import config, tracer -config._trace_sample_rate = 0.2 config._logs_injection = False config._trace_http_header_tags = {"header": "value"} config.tags = {"header": "value"} @@ -96,12 +94,6 @@ def test_setting_origin_code(test_agent_session, run_python_code_in_subprocess): assert status == 0, err events = test_agent_session.get_events(subprocess=True) - events_trace_sample_rate = _get_telemetry_config_items(events, "DD_TRACE_SAMPLE_RATE") - assert { - "name": "DD_TRACE_SAMPLE_RATE", - "value": 0.2, - "origin": "code", - } in events_trace_sample_rate events_logs_injection_enabled = _get_telemetry_config_items(events, "DD_LOGS_INJECTION") assert { @@ -174,8 +166,8 @@ def test_remoteconfig_sampling_rate_default(test_agent_session, run_python_code_ assert status == 0, err events = test_agent_session.get_events(subprocess=True) - events_trace_sample_rate = _get_telemetry_config_items(events, "DD_TRACE_SAMPLE_RATE") - assert {"name": "DD_TRACE_SAMPLE_RATE", "value": 1.0, "origin": "default"} in events_trace_sample_rate + events_trace_sample_rate = _get_telemetry_config_items(events, "trace_sample_rate") + assert {"name": "trace_sample_rate", "value": 1.0, "origin": "default"} in events_trace_sample_rate @pytest.mark.skipif(AGENT_VERSION != "testagent", reason="Tests only compatible with a testagent") @@ -191,7 +183,22 @@ def test_remoteconfig_sampling_rate_telemetry(test_agent_session, run_python_cod from ddtrace import config, tracer from tests.internal.test_settings import _base_rc_config -config._handle_remoteconfig(_base_rc_config({"tracing_sampling_rate": 0.5})) +config._handle_remoteconfig( + _base_rc_config( + { + "tracing_sampling_rules": [ + { + "sample_rate": "0.5", + "service": "*", + "name": "*", + "resource": "*", + "tags": {}, + "provenance": "customer", + } + ] + } + ) +) with tracer.trace("test") as span: pass assert span.get_metric("_dd.rule_psr") == 0.5 @@ -201,8 +208,13 @@ def test_remoteconfig_sampling_rate_telemetry(test_agent_session, run_python_cod assert status == 0, err events = test_agent_session.get_events(subprocess=True) - events_trace_sample_rate = _get_telemetry_config_items(events, "DD_TRACE_SAMPLE_RATE") - assert {"name": "DD_TRACE_SAMPLE_RATE", "value": 0.5, "origin": "remote_config"} in events_trace_sample_rate + events_trace_sample_rate = _get_telemetry_config_items(events, "DD_TRACE_SAMPLING_RULES") + assert { + "name": "DD_TRACE_SAMPLING_RULES", + "origin": "remote_config", + "value": '[{"sample_rate": "0.5", "service": "*", "name": "*", "resource": "*", ' + '"tags": {}, "provenance": "customer"}]', + } in events_trace_sample_rate @pytest.mark.skipif(AGENT_VERSION != "testagent", reason="Tests only compatible with a testagent") @@ -226,9 +238,11 @@ def test_remoteconfig_header_tags_telemetry(test_agent_session, run_python_code_ {"header": "used-with-default", "tag_name":""}] })) with tracer.trace("test") as span: - trace_utils.set_http_meta(span, - config.falcon, # randomly chosen http integration config - request_headers={"used": "foobarbanana", "used-with-default": "defaultname"}) + trace_utils.set_http_meta( + span, + config.falcon, # randomly chosen http integration config + request_headers={"used": "foobarbanana", "used-with-default": "defaultname"}, + ) assert span.get_tag("header_tag_69") == "foobarbanana" assert span.get_tag("header_tag_70") is None assert span.get_tag("http.request.headers.used-with-default") == "defaultname" diff --git a/tests/internal/test_settings.py b/tests/internal/test_settings.py index 2ff1843690e..a26d692eea4 100644 --- a/tests/internal/test_settings.py +++ b/tests/internal/test_settings.py @@ -62,22 +62,36 @@ def _deleted_rc_config(): }, }, { - "env": {"DD_TRACE_SAMPLE_RATE": "0.9"}, - "expected": {"_trace_sample_rate": 0.9}, - "expected_source": {"_trace_sample_rate": "env_var"}, + "env": {"DD_TRACE_SAMPLING_RULES": '[{"sample_rate":0.91}]'}, + "expected": {"_trace_sampling_rules": '[{"sample_rate":0.91}]'}, + "expected_source": {"_trace_sampling_rules": "env_var"}, }, { - "env": {"DD_TRACE_SAMPLE_RATE": "0.9"}, - "code": {"_trace_sample_rate": 0.8}, - "expected": {"_trace_sample_rate": 0.8}, - "expected_source": {"_trace_sample_rate": "code"}, + "env": {"DD_TRACE_SAMPLING_RULES": '[{"sample_rate":0.92}]'}, + "code": {"_trace_sampling_rules": '[{"sample_rate":0.82}]'}, + "expected": {"_trace_sampling_rules": '[{"sample_rate":0.82}]'}, + "expected_source": {"_trace_sampling_rules": "code"}, }, { - "env": {"DD_TRACE_SAMPLE_RATE": "0.9"}, - "code": {"_trace_sample_rate": 0.8}, - "rc": {"tracing_sampling_rate": 0.7}, - "expected": {"_trace_sample_rate": 0.7}, - "expected_source": {"_trace_sample_rate": "remote_config"}, + "env": {"DD_TRACE_SAMPLING_RULES": '[{"sample_rate":0.93}]'}, + "code": {"_trace_sampling_rules": '[{"sample_rate":0.83}]'}, + "rc": { + "tracing_sampling_rules": [ + { + "sample_rate": "0.73", + "service": "*", + "name": "*", + "resource": "*", + "tags": [], + "provenance": "customer", + } + ] + }, + "expected": { + "_trace_sampling_rules": '[{"sample_rate": "0.73", "service": "*", "name": "*", ' + '"resource": "*", "tags": [], "provenance": "customer"}]', + }, + "expected_source": {"_trace_sampling_rules": "remote_config"}, }, { "env": {"DD_LOGS_INJECTION": "true"}, @@ -227,60 +241,6 @@ def test_config_subscription(config): _handler.assert_called_once_with(config, [s]) -def test_remoteconfig_sampling_rate_user(run_python_code_in_subprocess): - env = os.environ.copy() - env.update({"DD_TRACE_SAMPLE_RATE": "0.1"}) - out, err, status, _ = run_python_code_in_subprocess( - """ -from ddtrace import config, tracer -from ddtrace._trace.sampler import DatadogSampler -from tests.internal.test_settings import _base_rc_config, _deleted_rc_config - -with tracer.trace("test") as span: - pass -assert span.get_metric("_dd.rule_psr") == 0.1 - -config._handle_remoteconfig(_base_rc_config({"tracing_sampling_rate": 0.2})) -with tracer.trace("test") as span: - pass -assert span.get_metric("_dd.rule_psr") == 0.2 - -config._handle_remoteconfig(_base_rc_config({})) -with tracer.trace("test") as span: - pass -assert span.get_metric("_dd.rule_psr") == 0.1 - -custom_sampler = DatadogSampler(default_sample_rate=0.3) -tracer._configure(sampler=custom_sampler) -with tracer.trace("test") as span: - pass -assert span.get_metric("_dd.rule_psr") == 0.3 - -config._handle_remoteconfig(_base_rc_config({"tracing_sampling_rate": 0.4})) -with tracer.trace("test") as span: - pass -assert span.get_metric("_dd.rule_psr") == 0.4 - -config._handle_remoteconfig(_base_rc_config({})) -with tracer.trace("test") as span: - pass -assert span.get_metric("_dd.rule_psr") == 0.3 - -config._handle_remoteconfig(_base_rc_config({"tracing_sampling_rate": 0.4})) -with tracer.trace("test") as span: - pass -assert span.get_metric("_dd.rule_psr") == 0.4 - -config._handle_remoteconfig(_deleted_rc_config()) -with tracer.trace("test") as span: - pass -assert span.get_metric("_dd.rule_psr") == 0.3 - """, - env=env, - ) - assert status == 0, err.decode("utf-8") - - def test_remoteconfig_sampling_rules(run_python_code_in_subprocess): env = os.environ.copy() env.update({"DD_TRACE_SAMPLING_RULES": '[{"sample_rate":0.1, "name":"test"}]'}) @@ -368,13 +328,12 @@ def test_remoteconfig_sampling_rules(run_python_code_in_subprocess): assert status == 0, err.decode("utf-8") -def test_remoteconfig_sample_rate_and_rules(run_python_code_in_subprocess): +def test_remoteconfig_global_sample_rate_and_rules(run_python_code_in_subprocess): """There is complex logic regarding the interaction between setting new sample rates and rules with remote config. """ env = os.environ.copy() - env.update({"DD_TRACE_SAMPLING_RULES": '[{"sample_rate":0.9, "name":"rules"}]'}) - env.update({"DD_TRACE_SAMPLE_RATE": "0.8"}) + env.update({"DD_TRACE_SAMPLING_RULES": '[{"sample_rate":0.9, "name":"rules"}, {"sample_rate":0.8}]'}) out, err, status, _ = run_python_code_in_subprocess( """ @@ -410,8 +369,9 @@ def test_remoteconfig_sample_rate_and_rules(run_python_code_in_subprocess): with tracer.trace("sample_rate") as span: pass -assert span.get_metric("_dd.rule_psr") == 0.8 -assert span.get_tag("_dd.p.dm") == "-3" +# Global sampling rule was overwritten +assert span.get_metric("_dd.rule_psr") is None +assert span.get_tag("_dd.p.dm") == "-0" config._handle_remoteconfig(_base_rc_config({"tracing_sampling_rate": 0.2})) @@ -482,8 +442,8 @@ def test_remoteconfig_sample_rate_and_rules(run_python_code_in_subprocess): with tracer.trace("sample_rate") as span: pass -assert span.get_metric("_dd.rule_psr") == 0.8 -assert span.get_tag("_dd.p.dm") == "-3" +assert span.get_metric("_dd.rule_psr") is None +assert span.get_tag("_dd.p.dm") == "-0" """, env=env, diff --git a/tests/opentelemetry/test_config.py b/tests/opentelemetry/test_config.py index 39a43128e9e..d5e9bf570fd 100644 --- a/tests/opentelemetry/test_config.py +++ b/tests/opentelemetry/test_config.py @@ -1,6 +1,24 @@ import pytest +def _global_sampling_rule(): + from ddtrace._trace.sampling_rule import SamplingRule + from ddtrace.trace import tracer + + assert hasattr(tracer._sampler, "rules") + + for rule in tracer._sampler.rules: + if ( + rule.service == SamplingRule.NO_RULE + and rule.name == SamplingRule.NO_RULE + and rule.resource == SamplingRule.NO_RULE + and rule.tags == SamplingRule.NO_RULE + and rule.provenance == "default" + ): + return rule + assert False, "Rule not found" + + @pytest.mark.subprocess( env={ "OTEL_SERVICE_NAME": "Test", @@ -10,7 +28,7 @@ "OTEL_PROPAGATORS": "jaegar, tracecontext, b3", "DD_TRACE_PROPAGATION_STYLE": "b3", "OTEL_TRACES_SAMPLER": "always_off", - "DD_TRACE_SAMPLE_RATE": "1.0", + "DD_TRACE_SAMPLING_RULES": '[{"sample_rate":0.1}]', "OTEL_TRACES_EXPORTER": "True", "DD_TRACE_ENABLED": "True", "OTEL_METRICS_EXPORTER": "none", @@ -26,11 +44,12 @@ ) def test_dd_otel_mixed_env_configuration(): from ddtrace import config + from tests.opentelemetry.test_config import _global_sampling_rule assert config.service == "DD_service_test", config.service assert config._debug_mode is False, config._debug_mode assert config._propagation_style_extract == ["b3"], config._propagation_style_extract - assert config._trace_sample_rate == 1.0, config._trace_sample_rate + assert _global_sampling_rule().sample_rate == 0.1 assert config._tracing_enabled is True, config._tracing_enabled assert config._runtime_metrics_enabled is True, config._runtime_metrics_enabled assert config._otel_enabled is True, config._otel_enabled @@ -45,7 +64,7 @@ def test_dd_otel_mixed_env_configuration(): "OTEL_LOG_LEVEL": "debug", "OTEL_PROPAGATORS": "jaegar, tracecontext, b3", "OTEL_TRACES_SAMPLER": "always_off", - "DD_TRACE_SAMPLE_RATE": "1.0", + "DD_TRACE_SAMPLING_RULES": '[{"sample_rate":0.9}]', "OTEL_TRACES_EXPORTER": "OTLP", "OTEL_METRICS_EXPORTER": "none", "OTEL_LOGS_EXPORTER": "warning", @@ -59,13 +78,14 @@ def test_dd_otel_mixed_env_configuration(): ) def test_dd_otel_missing_dd_env_configuration(): from ddtrace import config + from tests.opentelemetry.test_config import _global_sampling_rule assert config.service == "Test", config.service assert config.version == "1.0" assert config._otel_enabled is True, config._otel_enabled assert config._debug_mode is True, config._debug_mode assert config._propagation_style_extract == ["tracecontext", "b3"], config._propagation_style_extract - assert config._trace_sample_rate == 1.0, config._trace_sample_rate + assert _global_sampling_rule().sample_rate == 0.9 assert config._tracing_enabled is True, config._tracing_enabled assert config._runtime_metrics_enabled is False, config._runtime_metrics_enabled assert config.tags == { @@ -133,8 +153,9 @@ def test_otel_propagation_style_configuration_unsupportedwarning(): ) def test_otel_traces_sampler_configuration_alwayson(): from ddtrace import config + from tests.opentelemetry.test_config import _global_sampling_rule - assert config._trace_sample_rate == 1.0, config._trace_sample_rate + assert _global_sampling_rule().sample_rate == 1.0, config._trace_sample_rate @pytest.mark.subprocess( @@ -143,8 +164,9 @@ def test_otel_traces_sampler_configuration_alwayson(): ) def test_otel_traces_sampler_configuration_ignore_parent(): from ddtrace import config + from tests.opentelemetry.test_config import _global_sampling_rule - assert config._trace_sample_rate == 1.0, config._trace_sample_rate + assert _global_sampling_rule().sample_rate == 1.0, config._trace_sample_rate @pytest.mark.subprocess( @@ -153,8 +175,9 @@ def test_otel_traces_sampler_configuration_ignore_parent(): ) def test_otel_traces_sampler_configuration_alwaysoff(): from ddtrace import config + from tests.opentelemetry.test_config import _global_sampling_rule - assert config._trace_sample_rate == 0.0, config._trace_sample_rate + assert _global_sampling_rule().sample_rate == 0.0, config._trace_sample_rate @pytest.mark.subprocess( @@ -167,8 +190,9 @@ def test_otel_traces_sampler_configuration_alwaysoff(): ) def test_otel_traces_sampler_configuration_traceidratio(): from ddtrace import config + from tests.opentelemetry.test_config import _global_sampling_rule - assert config._trace_sample_rate == 0.5, config._trace_sample_rate + assert _global_sampling_rule().sample_rate == 0.5, config._trace_sample_rate @pytest.mark.subprocess(env={"OTEL_TRACES_EXPORTER": "none"}) diff --git a/tests/suitespec.yml b/tests/suitespec.yml index d9da18df66d..69c6b19e8d8 100644 --- a/tests/suitespec.yml +++ b/tests/suitespec.yml @@ -76,7 +76,7 @@ components: - ddtrace/__init__.py - ddtrace/py.typed - ddtrace/version.py - - ddtrace/settings/config.py + - ddtrace/settings/_config.py - src/native/* datastreams: - ddtrace/internal/datastreams/* @@ -117,7 +117,7 @@ components: - ddtrace/trace/* - ddtrace/constants.py - ddtrace/settings/__init__.py - - ddtrace/settings/config.py + - ddtrace/settings/_config.py - ddtrace/settings/http.py - ddtrace/settings/exceptions.py - ddtrace/settings/integration.py diff --git a/tests/telemetry/test_writer.py b/tests/telemetry/test_writer.py index 39d672a1c01..2de23c9fba3 100644 --- a/tests/telemetry/test_writer.py +++ b/tests/telemetry/test_writer.py @@ -118,7 +118,6 @@ def test_app_started_event(telemetry_writer, test_agent_session, mock_time): {"name": "DD_SPAN_SAMPLING_RULES_FILE", "origin": "unknown", "value": None}, {"name": "DD_TRACE_128_BIT_TRACEID_GENERATION_ENABLED", "origin": "unknown", "value": True}, {"name": "DD_TRACE_AGENT_TIMEOUT_SECONDS", "origin": "unknown", "value": 2.0}, - {"name": "DD_TRACE_ANALYTICS_ENABLED", "origin": "unknown", "value": False}, {"name": "DD_TRACE_API_VERSION", "origin": "unknown", "value": None}, {"name": "DD_TRACE_CLIENT_IP_ENABLED", "origin": "unknown", "value": None}, {"name": "DD_TRACE_COMPUTE_STATS", "origin": "unknown", "value": False}, @@ -225,7 +224,6 @@ def test_app_started_event_configuration_override(test_agent_session, run_python env["DD_RUNTIME_METRICS_ENABLED"] = "True" env["DD_SERVICE_MAPPING"] = "default_dd_service:remapped_dd_service" env["DD_TRACE_128_BIT_TRACEID_GENERATION_ENABLED"] = "True" - env["DD_TRACE_ANALYTICS_ENABLED"] = "True" env["DD_TRACE_CLIENT_IP_ENABLED"] = "True" env["DD_TRACE_COMPUTE_STATS"] = "True" env["DD_TRACE_DEBUG"] = "True" @@ -237,7 +235,6 @@ def test_app_started_event_configuration_override(test_agent_session, run_python env["DD_TRACE_PROPAGATION_STYLE_INJECT"] = "tracecontext" env["DD_REMOTE_CONFIGURATION_ENABLED"] = "True" env["DD_REMOTE_CONFIG_POLL_INTERVAL_SECONDS"] = "1" - env["DD_TRACE_SAMPLE_RATE"] = "0.5" env["DD_TRACE_RATE_LIMIT"] = "50" env["DD_TRACE_SAMPLING_RULES"] = '[{"sample_rate":1.0,"service":"xyz","name":"abc"}]' env["DD_PROFILING_ENABLED"] = "True" @@ -356,7 +353,6 @@ def test_app_started_event_configuration_override(test_agent_session, run_python {"name": "DD_EXCEPTION_REPLAY_CAPTURE_MAX_FRAMES", "origin": "default", "value": 8}, {"name": "DD_EXCEPTION_REPLAY_ENABLED", "origin": "env_var", "value": True}, {"name": "DD_EXPERIMENTAL_APPSEC_STANDALONE_ENABLED", "origin": "default", "value": False}, - {"name": "DD_HTTP_CLIENT_TAG_QUERY_STRING", "origin": "default", "value": None}, {"name": "DD_IAST_DEDUPLICATION_ENABLED", "origin": "default", "value": True}, {"name": "DD_IAST_ENABLED", "origin": "default", "value": False}, {"name": "DD_IAST_MAX_CONCURRENT_REQUESTS", "origin": "default", "value": 2}, @@ -433,7 +429,6 @@ def test_app_started_event_configuration_override(test_agent_session, run_python {"name": "DD_TRACE_128_BIT_TRACEID_GENERATION_ENABLED", "origin": "env_var", "value": True}, {"name": "DD_TRACE_128_BIT_TRACEID_LOGGING_ENABLED", "origin": "default", "value": False}, {"name": "DD_TRACE_AGENT_TIMEOUT_SECONDS", "origin": "default", "value": 2.0}, - {"name": "DD_TRACE_ANALYTICS_ENABLED", "origin": "env_var", "value": True}, {"name": "DD_TRACE_API_VERSION", "origin": "env_var", "value": "v0.5"}, {"name": "DD_TRACE_CLIENT_IP_ENABLED", "origin": "env_var", "value": True}, {"name": "DD_TRACE_CLIENT_IP_HEADER", "origin": "default", "value": None}, @@ -456,13 +451,11 @@ def test_app_started_event_configuration_override(test_agent_session, run_python {"name": "DD_TRACE_PROPAGATION_STYLE_INJECT", "origin": "env_var", "value": "tracecontext"}, {"name": "DD_TRACE_RATE_LIMIT", "origin": "env_var", "value": 50}, {"name": "DD_TRACE_REPORT_HOSTNAME", "origin": "default", "value": False}, - {"name": "DD_TRACE_SAMPLE_RATE", "origin": "env_var", "value": 0.5}, { "name": "DD_TRACE_SAMPLING_RULES", "origin": "env_var", "value": '[{"sample_rate":1.0,"service":"xyz","name":"abc"}]', }, - {"name": "DD_TRACE_SPAN_AGGREGATOR_RLOCK", "origin": "default", "value": True}, {"name": "DD_TRACE_SPAN_TRACEBACK_MAX_SIZE", "origin": "default", "value": 30}, {"name": "DD_TRACE_STARTUP_LOGS", "origin": "env_var", "value": True}, {"name": "DD_TRACE_WRITER_BUFFER_SIZE_BYTES", "origin": "env_var", "value": 1000}, @@ -483,6 +476,7 @@ def test_app_started_event_configuration_override(test_agent_session, run_python {"name": "python_build_gnu_type", "origin": "unknown", "value": sysconfig.get_config_var("BUILD_GNU_TYPE")}, {"name": "python_host_gnu_type", "origin": "unknown", "value": sysconfig.get_config_var("HOST_GNU_TYPE")}, {"name": "python_soabi", "origin": "unknown", "value": sysconfig.get_config_var("SOABI")}, + {"name": "trace_sample_rate", "origin": "default", "value": 1.0}, ] assert configurations == expected, configurations diff --git a/tests/tracer/test_encoders.py b/tests/tracer/test_encoders.py index 7006bc6b95d..4fe48a2a838 100644 --- a/tests/tracer/test_encoders.py +++ b/tests/tracer/test_encoders.py @@ -869,19 +869,3 @@ def test_json_encoder_traces_bytes(): assert "\\x80span.a" == span_a["name"] assert "\x80span.b" == span_b["name"] assert "\x80span.b" == span_c["name"] - - -@pytest.mark.subprocess(env={"DD_TRACE_API_VERSION": "v0.3"}) -def test_v03_trace_api_deprecation(): - import warnings - - with warnings.catch_warnings(record=True) as warns: - warnings.simplefilter("always") - from ddtrace.trace import tracer - - assert tracer._writer._api_version == "v0.4" - assert len(warns) == 1, warns - assert ( - warns[0].message.args[0] == "DD_TRACE_API_VERSION=v0.3 is deprecated and will be " - "removed in version '3.0.0': Traces will be submitted to the v0.4/traces agent endpoint instead." - ), warns[0].message diff --git a/tests/tracer/test_sampler.py b/tests/tracer/test_sampler.py index 22620d8184b..f54c7de55da 100644 --- a/tests/tracer/test_sampler.py +++ b/tests/tracer/test_sampler.py @@ -568,21 +568,6 @@ def test_sampling_rule_sample(): ) -@pytest.mark.subprocess(env={"DD_TRACE_SAMPLE_RATE": "0.2"}) -def test_sampling_rate_config_deprecated(): - import warnings - - with warnings.catch_warnings(record=True) as ws: - warnings.simplefilter("always") - - from ddtrace import config - - assert config._trace_sample_rate == 0.2 - - assert len(ws) >= 1 - assert any(w for w in ws if "DD_TRACE_SAMPLE_RATE is deprecated" in str(w.message)), [w.message for w in ws] - - def test_sampling_rule_sample_rate_1(): rule = SamplingRule(sample_rate=1) @@ -650,15 +635,6 @@ def test_datadog_sampler_init(): SamplingRule(sample_rate=0.5) ], "DatadogSampler initialized with no arguments and envvars set should hold a sample_rate from the envvar" - with override_global_config(dict(_trace_sample_rate=0)): - sampler = DatadogSampler() - assert ( - sampler.limiter.rate_limit == DatadogSampler.DEFAULT_RATE_LIMIT - ), "DatadogSampler initialized with DD_TRACE_SAMPLE_RATE=0 envvar should hold the default rate limit" - assert sampler.rules == [ - SamplingRule(sample_rate=0) - ], "DatadogSampler initialized with DD_TRACE_SAMPLE_RATE=0 envvar should hold sample_rate=0" - with override_global_config(dict(_trace_sample_rate="asdf")): with pytest.raises(ValueError): DatadogSampler()