From 3128327807f9df4c0bf89a18d526477ae72bb52c Mon Sep 17 00:00:00 2001 From: Emmett Butler <723615+emmettbutler@users.noreply.github.com> Date: Fri, 17 Oct 2025 11:22:07 -0700 Subject: [PATCH 1/5] chore: remove cassandra integration (#14936) This change removes the `cassandra` contrib package, which is only tested on the to-be-removed Python 3.8 runtime. --- .riot/requirements/164d658.txt | 27 - .riot/requirements/f229429.txt | 27 - ddtrace/_monkey.py | 4 +- .../integration_registry/registry.yaml | 10 - .../contrib/internal/cassandra/__init__.py | 24 - ddtrace/contrib/internal/cassandra/patch.py | 9 - ddtrace/contrib/internal/cassandra/session.py | 316 ---------- ddtrace/ext/cassandra.py | 6 - ddtrace/settings/_config.py | 1 - docs/index.rst | 2 - docs/integrations.rst | 7 - .../notes/cassandra-d3c8aaf478bddc56.yaml | 5 + riotfile.py | 6 - supported_versions_output.json | 12 +- supported_versions_table.csv | 5 +- tests/contrib/cassandra/__init__.py | 0 tests/contrib/cassandra/test.py | 546 ------------------ .../contrib/cassandra/test_cassandra_patch.py | 31 - tests/contrib/suitespec.yml | 16 - 19 files changed, 11 insertions(+), 1043 deletions(-) delete mode 100644 .riot/requirements/164d658.txt delete mode 100644 .riot/requirements/f229429.txt delete mode 100644 ddtrace/contrib/internal/cassandra/__init__.py delete mode 100644 ddtrace/contrib/internal/cassandra/patch.py delete mode 100644 ddtrace/contrib/internal/cassandra/session.py delete mode 100644 ddtrace/ext/cassandra.py create mode 100644 releasenotes/notes/cassandra-d3c8aaf478bddc56.yaml delete mode 100644 tests/contrib/cassandra/__init__.py delete mode 100644 tests/contrib/cassandra/test.py delete mode 100644 tests/contrib/cassandra/test_cassandra_patch.py diff --git a/.riot/requirements/164d658.txt b/.riot/requirements/164d658.txt deleted file mode 100644 index cd0bb3c4f4c..00000000000 --- a/.riot/requirements/164d658.txt +++ /dev/null @@ -1,27 +0,0 @@ -# -# This file is autogenerated by pip-compile with Python 3.8 -# by the following command: -# -# pip-compile --no-annotate .riot/requirements/164d658.in -# -attrs==23.1.0 -cassandra-driver==3.28.0 -click==8.1.7 -coverage[toml]==7.3.4 -exceptiongroup==1.2.0 -geomet==0.2.1.post1 -hypothesis==6.45.0 -importlib-metadata==7.0.0 -iniconfig==2.0.0 -mock==5.1.0 -opentracing==2.4.0 -packaging==23.2 -pluggy==1.3.0 -pytest==7.4.3 -pytest-cov==4.1.0 -pytest-mock==3.12.0 -pytest-randomly==3.15.0 -six==1.16.0 -sortedcontainers==2.4.0 -tomli==2.0.1 -zipp==3.17.0 diff --git a/.riot/requirements/f229429.txt b/.riot/requirements/f229429.txt deleted file mode 100644 index 4f0448ccdbb..00000000000 --- a/.riot/requirements/f229429.txt +++ /dev/null @@ -1,27 +0,0 @@ -# -# This file is autogenerated by pip-compile with Python 3.8 -# by the following command: -# -# pip-compile --no-annotate .riot/requirements/f229429.in -# -attrs==23.1.0 -cassandra-driver==3.24.0 -click==8.1.7 -coverage[toml]==7.3.4 -exceptiongroup==1.2.0 -geomet==0.2.1.post1 -hypothesis==6.45.0 -importlib-metadata==7.0.0 -iniconfig==2.0.0 -mock==5.1.0 -opentracing==2.4.0 -packaging==23.2 -pluggy==1.3.0 -pytest==7.4.3 -pytest-cov==4.1.0 -pytest-mock==3.12.0 -pytest-randomly==3.15.0 -six==1.16.0 -sortedcontainers==2.4.0 -tomli==2.0.1 -zipp==3.17.0 diff --git a/ddtrace/_monkey.py b/ddtrace/_monkey.py index f943f465d1b..92e3c468807 100644 --- a/ddtrace/_monkey.py +++ b/ddtrace/_monkey.py @@ -39,7 +39,6 @@ "boto": True, "botocore": True, "bottle": True, - "cassandra": True, "celery": True, "consul": True, "ddtrace_api": True, @@ -156,7 +155,6 @@ "psycopg2", ), "snowflake": ("snowflake.connector",), - "cassandra": ("cassandra.cluster",), "dogpile_cache": ("dogpile.cache",), "mysqldb": ("MySQLdb",), "futures": ("concurrent.futures.thread",), @@ -335,7 +333,7 @@ def patch_all(**patch_modules: bool) -> None: :param dict patch_modules: Override whether particular modules are patched or not. - >>> _patch_all(redis=False, cassandra=False) + >>> _patch_all(redis=False) """ deprecate( "patch_all is deprecated and will be removed in a future version of the tracer.", diff --git a/ddtrace/contrib/integration_registry/registry.yaml b/ddtrace/contrib/integration_registry/registry.yaml index 4a467241940..1a877c8e784 100644 --- a/ddtrace/contrib/integration_registry/registry.yaml +++ b/ddtrace/contrib/integration_registry/registry.yaml @@ -195,16 +195,6 @@ integrations: min: 0.12.25 max: 0.13.4 -- integration_name: cassandra - is_external_package: true - is_tested: true - dependency_names: - - cassandra-driver - tested_versions_by_dependency: - cassandra-driver: - min: 3.24.0 - max: 3.28.0 - - integration_name: celery is_external_package: true is_tested: true diff --git a/ddtrace/contrib/internal/cassandra/__init__.py b/ddtrace/contrib/internal/cassandra/__init__.py deleted file mode 100644 index d0de07f8f16..00000000000 --- a/ddtrace/contrib/internal/cassandra/__init__.py +++ /dev/null @@ -1,24 +0,0 @@ -"""Instrument Cassandra to report Cassandra queries. - -``import ddtrace.auto`` will automatically patch your Cluster instance to make it work. -:: - - from ddtrace import patch - from ddtrace.trace import Pin - from cassandra.cluster import Cluster - - # If not patched yet, you can patch cassandra specifically - patch(cassandra=True) - - # This will report spans with the default instrumentation - cluster = Cluster(contact_points=["127.0.0.1"], port=9042) - session = cluster.connect("my_keyspace") - # Example of instrumented query - session.execute("select id from my_table limit 10;") - - # Use a pin to specify metadata related to this cluster - cluster = Cluster(contact_points=['10.1.1.3', '10.1.1.4', '10.1.1.5'], port=9042) - Pin.override(cluster, service='cassandra-backend') - session = cluster.connect("my_keyspace") - session.execute("select id from my_table limit 10;") -""" diff --git a/ddtrace/contrib/internal/cassandra/patch.py b/ddtrace/contrib/internal/cassandra/patch.py deleted file mode 100644 index bc82b8dbe0e..00000000000 --- a/ddtrace/contrib/internal/cassandra/patch.py +++ /dev/null @@ -1,9 +0,0 @@ -from typing import Dict - -from .session import get_version # noqa: F401 -from .session import patch # noqa: F401 -from .session import unpatch # noqa: F401 - - -def _supported_versions() -> Dict[str, str]: - return {"cassandra": ">=3.24.0"} diff --git a/ddtrace/contrib/internal/cassandra/session.py b/ddtrace/contrib/internal/cassandra/session.py deleted file mode 100644 index ed1b56ea251..00000000000 --- a/ddtrace/contrib/internal/cassandra/session.py +++ /dev/null @@ -1,316 +0,0 @@ -""" -Trace queries along a session to a cassandra cluster -""" -import sys -from typing import Any -from typing import Dict -from typing import List -from typing import Optional - -from cassandra import __version__ - - -try: - import cassandra.cluster as cassandra_cluster -except AttributeError: - from cassandra import cluster as cassandra_cluster -from cassandra.query import BatchStatement -from cassandra.query import BoundStatement -from cassandra.query import PreparedStatement -from cassandra.query import SimpleStatement -import wrapt - -from ddtrace import config -from ddtrace._trace.pin import Pin -from ddtrace.constants import _SPAN_MEASURED_KEY -from ddtrace.constants import ERROR_MSG -from ddtrace.constants import ERROR_TYPE -from ddtrace.constants import SPAN_KIND -from ddtrace.ext import SpanKind -from ddtrace.ext import SpanTypes -from ddtrace.ext import cassandra as cassx -from ddtrace.ext import db -from ddtrace.ext import net -from ddtrace.internal.compat import maybe_stringify -from ddtrace.internal.constants import COMPONENT -from ddtrace.internal.logger import get_logger -from ddtrace.internal.schema import schematize_database_operation -from ddtrace.internal.schema import schematize_service_name -from ddtrace.internal.utils import get_argument_value -from ddtrace.internal.utils.formats import deep_getattr -from ddtrace.trace import Span - - -log = get_logger(__name__) - -RESOURCE_MAX_LENGTH = 5000 -SERVICE = schematize_service_name("cassandra") -CURRENT_SPAN = "_ddtrace_current_span" -PAGE_NUMBER = "_ddtrace_page_number" - - -# Original connect connect function -_connect = cassandra_cluster.Cluster.connect - - -def get_version(): - # type: () -> str - return __version__ - - -def patch(): - """patch will add tracing to the cassandra library.""" - cassandra_cluster.Cluster.connect = wrapt.FunctionWrapper(_connect, traced_connect) - Pin(service=SERVICE).onto(cassandra_cluster.Cluster) - cassandra_cluster._datadog_patch = True - - -def unpatch(): - cassandra_cluster.Cluster.connect = _connect - cassandra_cluster._datadog_patch = False - - -def traced_connect(func, instance, args, kwargs): - session = func(*args, **kwargs) - if not isinstance(session.execute, wrapt.FunctionWrapper): - # FIXME[matt] this should probably be private. - session.execute_async = wrapt.FunctionWrapper(session.execute_async, traced_execute_async) - return session - - -def _close_span_on_success(result, future): - span = getattr(future, CURRENT_SPAN, None) - if not span: - log.debug("traced_set_final_result was not able to get the current span from the ResponseFuture") - return - try: - span.set_tags(_extract_result_metas(cassandra_cluster.ResultSet(future, result))) - except Exception: - log.debug("an exception occurred while setting tags", exc_info=True) - finally: - span.finish() - delattr(future, CURRENT_SPAN) - - -def traced_set_final_result(func, instance, args, kwargs): - result = get_argument_value(args, kwargs, 0, "response") - _close_span_on_success(result, instance) - return func(*args, **kwargs) - - -def _close_span_on_error(exc, future): - span = getattr(future, CURRENT_SPAN, None) - if not span: - log.debug("traced_set_final_exception was not able to get the current span from the ResponseFuture") - return - try: - # handling the exception manually because we - # don't have an ongoing exception here - span.error = 1 - span.set_tag_str(ERROR_MSG, exc.args[0]) - span.set_tag_str(ERROR_TYPE, exc.__class__.__name__) - except Exception: - log.debug("traced_set_final_exception was not able to set the error, failed with error", exc_info=True) - finally: - span.finish() - delattr(future, CURRENT_SPAN) - - -def traced_set_final_exception(func, instance, args, kwargs): - exc = get_argument_value(args, kwargs, 0, "response") - _close_span_on_error(exc, instance) - return func(*args, **kwargs) - - -def traced_start_fetching_next_page(func, instance, args, kwargs): - has_more_pages = getattr(instance, "has_more_pages", True) - if not has_more_pages: - return func(*args, **kwargs) - session = getattr(instance, "session", None) - cluster = getattr(session, "cluster", None) - pin = Pin.get_from(cluster) - if not pin or not pin.enabled(): - return func(*args, **kwargs) - - # In case the current span is not finished we make sure to finish it - old_span = getattr(instance, CURRENT_SPAN, None) - if old_span: - log.debug("previous span was not finished before fetching next page") - old_span.finish() - - query = getattr(instance, "query", None) - - sanitized_query = _sanitize_query(query) if isinstance(query, BatchStatement) else None - statements_and_parameters = query._statements_and_parameters if isinstance(query, BatchStatement) else None - additional_tags = dict(**_extract_session_metas(session), **_extract_cluster_metas(cluster)) - span = _start_span_and_set_tags( - pin, _get_resource(query), additional_tags, sanitized_query, statements_and_parameters - ) - - page_number = getattr(instance, PAGE_NUMBER, 1) + 1 - setattr(instance, PAGE_NUMBER, page_number) - setattr(instance, CURRENT_SPAN, span) - try: - return func(*args, **kwargs) - except Exception: - with span: - span.set_exc_info(*sys.exc_info()) - raise - - -def traced_execute_async(func, instance, args, kwargs): - cluster = getattr(instance, "cluster", None) - pin = Pin.get_from(cluster) - if not pin or not pin.enabled(): - return func(*args, **kwargs) - - query = get_argument_value(args, kwargs, 0, "query") - - sanitized_query = _sanitize_query(query) if isinstance(query, BatchStatement) else None - statements_and_parameters = query._statements_and_parameters if isinstance(query, BatchStatement) else None - additional_tags = dict(**_extract_session_metas(instance), **_extract_cluster_metas(cluster)) - span = _start_span_and_set_tags( - pin, _get_resource(query), additional_tags, sanitized_query, statements_and_parameters - ) - - try: - result = func(*args, **kwargs) - setattr(result, CURRENT_SPAN, span) - setattr(result, PAGE_NUMBER, 1) - result._set_final_result = wrapt.FunctionWrapper(result._set_final_result, traced_set_final_result) - result._set_final_exception = wrapt.FunctionWrapper(result._set_final_exception, traced_set_final_exception) - result.start_fetching_next_page = wrapt.FunctionWrapper( - result.start_fetching_next_page, traced_start_fetching_next_page - ) - - # Since we cannot be sure that the previous methods were overwritten - # before the call ended, we add callbacks that will be run - # synchronously if the call already returned and we remove them right - # after. - result.add_callbacks( - _close_span_on_success, _close_span_on_error, callback_args=(result,), errback_args=(result,) - ) - result.clear_callbacks() - return result - except Exception: - with span: - span.set_exc_info(*sys.exc_info()) - raise - - -def _start_span_and_set_tags( - pin, - resource: str, - additional_tags: Dict, - query: Optional[str] = None, - statements_and_parameters: Optional[List] = None, -) -> Span: - span = pin.tracer.trace( - schematize_database_operation("cassandra.query", database_provider="cassandra"), - service=pin.service, - span_type=SpanTypes.CASSANDRA, - ) - span.set_tag_str(COMPONENT, config.cassandra.integration_name) - span.set_tag_str(db.SYSTEM, "cassandra") - span.set_tag_str(SPAN_KIND, SpanKind.CLIENT) - # PERF: avoid setting via Span.set_tag - span.set_metric(_SPAN_MEASURED_KEY, 1) - span.set_tags(additional_tags) - if query is not None: - span.set_tag_str("cassandra.query", query) - if statements_and_parameters is not None: - span.set_metric("cassandra.batch_size", len(statements_and_parameters)) - span.resource = resource[:RESOURCE_MAX_LENGTH] - return span - - -def _extract_session_metas(session): - metas = {} - - if getattr(session, "keyspace", None): - # FIXME the keyspace can be overridden explicitly in the query itself - # e.g. 'select * from trace.hash_to_resource' - metas[cassx.KEYSPACE] = session.keyspace.lower() - - return metas - - -def _extract_cluster_metas(cluster): - metas = {} - if deep_getattr(cluster, "metadata.cluster_name"): - metas[cassx.CLUSTER] = cluster.metadata.cluster_name - if getattr(cluster, "port", None): - metas[net.TARGET_PORT] = cluster.port - - return metas - - -def _extract_result_metas(result): - metas = {} - if result is None: - return metas - - future = getattr(result, "response_future", None) - - if future: - # get the host - host = maybe_stringify(getattr(future, "coordinator_host", None)) - if host: - host, _, port = host.partition(":") - metas[net.TARGET_HOST] = host - metas[net.SERVER_ADDRESS] = host - if port: - metas[net.TARGET_PORT] = int(port) - elif hasattr(future, "_current_host"): - address = deep_getattr(future, "_current_host.address") - if address: - metas[net.TARGET_HOST] = address - metas[net.SERVER_ADDRESS] = address - - query = getattr(future, "query", None) - if getattr(query, "consistency_level", None): - metas[cassx.CONSISTENCY_LEVEL] = query.consistency_level - if getattr(query, "keyspace", None): - metas[cassx.KEYSPACE] = query.keyspace.lower() - - page_number = getattr(future, PAGE_NUMBER, 1) - has_more_pages = future.has_more_pages - is_paginated = has_more_pages or page_number > 1 - metas[cassx.PAGINATED] = is_paginated - if is_paginated: - metas[cassx.PAGE_NUMBER] = page_number - - if hasattr(result, "current_rows"): - result_rows = result.current_rows or [] - metas[db.ROWCOUNT] = len(result_rows) - - return metas - - -def _get_resource(query: Any) -> str: - if isinstance(query, SimpleStatement) or isinstance(query, PreparedStatement): - return getattr(query, "query_string", query) - elif isinstance(query, BatchStatement): - return "BatchStatement" - elif isinstance(query, BoundStatement): - ps = getattr(query, "prepared_statement", None) - if ps: - return getattr(ps, "query_string", None) - elif isinstance(query, str): - return query - else: - return "unknown-query-type" - - -def _sanitize_query(query: BatchStatement) -> str: - """ - Each element in `_statements_and_parameters` is: - (is_prepared, statement, parameters) - ref:https://github.com/datastax/python-driver/blob/13d6d72be74f40fcef5ec0f2b3e98538b3b87459/cassandra/query.py#L844 - - For prepared statements, the `statement` value is just the query_id - which is not a statement and when trying to join with other strings - raises an error in python3 around joining bytes to unicode, so this - just filters out prepared statements from this tag value - """ - return "; ".join(q[1] for q in query._statements_and_parameters[:2] if not q[0]) diff --git a/ddtrace/ext/cassandra.py b/ddtrace/ext/cassandra.py deleted file mode 100644 index d510897d12d..00000000000 --- a/ddtrace/ext/cassandra.py +++ /dev/null @@ -1,6 +0,0 @@ -# tags -CLUSTER = "cassandra.cluster" -KEYSPACE = "cassandra.keyspace" -CONSISTENCY_LEVEL = "cassandra.consistency_level" -PAGINATED = "cassandra.paginated" -PAGE_NUMBER = "cassandra.page_number" diff --git a/ddtrace/settings/_config.py b/ddtrace/settings/_config.py index 96c66bb5fce..9a14793c080 100644 --- a/ddtrace/settings/_config.py +++ b/ddtrace/settings/_config.py @@ -178,7 +178,6 @@ "crewai", "pydantic_ai", "logging", - "cassandra", "boto", "mariadb", "aiohttp", diff --git a/docs/index.rst b/docs/index.rst index caf65d873e2..8275e9998b2 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -72,8 +72,6 @@ contacting support. +--------------------------------------------------+------------+----------+------+ | :ref:`bottle` | >= 0.12 | No | | +--------------------------------------------------+------------+----------+------+ -| :ref:`cassandra` | >= 3.24 | Yes | | -+--------------------------------------------------+------------+----------+------+ | :ref:`celery` | >= 4.4 | Yes | | +--------------------------------------------------+------------+----------+------+ | :ref:`cherrypy` | >= 17.0 | No | | diff --git a/docs/integrations.rst b/docs/integrations.rst index c33138a508e..ba36c26912d 100644 --- a/docs/integrations.rst +++ b/docs/integrations.rst @@ -110,13 +110,6 @@ Bottle .. automodule:: ddtrace.contrib.bottle -.. _cassandra: - -Cassandra -^^^^^^^^^ -.. automodule:: ddtrace.contrib.internal.cassandra - - .. _celery: Celery diff --git a/releasenotes/notes/cassandra-d3c8aaf478bddc56.yaml b/releasenotes/notes/cassandra-d3c8aaf478bddc56.yaml new file mode 100644 index 00000000000..07df72ad56a --- /dev/null +++ b/releasenotes/notes/cassandra-d3c8aaf478bddc56.yaml @@ -0,0 +1,5 @@ +--- +other: + - | + cassandra: The Cassandra integration is removed because it is only compatible with Python 3.8, + which is a year past its end-of-life. diff --git a/riotfile.py b/riotfile.py index f12379c4b8c..224a59ca7b4 100644 --- a/riotfile.py +++ b/riotfile.py @@ -2170,12 +2170,6 @@ def select_pys(min_version: str = MIN_PYTHON_VERSION, max_version: str = MAX_PYT ), ], ), - Venv( - name="cassandra", - pys="3.8", # see https://github.com/r4fek/django-cassandra-engine/issues/104 - pkgs={"cassandra-driver": ["~=3.24.0", latest], "pytest-randomly": latest}, - command="pytest {cmdargs} tests/contrib/cassandra", - ), Venv( name="algoliasearch", command="pytest {cmdargs} tests/contrib/algoliasearch", diff --git a/supported_versions_output.json b/supported_versions_output.json index c1ea2d658ad..ba6dc49f9cb 100644 --- a/supported_versions_output.json +++ b/supported_versions_output.json @@ -106,7 +106,7 @@ "minimum_tracer_supported": "5.12.2", "max_tracer_supported": "5.15.0", "pinned": "true", - "auto-instrumented": false + "auto-instrumented": true }, { "dependency": "azure-functions", @@ -147,13 +147,6 @@ "max_tracer_supported": "0.13.4", "auto-instrumented": true }, - { - "dependency": "cassandra-driver", - "integration": "cassandra", - "minimum_tracer_supported": "3.24.0", - "max_tracer_supported": "3.28.0", - "auto-instrumented": true - }, { "dependency": "celery", "integration": "celery", @@ -489,7 +482,8 @@ "dependency": "openai", "integration": "openai", "minimum_tracer_supported": "1.0.0", - "max_tracer_supported": "1.91.0", + "max_tracer_supported": "1.109.1", + "pinned": "true", "auto-instrumented": true }, { diff --git a/supported_versions_table.csv b/supported_versions_table.csv index 94af82316ad..25309eedf48 100644 --- a/supported_versions_table.csv +++ b/supported_versions_table.csv @@ -13,13 +13,12 @@ asyncpg,asyncpg,0.22.0,0.30.0,True avro,avro,1.12.0,1.12.0,True datadog-lambda,aws_lambda,6.105.0,6.105.0,True datadog_lambda,aws_lambda,6.105.0,6.105.0,True -azure-eventhub,azure_eventhubs *,5.12.2,5.15.0,False +azure-eventhub,azure_eventhubs *,5.12.2,5.15.0,True azure-functions,azure_functions *,1.10.1,1.23.0,True azure-servicebus,azure_servicebus *,7.14.2,7.14.2,True boto3,botocore *,1.34.49,1.38.26,True botocore,botocore *,1.34.49,1.38.26,True bottle,bottle,0.12.25,0.13.4,True -cassandra-driver,cassandra,3.24.0,3.28.0,True celery,celery,5.5.3,5.5.3,True cherrypy,cherrypy,17.0.0,18.10.0,False python-consul,consul,1.1.0,1.1.0,True @@ -67,7 +66,7 @@ molten,molten,1.0.2,1.0.2,True mongoengine,mongoengine,0.23.1,0.29.1,True mysql-connector-python,mysql,8.0.5,9.4.0,True mysqlclient,mysqldb,2.2.1,2.2.6,True -openai,openai,1.0.0,1.91.0,True +openai,openai *,1.0.0,1.109.1,True openai-agents,openai_agents,0.0.8,0.0.16,True protobuf,protobuf,5.29.3,6.32.0,False psycopg,psycopg,3.0.18,3.2.10,True diff --git a/tests/contrib/cassandra/__init__.py b/tests/contrib/cassandra/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/tests/contrib/cassandra/test.py b/tests/contrib/cassandra/test.py deleted file mode 100644 index 708d599040a..00000000000 --- a/tests/contrib/cassandra/test.py +++ /dev/null @@ -1,546 +0,0 @@ -import contextlib -import logging -from threading import Event -import unittest - -from cassandra.cluster import Cluster -from cassandra.cluster import ResultSet -from cassandra.query import BatchStatement -from cassandra.query import SimpleStatement -import mock - -from ddtrace import config -from ddtrace._trace.pin import Pin -from ddtrace.constants import ERROR_MSG -from ddtrace.constants import ERROR_TYPE -from ddtrace.contrib.internal.cassandra.patch import patch -from ddtrace.contrib.internal.cassandra.patch import unpatch -from ddtrace.contrib.internal.cassandra.session import SERVICE -from ddtrace.ext import cassandra as cassx -from ddtrace.ext import net -from ddtrace.internal.schema import DEFAULT_SPAN_SERVICE_NAME -from tests.contrib.config import CASSANDRA_CONFIG -from tests.opentracer.utils import init_tracer -from tests.utils import DummyTracer -from tests.utils import TracerTestCase -from tests.utils import assert_is_measured - - -# Oftentimes our tests fails because Cassandra connection timeouts during keyspace drop. Slowness in keyspace drop -# is known and is due to 'auto_snapshot' configuration. In our test env we should disable it, but the official cassandra -# image that we are using only allows us to configure a few configs: -# https://github.com/docker-library/cassandra/blob/4474c6c5cc2a81ee57c5615aae00555fca7e26a6/3.11/docker-entrypoint.sh#L51 -# So for now we just increase the timeout, if this is not enough we may want to extend the official image with our own -# custom image. -CONNECTION_TIMEOUT_SECS = 20 # override the default value of 5 - -logging.getLogger("cassandra").setLevel(logging.INFO) - - -def _setup(testObject): - self = testObject or mock.Mock() - - # skip all the modules if the Cluster is not available - if not Cluster: - raise unittest.SkipTest("cassandra.cluster.Cluster is not available.") - - # create the KEYSPACE for this test module - self.cluster = Cluster(port=CASSANDRA_CONFIG["port"], connect_timeout=CONNECTION_TIMEOUT_SECS) - self.session = self.cluster.connect() - self.session.execute("DROP KEYSPACE IF EXISTS test", timeout=10) - self.session.execute( - "CREATE KEYSPACE if not exists test WITH REPLICATION = { 'class' : 'SimpleStrategy', 'replication_factor': 1};" # noqa:E501 - ) - self.session.execute("CREATE TABLE if not exists test.person (name text PRIMARY KEY, age int, description text)") - self.session.execute( - "CREATE TABLE if not exists test.person_write (name text PRIMARY KEY, age int, description text)" - ) - self.session.execute( - "INSERT INTO test.person (name, age, description) VALUES ('Cassandra', 100, 'A cruel mistress')" - ) - self.session.execute( - "INSERT INTO test.person (name, age, description) VALUES ('Athena', 100, 'Whose shield is thunder')" - ) - self.session.execute( - "INSERT INTO test.person (name, age, description) VALUES ('Calypso', 100, 'Softly-braided nymph')" - ) - - -def _teardown(testObject): - self = testObject or mock.Mock() - # destroy the KEYSPACE - self.session.execute("DROP TABLE IF EXISTS test.person") - self.session.execute("DROP TABLE IF EXISTS test.person_write") - self.session.execute("DROP KEYSPACE IF EXISTS test", timeout=10) - - -def setUpModule(): - _setup(None) - - -def tearDownModule(): - _teardown(None) - - -class CassandraBase(object): - """ - Needs a running Cassandra - """ - - TEST_QUERY = "SELECT * from test.person WHERE name = 'Cassandra'" - TEST_QUERY_PAGINATED = "SELECT * from test.person" - TEST_KEYSPACE = "test" - TEST_PORT = CASSANDRA_CONFIG["port"] - TEST_SERVICE = "test-cassandra" - - def setUp(self): - _setup(self) - - def tearDown(self): - _teardown(self) - - @contextlib.contextmanager - def override_config(self, integration, values): - """ - Temporarily override an integration configuration value - >>> with self.override_config('flask', dict(service_name='test-service')): - ... # Your test - """ - options = getattr(config, integration) - - original = dict((key, options.get(key)) for key in values.keys()) - - options.update(values) - try: - yield - finally: - options.update(original) - - def _assert_result_correct(self, result): - assert len(result.current_rows) == 1 - for r in result: - assert r.name == "Cassandra" - assert r.age == 100 - assert r.description == "A cruel mistress" - - def _test_query_base(self, execute_fn): - session, tracer = self._traced_session() - - result = execute_fn(session, self.TEST_QUERY) - self._assert_result_correct(result) - - spans = tracer.pop() - assert spans, spans - - # another for the actual query - assert len(spans) == 1 - - query = spans[0] - - assert_is_measured(query) - assert query.service == self.TEST_SERVICE - assert query.resource == self.TEST_QUERY - assert query.span_type == "cassandra" - - assert query.get_tag(cassx.KEYSPACE) == self.TEST_KEYSPACE - assert query.get_metric("db.row_count") == 1 - assert query.get_metric("network.destination.port") == self.TEST_PORT - assert query.get_tag(cassx.PAGE_NUMBER) is None - assert query.get_tag(cassx.PAGINATED) == "False" - assert query.get_tag(net.TARGET_HOST) == "127.0.0.1" - assert query.get_tag(net.SERVER_ADDRESS) == "127.0.0.1" - assert query.get_tag("component") == "cassandra" - assert query.get_tag("span.kind") == "client" - assert query.get_tag("db.system") == "cassandra" - - def test_query(self): - def execute_fn(session, query): - return session.execute(query) - - self._test_query_base(execute_fn) - - def test_query_ot(self): - """Ensure that cassandra works with the opentracer.""" - - def execute_fn(session, query): - return session.execute(query) - - session, tracer = self._traced_session() - ot_tracer = init_tracer("cass_svc", tracer) - - with ot_tracer.start_active_span("cass_op"): - result = execute_fn(session, self.TEST_QUERY) - self._assert_result_correct(result) - - spans = tracer.pop() - assert spans, spans - - # another for the actual query - assert len(spans) == 2 - ot_span, dd_span = spans - - # confirm parenting - assert ot_span.parent_id is None - assert dd_span.parent_id == ot_span.span_id - - assert ot_span.name == "cass_op" - assert ot_span.service == "cass_svc" - - assert dd_span.service == self.TEST_SERVICE - assert dd_span.resource == self.TEST_QUERY - assert dd_span.span_type == "cassandra" - - assert dd_span.get_tag(cassx.KEYSPACE) == self.TEST_KEYSPACE - assert dd_span.get_metric("db.row_count") == 1 - assert dd_span.get_metric("network.destination.port") == self.TEST_PORT - assert dd_span.get_tag(cassx.PAGE_NUMBER) is None - assert dd_span.get_tag(cassx.PAGINATED) == "False" - assert dd_span.get_tag(net.TARGET_HOST) == "127.0.0.1" - assert dd_span.get_tag(net.SERVER_ADDRESS) == "127.0.0.1" - assert dd_span.get_tag("component") == "cassandra" - assert dd_span.get_tag("span.kind") == "client" - assert dd_span.get_tag("db.system") == "cassandra" - - def test_query_async(self): - def execute_fn(session, query): - event = Event() - result = [] - future = session.execute_async(query) - - def callback(results): - result.append(ResultSet(future, results)) - event.set() - - future.add_callback(callback) - event.wait() - return result[0] - - self._test_query_base(execute_fn) - - def test_query_async_clearing_callbacks(self): - def execute_fn(session, query): - future = session.execute_async(query) - future.clear_callbacks() - return future.result() - - self._test_query_base(execute_fn) - - def test_span_is_removed_from_future(self): - session, tracer = self._traced_session() - future = session.execute_async(self.TEST_QUERY) - future.result() - span = getattr(future, "_ddtrace_current_span", None) - assert span is None - - def test_paginated_query(self): - session, tracer = self._traced_session() - - statement = SimpleStatement(self.TEST_QUERY_PAGINATED, fetch_size=1) - result = session.execute(statement) - # iterate over all pages - results = list(result) - assert len(results) == 3 - - spans = tracer.pop() - assert spans, spans - - # There are 4 spans for 3 results since the driver makes a request with - # no result to check that it has reached the last page - assert len(spans) == 4 - - for i in range(4): - query = spans[i] - assert query.service == self.TEST_SERVICE - assert query.resource == self.TEST_QUERY_PAGINATED - assert query.span_type == "cassandra" - - assert query.get_tag(cassx.KEYSPACE) == self.TEST_KEYSPACE - assert query.get_metric("network.destination.port") == self.TEST_PORT - if i == 3: - assert query.get_metric("db.row_count") == 0 - else: - assert query.get_metric("db.row_count") == 1 - assert query.get_tag(net.TARGET_HOST) == "127.0.0.1" - assert query.get_tag(net.SERVER_ADDRESS) == "127.0.0.1" - assert query.get_tag(cassx.PAGINATED) == "True" - assert query.get_metric(cassx.PAGE_NUMBER) == i + 1 - assert query.get_tag("db.system") == "cassandra" - - def test_trace_with_service(self): - session, tracer = self._traced_session() - - session.execute(self.TEST_QUERY) - spans = tracer.pop() - assert spans - assert len(spans) == 1 - query = spans[0] - assert query.service == self.TEST_SERVICE - - def test_trace_error(self): - session, tracer = self._traced_session() - - try: - session.execute("select * from test.i_dont_exist limit 1") - except Exception: - pass - else: - assert 0 - - spans = tracer.pop() - assert spans - query = spans[0] - assert query.error == 1 - for k in (ERROR_MSG, ERROR_TYPE): - assert query.get_tag(k) - - def test_bound_statement(self): - session, tracer = self._traced_session() - - query = "INSERT INTO test.person_write (name, age, description) VALUES (?, ?, ?)" - prepared = session.prepare(query) - session.execute(prepared, ("matt", 34, "can")) - - prepared = session.prepare(query) - bound_stmt = prepared.bind(("leo", 16, "fr")) - session.execute(bound_stmt) - - spans = tracer.pop() - assert len(spans) == 2 - for s in spans: - assert s.resource == query - - def test_batch_statement(self): - session, tracer = self._traced_session() - - batch = BatchStatement() - batch.add( - SimpleStatement("INSERT INTO test.person_write (name, age, description) VALUES (%s, %s, %s)"), - ("Joe", 1, "a"), - ) - batch.add( - SimpleStatement("INSERT INTO test.person_write (name, age, description) VALUES (%s, %s, %s)"), - ("Jane", 2, "b"), - ) - session.execute(batch) - - spans = tracer.pop() - assert len(spans) == 1 - s = spans[0] - assert s.resource == "BatchStatement" - assert s.get_metric("cassandra.batch_size") == 2 - assert "test.person" in s.get_tag("cassandra.query") - - def test_batched_bound_statement(self): - session, tracer = self._traced_session() - - batch = BatchStatement() - - prepared_statement = session.prepare("INSERT INTO test.person_write (name, age, description) VALUES (?, ?, ?)") - batch.add(prepared_statement.bind(("matt", 34, "can"))) - session.execute(batch) - - spans = tracer.pop() - assert len(spans) == 1 - s = spans[0] - assert s.resource == "BatchStatement" - assert s.get_tag("cassandra.query") == "" - - -class TestCassPatchDefault(unittest.TestCase, CassandraBase): - """Test Cassandra instrumentation with patching and default configuration""" - - TEST_SERVICE = SERVICE - - def tearDown(self): - unpatch() - - def setUp(self): - CassandraBase.setUp(self) - patch() - - def _traced_session(self): - tracer = DummyTracer() - Pin.get_from(self.cluster)._clone(tracer=tracer).onto(self.cluster) - return self.cluster.connect(self.TEST_KEYSPACE), tracer - - -class TestCassPatchAll(TestCassPatchDefault): - """Test Cassandra instrumentation with patching and custom service on all clusters""" - - TEST_SERVICE = "test-cassandra-patch-all" - - def tearDown(self): - unpatch() - - def setUp(self): - CassandraBase.setUp(self) - patch() - - def _traced_session(self): - tracer = DummyTracer() - # pin the global Cluster to test if they will conflict - pin = Pin(service=self.TEST_SERVICE) - pin._tracer = tracer - pin.onto(Cluster) - self.cluster = Cluster(port=CASSANDRA_CONFIG["port"]) - - return self.cluster.connect(self.TEST_KEYSPACE), tracer - - -class TestCassPatchOne(TestCassPatchDefault): - """Test Cassandra instrumentation with patching and custom service on one cluster""" - - TEST_SERVICE = "test-cassandra-patch-one" - - def tearDown(self): - unpatch() - - def setUp(self): - CassandraBase.setUp(self) - patch() - - def _traced_session(self): - tracer = DummyTracer() - # pin the global Cluster to test if they will conflict - Pin(service="not-%s" % self.TEST_SERVICE).onto(Cluster) - self.cluster = Cluster(port=CASSANDRA_CONFIG["port"]) - - pin = Pin(service=self.TEST_SERVICE) - pin._tracer = tracer - pin.onto(self.cluster) - return self.cluster.connect(self.TEST_KEYSPACE), tracer - - def test_patch_unpatch(self): - # Test patch idempotence - patch() - patch() - - tracer = DummyTracer() - Pin.get_from(Cluster)._clone(tracer=tracer).onto(Cluster) - - session = Cluster(port=CASSANDRA_CONFIG["port"]).connect(self.TEST_KEYSPACE) - session.execute(self.TEST_QUERY) - - spans = tracer.pop() - assert spans, spans - assert len(spans) == 1 - - # Test unpatch - unpatch() - - session = Cluster(port=CASSANDRA_CONFIG["port"]).connect(self.TEST_KEYSPACE) - session.execute(self.TEST_QUERY) - - spans = tracer.pop() - assert not spans, spans - - # Test patch again - patch() - Pin.get_from(Cluster)._clone(tracer=tracer).onto(Cluster) - - session = Cluster(port=CASSANDRA_CONFIG["port"]).connect(self.TEST_KEYSPACE) - session.execute(self.TEST_QUERY) - - spans = tracer.pop() - assert spans, spans - - -class TestCassandraConfig(TracerTestCase): - """ - Test various configurations of the Cassandra integration. - """ - - TEST_QUERY = "SELECT * from test.person WHERE name = 'Cassandra'" - TEST_KEYSPACE = "test" - - def setUp(self): - super(TestCassandraConfig, self).setUp() - patch() - self.tracer = DummyTracer() - self.cluster = Cluster(port=CASSANDRA_CONFIG["port"]) - Pin.get_from(self.cluster)._clone(tracer=self.tracer).onto(self.cluster) - self.session = self.cluster.connect(self.TEST_KEYSPACE) - - def tearDown(self): - unpatch() - super(TestCassandraConfig, self).tearDown() - - @TracerTestCase.run_in_subprocess(env_overrides=dict(DD_SERVICE="mysvc", DD_TRACE_SPAN_ATTRIBUTE_SCHEMA="v0")) - def test_user_specified_service_v0(self): - """ - v0: When a user specifies a service for the app - The cassandra integration should not use it. - """ - # Ensure that the service name was configured - from ddtrace import config - - assert config.service == "mysvc" - - self.session.execute(self.TEST_QUERY) - spans = self.pop_spans() - assert spans - assert len(spans) == 1 - query = spans[0] - assert query.service != "mysvc" - - @TracerTestCase.run_in_subprocess(env_overrides=dict(DD_SERVICE="mysvc", DD_TRACE_SPAN_ATTRIBUTE_SCHEMA="v1")) - def test_user_specified_service_v1(self): - """ - v1: When a user specifies a service for the app - The cassandra integration should use it. - """ - # Ensure that the service name was configured - from ddtrace import config - - assert config.service == "mysvc" - - self.session.execute(self.TEST_QUERY) - spans = self.pop_spans() - assert spans - assert len(spans) == 1 - query = spans[0] - assert query.service == "mysvc" - - @TracerTestCase.run_in_subprocess(env_overrides=dict(DD_TRACE_SPAN_ATTRIBUTE_SCHEMA="v1")) - def test_unspecified_service_v1(self): - """ - v1: When a user does not specify a service for the app - dd-trace-py should default to internal.schema.DEFAULT_SPAN_SERVICE_NAME - """ - # Ensure that the service name was configured - from ddtrace import config - - assert config.service == DEFAULT_SPAN_SERVICE_NAME - - self.session.execute(self.TEST_QUERY) - spans = self.pop_spans() - assert spans - assert len(spans) == 1 - query = spans[0] - assert query.service == DEFAULT_SPAN_SERVICE_NAME - - @TracerTestCase.run_in_subprocess(env_overrides=dict(DD_TRACE_SPAN_ATTRIBUTE_SCHEMA="v0")) - def test_span_name_v0_schema(self): - """ - When a user specifies a service for the app - The cassandra integration should not use it. - """ - self.session.execute(self.TEST_QUERY) - spans = self.pop_spans() - assert spans - assert len(spans) == 1 - query = spans[0] - assert query.name == "cassandra.query" - - @TracerTestCase.run_in_subprocess(env_overrides=dict(DD_TRACE_SPAN_ATTRIBUTE_SCHEMA="v1")) - def test_span_name_v1_schema(self): - """ - When a user specifies a service for the app - The cassandra integration should not use it. - """ - self.session.execute(self.TEST_QUERY) - spans = self.pop_spans() - assert spans - assert len(spans) == 1 - query = spans[0] - assert query.name == "cassandra.query" diff --git a/tests/contrib/cassandra/test_cassandra_patch.py b/tests/contrib/cassandra/test_cassandra_patch.py deleted file mode 100644 index 19a09daccf4..00000000000 --- a/tests/contrib/cassandra/test_cassandra_patch.py +++ /dev/null @@ -1,31 +0,0 @@ -# This test script was automatically generated by the contrib-patch-tests.py -# script. If you want to make changes to it, you should make sure that you have -# removed the ``_generated`` suffix from the file name, to prevent the content -# from being overwritten by future re-generations. - -from ddtrace.contrib.internal.cassandra.patch import patch -from ddtrace.contrib.internal.cassandra.session import get_version - - -try: - from ddtrace.contrib.internal.cassandra.patch import unpatch -except ImportError: - unpatch = None -from tests.contrib.patch import PatchTestCase - - -class TestCassandraPatch(PatchTestCase.Base): - __integration_name__ = "cassandra" - __module_name__ = "cassandra.cluster" - __patch_func__ = patch - __unpatch_func__ = unpatch - __get_version__ = get_version - - def assert_module_patched(self, cassandra_cluster): - pass - - def assert_not_module_patched(self, cassandra_cluster): - pass - - def assert_not_module_double_patched(self, cassandra_cluster): - pass diff --git a/tests/contrib/suitespec.yml b/tests/contrib/suitespec.yml index 830cc5511b3..ec373de1f66 100644 --- a/tests/contrib/suitespec.yml +++ b/tests/contrib/suitespec.yml @@ -31,9 +31,6 @@ components: bottle: - ddtrace/contrib/bottle.py - ddtrace/contrib/internal/bottle/* - cassandra: - - ddtrace/contrib/internal/cassandra/* - - ddtrace/ext/cassandra.py celery: - ddtrace/contrib/celery.py - ddtrace/contrib/internal/celery/* @@ -459,19 +456,6 @@ suites: - tests/contrib/bottle/* runner: riot snapshot: true - cassandra: - paths: - - '@bootstrap' - - '@core' - - '@contrib' - - '@tracing' - - '@cassandra' - - tests/contrib/cassandra/* - runner: riot - snapshot: true - parallelism: 2 - services: - - cassandra celery: env: DD_DISABLE_ERROR_RESPONSES: true From b2cee418ce62caff5e056b53db0234389783d6f5 Mon Sep 17 00:00:00 2001 From: Emmett Butler Date: Tue, 21 Oct 2025 10:12:11 -0700 Subject: [PATCH 2/5] update system tests --- .github/workflows/system-tests.yml | 6 +++--- .gitlab-ci.yml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/system-tests.yml b/.github/workflows/system-tests.yml index 88446a9a863..911974c8958 100644 --- a/.github/workflows/system-tests.yml +++ b/.github/workflows/system-tests.yml @@ -45,7 +45,7 @@ jobs: persist-credentials: false repository: 'DataDog/system-tests' # Automatically managed, use scripts/update-system-tests-version to update - ref: 'd5152ebefb021a4273f8d189d798c5e302986f7b' + ref: '201596d32822ba4b9ba184e6a16244ee1a8b74e4' - name: Download wheels to binaries directory uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 @@ -90,7 +90,7 @@ jobs: persist-credentials: false repository: 'DataDog/system-tests' # Automatically managed, use scripts/update-system-tests-version to update - ref: 'd5152ebefb021a4273f8d189d798c5e302986f7b' + ref: '201596d32822ba4b9ba184e6a16244ee1a8b74e4' - name: Build runner uses: ./.github/actions/install_runner @@ -275,7 +275,7 @@ jobs: persist-credentials: false repository: 'DataDog/system-tests' # Automatically managed, use scripts/update-system-tests-version to update - ref: 'd5152ebefb021a4273f8d189d798c5e302986f7b' + ref: '201596d32822ba4b9ba184e6a16244ee1a8b74e4' - name: Download wheels to binaries directory uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 with: diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index cff4dba02bb..9ca2c371ff2 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -14,7 +14,7 @@ variables: DD_VPA_TEMPLATE: "vpa-template-cpu-p70-10percent-2x-oom-min-cap" # CI_DEBUG_SERVICES: "true" # Automatically managed, use scripts/update-system-tests-version to update - SYSTEM_TESTS_REF: "d5152ebefb021a4273f8d189d798c5e302986f7b" + SYSTEM_TESTS_REF: "201596d32822ba4b9ba184e6a16244ee1a8b74e4" default: interruptible: true From 3d713e183c06f8350525f5bc31a6b4566368013d Mon Sep 17 00:00:00 2001 From: Munir Abdinur Date: Wed, 22 Oct 2025 18:02:23 -0400 Subject: [PATCH 3/5] chore(mongoengine): remove integration (#14173) ## Motivation The mongoengine integration does not generate any spans and only supports attaching a Pin object to the underlying pymongo client. Since we're deprecating the Pin mechanism and pymongo already fully supports the needed functionality, maintaining the mongoengine integration is redundant. ## Description This PR removes the mongoengine integration from ddtrace. The pymongo integration, which is enabled by default, will continue to provide tracing for applications using mongoengine, as mongoengine internally uses pymongo. The only notable change is that users can no longer set a Pin on the mongoengine client. Instead, they should configure the Pin directly on the pymongo client if needed. Support for the Pin API will be removed in a future release. ## Checklist - [x] PR author has checked that all the criteria below are met - The PR description includes an overview of the change - The PR description articulates the motivation for the change - The change includes tests OR the PR description describes a testing strategy - The PR description notes risks associated with the change, if any - Newly-added code is easy to change - The change follows the [library release note guidelines](https://ddtrace.readthedocs.io/en/stable/releasenotes.html) - The change includes or references documentation updates if necessary - Backport labels are set (if [applicable](https://ddtrace.readthedocs.io/en/latest/contributing.html#backporting)) ## Reviewer Checklist - [ ] Reviewer has checked that all the criteria below are met - Title is accurate - All changes are related to the pull request's stated goal - Avoids breaking [API](https://ddtrace.readthedocs.io/en/stable/versioning.html#interfaces) changes - Testing strategy adequately addresses listed risks - Newly-added code is easy to change - Release note makes sense to a user of the library - If necessary, author has acknowledged and discussed the performance implications of this PR as reported in the benchmarks PR comment - Backport labels are set in a manner that is consistent with the [release branch maintenance policy](https://ddtrace.readthedocs.io/en/latest/contributing.html#backporting) --- .riot/requirements/106f38d.txt | 23 - .riot/requirements/1087ca6.txt | 26 -- .riot/requirements/10a00e7.txt | 24 - .riot/requirements/10b490c.txt | 23 - .riot/requirements/1424e42.txt | 22 - .riot/requirements/1468cf5.txt | 23 - .riot/requirements/14e85f3.txt | 22 - .riot/requirements/168e13d.txt | 23 - .riot/requirements/170ff7e.txt | 28 -- .riot/requirements/1c4e625.txt | 26 -- .riot/requirements/1ce93b3.txt | 22 - .riot/requirements/328b28c.txt | 24 - .riot/requirements/3dd53da.txt | 22 - .riot/requirements/40a41fd.txt | 23 - .riot/requirements/a0b94b1.txt | 23 - .riot/requirements/ad40916.txt | 22 - .riot/requirements/b089663.txt | 26 -- .riot/requirements/b344fed.txt | 22 - .riot/requirements/de53117.txt | 26 -- .riot/requirements/f9d0e8e.txt | 26 -- ddtrace/_monkey.py | 1 - .../integration_registry/registry.yaml | 10 - .../contrib/internal/mongoengine/__init__.py | 19 - ddtrace/contrib/internal/mongoengine/patch.py | 38 -- ddtrace/contrib/internal/mongoengine/trace.py | 38 -- ddtrace/settings/_config.py | 1 - docs/contributing-integrations.rst | 1 - docs/index.rst | 2 - docs/integrations.rst | 7 - ...emove-pymongo-engine-0584c2055377f718.yaml | 5 + riotfile.py | 20 - supported_versions_output.json | 7 - supported_versions_table.csv | 1 - .../integration_registry_manager.py | 2 +- tests/contrib/mongoengine/__init__.py | 0 tests/contrib/mongoengine/test.py | 415 ------------------ .../mongoengine/test_mongoengine_patch.py | 31 -- tests/contrib/suitespec.yml | 13 - 38 files changed, 6 insertions(+), 1081 deletions(-) delete mode 100644 .riot/requirements/106f38d.txt delete mode 100644 .riot/requirements/1087ca6.txt delete mode 100644 .riot/requirements/10a00e7.txt delete mode 100644 .riot/requirements/10b490c.txt delete mode 100644 .riot/requirements/1424e42.txt delete mode 100644 .riot/requirements/1468cf5.txt delete mode 100644 .riot/requirements/14e85f3.txt delete mode 100644 .riot/requirements/168e13d.txt delete mode 100644 .riot/requirements/170ff7e.txt delete mode 100644 .riot/requirements/1c4e625.txt delete mode 100644 .riot/requirements/1ce93b3.txt delete mode 100644 .riot/requirements/328b28c.txt delete mode 100644 .riot/requirements/3dd53da.txt delete mode 100644 .riot/requirements/40a41fd.txt delete mode 100644 .riot/requirements/a0b94b1.txt delete mode 100644 .riot/requirements/ad40916.txt delete mode 100644 .riot/requirements/b089663.txt delete mode 100644 .riot/requirements/b344fed.txt delete mode 100644 .riot/requirements/de53117.txt delete mode 100644 .riot/requirements/f9d0e8e.txt delete mode 100644 ddtrace/contrib/internal/mongoengine/__init__.py delete mode 100644 ddtrace/contrib/internal/mongoengine/patch.py delete mode 100644 ddtrace/contrib/internal/mongoengine/trace.py create mode 100644 releasenotes/notes/remove-pymongo-engine-0584c2055377f718.yaml delete mode 100644 tests/contrib/mongoengine/__init__.py delete mode 100644 tests/contrib/mongoengine/test.py delete mode 100644 tests/contrib/mongoengine/test_mongoengine_patch.py diff --git a/.riot/requirements/106f38d.txt b/.riot/requirements/106f38d.txt deleted file mode 100644 index 35ad753ef8f..00000000000 --- a/.riot/requirements/106f38d.txt +++ /dev/null @@ -1,23 +0,0 @@ -# -# This file is autogenerated by pip-compile with Python 3.14 -# by the following command: -# -# pip-compile --allow-unsafe --no-annotate .riot/requirements/106f38d.in -# -attrs==25.3.0 -coverage[toml]==7.10.5 -dnspython==2.7.0 -hypothesis==6.45.0 -iniconfig==2.1.0 -mock==5.2.0 -mongoengine==0.29.1 -opentracing==2.4.0 -packaging==25.0 -pluggy==1.6.0 -pygments==2.19.2 -pymongo==4.8.0 -pytest==8.4.1 -pytest-cov==6.2.1 -pytest-mock==3.14.1 -pytest-randomly==3.16.0 -sortedcontainers==2.4.0 diff --git a/.riot/requirements/1087ca6.txt b/.riot/requirements/1087ca6.txt deleted file mode 100644 index 875cc5be3a4..00000000000 --- a/.riot/requirements/1087ca6.txt +++ /dev/null @@ -1,26 +0,0 @@ -# -# This file is autogenerated by pip-compile with Python 3.10 -# by the following command: -# -# pip-compile --allow-unsafe --no-annotate .riot/requirements/1087ca6.in -# -attrs==25.3.0 -coverage[toml]==7.8.2 -dnspython==2.7.0 -exceptiongroup==1.3.0 -hypothesis==6.45.0 -iniconfig==2.1.0 -mock==5.2.0 -mongoengine==0.24.2 -opentracing==2.4.0 -packaging==25.0 -pluggy==1.6.0 -pygments==2.19.1 -pymongo==4.8.0 -pytest==8.4.0 -pytest-cov==6.1.1 -pytest-mock==3.14.1 -pytest-randomly==3.16.0 -sortedcontainers==2.4.0 -tomli==2.2.1 -typing-extensions==4.14.0 diff --git a/.riot/requirements/10a00e7.txt b/.riot/requirements/10a00e7.txt deleted file mode 100644 index ed2fd846015..00000000000 --- a/.riot/requirements/10a00e7.txt +++ /dev/null @@ -1,24 +0,0 @@ -# -# This file is autogenerated by pip-compile with Python 3.10 -# by the following command: -# -# pip-compile --no-annotate --resolver=backtracking .riot/requirements/10a00e7.in -# -attrs==24.2.0 -coverage[toml]==7.6.1 -dnspython==2.6.1 -exceptiongroup==1.2.2 -hypothesis==6.45.0 -iniconfig==2.0.0 -mock==5.1.0 -mongoengine==0.29.1 -opentracing==2.4.0 -packaging==24.1 -pluggy==1.5.0 -pymongo==4.8.0 -pytest==8.3.3 -pytest-cov==5.0.0 -pytest-mock==3.14.0 -pytest-randomly==3.15.0 -sortedcontainers==2.4.0 -tomli==2.0.1 diff --git a/.riot/requirements/10b490c.txt b/.riot/requirements/10b490c.txt deleted file mode 100644 index 4126321ff11..00000000000 --- a/.riot/requirements/10b490c.txt +++ /dev/null @@ -1,23 +0,0 @@ -# -# This file is autogenerated by pip-compile with Python 3.11 -# by the following command: -# -# pip-compile --allow-unsafe --no-annotate .riot/requirements/10b490c.in -# -attrs==25.3.0 -coverage[toml]==7.8.2 -dnspython==2.7.0 -hypothesis==6.45.0 -iniconfig==2.1.0 -mock==5.2.0 -mongoengine==0.24.2 -opentracing==2.4.0 -packaging==25.0 -pluggy==1.6.0 -pygments==2.19.1 -pymongo==4.8.0 -pytest==8.4.0 -pytest-cov==6.1.1 -pytest-mock==3.14.1 -pytest-randomly==3.16.0 -sortedcontainers==2.4.0 diff --git a/.riot/requirements/1424e42.txt b/.riot/requirements/1424e42.txt deleted file mode 100644 index f58bbb22bd6..00000000000 --- a/.riot/requirements/1424e42.txt +++ /dev/null @@ -1,22 +0,0 @@ -# -# This file is autogenerated by pip-compile with Python 3.12 -# by the following command: -# -# pip-compile --no-annotate .riot/requirements/1424e42.in -# -attrs==24.2.0 -coverage[toml]==7.6.1 -dnspython==2.6.1 -hypothesis==6.45.0 -iniconfig==2.0.0 -mock==5.1.0 -mongoengine==0.29.1 -opentracing==2.4.0 -packaging==24.1 -pluggy==1.5.0 -pymongo==4.8.0 -pytest==8.3.3 -pytest-cov==5.0.0 -pytest-mock==3.14.0 -pytest-randomly==3.15.0 -sortedcontainers==2.4.0 diff --git a/.riot/requirements/1468cf5.txt b/.riot/requirements/1468cf5.txt deleted file mode 100644 index 6b90ac2ac97..00000000000 --- a/.riot/requirements/1468cf5.txt +++ /dev/null @@ -1,23 +0,0 @@ -# -# This file is autogenerated by pip-compile with Python 3.14 -# by the following command: -# -# pip-compile --allow-unsafe --no-annotate .riot/requirements/1468cf5.in -# -attrs==25.3.0 -coverage[toml]==7.10.5 -dnspython==2.7.0 -hypothesis==6.45.0 -iniconfig==2.1.0 -mock==5.2.0 -mongoengine==0.29.1 -opentracing==2.4.0 -packaging==25.0 -pluggy==1.6.0 -pygments==2.19.2 -pymongo==4.8.0 -pytest==8.4.1 -pytest-cov==6.2.1 -pytest-mock==3.14.1 -pytest-randomly==3.16.0 -sortedcontainers==2.4.0 diff --git a/.riot/requirements/14e85f3.txt b/.riot/requirements/14e85f3.txt deleted file mode 100644 index 44ce4a54256..00000000000 --- a/.riot/requirements/14e85f3.txt +++ /dev/null @@ -1,22 +0,0 @@ -# -# This file is autogenerated by pip-compile with Python 3.11 -# by the following command: -# -# pip-compile --no-annotate --resolver=backtracking .riot/requirements/14e85f3.in -# -attrs==24.2.0 -coverage[toml]==7.6.1 -dnspython==2.6.1 -hypothesis==6.45.0 -iniconfig==2.0.0 -mock==5.1.0 -mongoengine==0.29.1 -opentracing==2.4.0 -packaging==24.1 -pluggy==1.5.0 -pymongo==4.8.0 -pytest==8.3.3 -pytest-cov==5.0.0 -pytest-mock==3.14.0 -pytest-randomly==3.15.0 -sortedcontainers==2.4.0 diff --git a/.riot/requirements/168e13d.txt b/.riot/requirements/168e13d.txt deleted file mode 100644 index 5161e01c8a3..00000000000 --- a/.riot/requirements/168e13d.txt +++ /dev/null @@ -1,23 +0,0 @@ -# -# This file is autogenerated by pip-compile with Python 3.14 -# by the following command: -# -# pip-compile --allow-unsafe --no-annotate .riot/requirements/168e13d.in -# -attrs==25.3.0 -coverage[toml]==7.10.5 -dnspython==2.7.0 -hypothesis==6.45.0 -iniconfig==2.1.0 -mock==5.2.0 -mongoengine==0.24.2 -opentracing==2.4.0 -packaging==25.0 -pluggy==1.6.0 -pygments==2.19.2 -pymongo==4.8.0 -pytest==8.4.1 -pytest-cov==6.2.1 -pytest-mock==3.14.1 -pytest-randomly==3.16.0 -sortedcontainers==2.4.0 diff --git a/.riot/requirements/170ff7e.txt b/.riot/requirements/170ff7e.txt deleted file mode 100644 index 64fffcfc4f2..00000000000 --- a/.riot/requirements/170ff7e.txt +++ /dev/null @@ -1,28 +0,0 @@ -# -# This file is autogenerated by pip-compile with Python 3.9 -# by the following command: -# -# pip-compile --allow-unsafe --no-annotate --resolver=backtracking .riot/requirements/170ff7e.in -# -attrs==25.3.0 -coverage[toml]==7.8.2 -dnspython==2.7.0 -exceptiongroup==1.3.0 -hypothesis==6.45.0 -importlib-metadata==8.7.0 -iniconfig==2.1.0 -mock==5.2.0 -mongoengine==0.24.2 -opentracing==2.4.0 -packaging==25.0 -pluggy==1.6.0 -pygments==2.19.1 -pymongo==4.8.0 -pytest==8.4.0 -pytest-cov==6.1.1 -pytest-mock==3.14.1 -pytest-randomly==3.16.0 -sortedcontainers==2.4.0 -tomli==2.2.1 -typing-extensions==4.14.0 -zipp==3.23.0 diff --git a/.riot/requirements/1c4e625.txt b/.riot/requirements/1c4e625.txt deleted file mode 100644 index 4ee880ebb56..00000000000 --- a/.riot/requirements/1c4e625.txt +++ /dev/null @@ -1,26 +0,0 @@ -# -# This file is autogenerated by pip-compile with Python 3.8 -# by the following command: -# -# pip-compile --allow-unsafe --no-annotate --resolver=backtracking .riot/requirements/1c4e625.in -# -attrs==25.3.0 -coverage[toml]==7.6.1 -exceptiongroup==1.3.0 -hypothesis==6.45.0 -importlib-metadata==8.5.0 -iniconfig==2.1.0 -mock==5.2.0 -mongoengine==0.23.1 -opentracing==2.4.0 -packaging==25.0 -pluggy==1.5.0 -pymongo==3.13.0 -pytest==8.3.5 -pytest-cov==5.0.0 -pytest-mock==3.14.1 -pytest-randomly==3.15.0 -sortedcontainers==2.4.0 -tomli==2.2.1 -typing-extensions==4.13.2 -zipp==3.20.2 diff --git a/.riot/requirements/1ce93b3.txt b/.riot/requirements/1ce93b3.txt deleted file mode 100644 index a0edba9ffd0..00000000000 --- a/.riot/requirements/1ce93b3.txt +++ /dev/null @@ -1,22 +0,0 @@ -# -# This file is autogenerated by pip-compile with Python 3.13 -# by the following command: -# -# pip-compile --allow-unsafe --no-annotate .riot/requirements/1ce93b3.in -# -attrs==24.2.0 -coverage[toml]==7.6.1 -dnspython==2.7.0 -hypothesis==6.45.0 -iniconfig==2.0.0 -mock==5.1.0 -mongoengine==0.29.1 -opentracing==2.4.0 -packaging==24.1 -pluggy==1.5.0 -pymongo==4.8.0 -pytest==8.3.3 -pytest-cov==5.0.0 -pytest-mock==3.14.0 -pytest-randomly==3.15.0 -sortedcontainers==2.4.0 diff --git a/.riot/requirements/328b28c.txt b/.riot/requirements/328b28c.txt deleted file mode 100644 index 38eac9651b9..00000000000 --- a/.riot/requirements/328b28c.txt +++ /dev/null @@ -1,24 +0,0 @@ -# -# This file is autogenerated by pip-compile with Python 3.10 -# by the following command: -# -# pip-compile --no-annotate --resolver=backtracking .riot/requirements/328b28c.in -# -attrs==24.2.0 -coverage[toml]==7.6.1 -dnspython==2.6.1 -exceptiongroup==1.2.2 -hypothesis==6.45.0 -iniconfig==2.0.0 -mock==5.1.0 -mongoengine==0.29.1 -opentracing==2.4.0 -packaging==24.1 -pluggy==1.5.0 -pymongo==4.8.0 -pytest==8.3.3 -pytest-cov==5.0.0 -pytest-mock==3.14.0 -pytest-randomly==3.15.0 -sortedcontainers==2.4.0 -tomli==2.0.1 diff --git a/.riot/requirements/3dd53da.txt b/.riot/requirements/3dd53da.txt deleted file mode 100644 index 088ac0ddd7e..00000000000 --- a/.riot/requirements/3dd53da.txt +++ /dev/null @@ -1,22 +0,0 @@ -# -# This file is autogenerated by pip-compile with Python 3.13 -# by the following command: -# -# pip-compile --allow-unsafe --no-annotate .riot/requirements/3dd53da.in -# -attrs==24.2.0 -coverage[toml]==7.6.1 -dnspython==2.7.0 -hypothesis==6.45.0 -iniconfig==2.0.0 -mock==5.1.0 -mongoengine==0.29.1 -opentracing==2.4.0 -packaging==24.1 -pluggy==1.5.0 -pymongo==4.8.0 -pytest==8.3.3 -pytest-cov==5.0.0 -pytest-mock==3.14.0 -pytest-randomly==3.15.0 -sortedcontainers==2.4.0 diff --git a/.riot/requirements/40a41fd.txt b/.riot/requirements/40a41fd.txt deleted file mode 100644 index 9f9034b3892..00000000000 --- a/.riot/requirements/40a41fd.txt +++ /dev/null @@ -1,23 +0,0 @@ -# -# This file is autogenerated by pip-compile with Python 3.13 -# by the following command: -# -# pip-compile --allow-unsafe --no-annotate .riot/requirements/40a41fd.in -# -attrs==25.3.0 -coverage[toml]==7.8.2 -dnspython==2.7.0 -hypothesis==6.45.0 -iniconfig==2.1.0 -mock==5.2.0 -mongoengine==0.24.2 -opentracing==2.4.0 -packaging==25.0 -pluggy==1.6.0 -pygments==2.19.1 -pymongo==4.8.0 -pytest==8.4.0 -pytest-cov==6.1.1 -pytest-mock==3.14.1 -pytest-randomly==3.16.0 -sortedcontainers==2.4.0 diff --git a/.riot/requirements/a0b94b1.txt b/.riot/requirements/a0b94b1.txt deleted file mode 100644 index 71d76a09e22..00000000000 --- a/.riot/requirements/a0b94b1.txt +++ /dev/null @@ -1,23 +0,0 @@ -# -# This file is autogenerated by pip-compile with Python 3.12 -# by the following command: -# -# pip-compile --allow-unsafe --no-annotate .riot/requirements/a0b94b1.in -# -attrs==25.3.0 -coverage[toml]==7.8.2 -dnspython==2.7.0 -hypothesis==6.45.0 -iniconfig==2.1.0 -mock==5.2.0 -mongoengine==0.24.2 -opentracing==2.4.0 -packaging==25.0 -pluggy==1.6.0 -pygments==2.19.1 -pymongo==4.8.0 -pytest==8.4.0 -pytest-cov==6.1.1 -pytest-mock==3.14.1 -pytest-randomly==3.16.0 -sortedcontainers==2.4.0 diff --git a/.riot/requirements/ad40916.txt b/.riot/requirements/ad40916.txt deleted file mode 100644 index 853f497ee9e..00000000000 --- a/.riot/requirements/ad40916.txt +++ /dev/null @@ -1,22 +0,0 @@ -# -# This file is autogenerated by pip-compile with Python 3.11 -# by the following command: -# -# pip-compile --no-annotate --resolver=backtracking .riot/requirements/ad40916.in -# -attrs==24.2.0 -coverage[toml]==7.6.1 -dnspython==2.6.1 -hypothesis==6.45.0 -iniconfig==2.0.0 -mock==5.1.0 -mongoengine==0.29.1 -opentracing==2.4.0 -packaging==24.1 -pluggy==1.5.0 -pymongo==4.8.0 -pytest==8.3.3 -pytest-cov==5.0.0 -pytest-mock==3.14.0 -pytest-randomly==3.15.0 -sortedcontainers==2.4.0 diff --git a/.riot/requirements/b089663.txt b/.riot/requirements/b089663.txt deleted file mode 100644 index 956c6d73e92..00000000000 --- a/.riot/requirements/b089663.txt +++ /dev/null @@ -1,26 +0,0 @@ -# -# This file is autogenerated by pip-compile with Python 3.9 -# by the following command: -# -# pip-compile --no-annotate --resolver=backtracking .riot/requirements/b089663.in -# -attrs==24.2.0 -coverage[toml]==7.6.1 -dnspython==2.6.1 -exceptiongroup==1.2.2 -hypothesis==6.45.0 -importlib-metadata==8.5.0 -iniconfig==2.0.0 -mock==5.1.0 -mongoengine==0.29.1 -opentracing==2.4.0 -packaging==24.1 -pluggy==1.5.0 -pymongo==4.8.0 -pytest==8.3.3 -pytest-cov==5.0.0 -pytest-mock==3.14.0 -pytest-randomly==3.15.0 -sortedcontainers==2.4.0 -tomli==2.0.1 -zipp==3.20.2 diff --git a/.riot/requirements/b344fed.txt b/.riot/requirements/b344fed.txt deleted file mode 100644 index 73e61eb69f9..00000000000 --- a/.riot/requirements/b344fed.txt +++ /dev/null @@ -1,22 +0,0 @@ -# -# This file is autogenerated by pip-compile with Python 3.12 -# by the following command: -# -# pip-compile --no-annotate .riot/requirements/b344fed.in -# -attrs==24.2.0 -coverage[toml]==7.6.1 -dnspython==2.6.1 -hypothesis==6.45.0 -iniconfig==2.0.0 -mock==5.1.0 -mongoengine==0.29.1 -opentracing==2.4.0 -packaging==24.1 -pluggy==1.5.0 -pymongo==4.8.0 -pytest==8.3.3 -pytest-cov==5.0.0 -pytest-mock==3.14.0 -pytest-randomly==3.15.0 -sortedcontainers==2.4.0 diff --git a/.riot/requirements/de53117.txt b/.riot/requirements/de53117.txt deleted file mode 100644 index 1dd3dcf18f2..00000000000 --- a/.riot/requirements/de53117.txt +++ /dev/null @@ -1,26 +0,0 @@ -# -# This file is autogenerated by pip-compile with Python 3.9 -# by the following command: -# -# pip-compile --no-annotate --resolver=backtracking .riot/requirements/de53117.in -# -attrs==24.2.0 -coverage[toml]==7.6.1 -dnspython==2.6.1 -exceptiongroup==1.2.2 -hypothesis==6.45.0 -importlib-metadata==8.5.0 -iniconfig==2.0.0 -mock==5.1.0 -mongoengine==0.29.1 -opentracing==2.4.0 -packaging==24.1 -pluggy==1.5.0 -pymongo==4.8.0 -pytest==8.3.3 -pytest-cov==5.0.0 -pytest-mock==3.14.0 -pytest-randomly==3.15.0 -sortedcontainers==2.4.0 -tomli==2.0.1 -zipp==3.20.2 diff --git a/.riot/requirements/f9d0e8e.txt b/.riot/requirements/f9d0e8e.txt deleted file mode 100644 index 42bc8937d56..00000000000 --- a/.riot/requirements/f9d0e8e.txt +++ /dev/null @@ -1,26 +0,0 @@ -# -# This file is autogenerated by pip-compile with Python 3.8 -# by the following command: -# -# pip-compile --no-annotate .riot/requirements/f9d0e8e.in -# -attrs==24.2.0 -coverage[toml]==7.6.1 -dnspython==2.6.1 -exceptiongroup==1.2.2 -hypothesis==6.45.0 -importlib-metadata==8.5.0 -iniconfig==2.0.0 -mock==5.1.0 -mongoengine==0.29.1 -opentracing==2.4.0 -packaging==24.1 -pluggy==1.5.0 -pymongo==4.8.0 -pytest==8.3.3 -pytest-cov==5.0.0 -pytest-mock==3.14.0 -pytest-randomly==3.15.0 -sortedcontainers==2.4.0 -tomli==2.0.1 -zipp==3.20.2 diff --git a/ddtrace/_monkey.py b/ddtrace/_monkey.py index 5cef2d0f5cf..170c1870871 100644 --- a/ddtrace/_monkey.py +++ b/ddtrace/_monkey.py @@ -57,7 +57,6 @@ "kafka": True, "langgraph": True, "litellm": True, - "mongoengine": True, "mysql": True, "mysqldb": True, "pymysql": True, diff --git a/ddtrace/contrib/integration_registry/registry.yaml b/ddtrace/contrib/integration_registry/registry.yaml index 1a877c8e784..2adf38cf686 100644 --- a/ddtrace/contrib/integration_registry/registry.yaml +++ b/ddtrace/contrib/integration_registry/registry.yaml @@ -599,16 +599,6 @@ integrations: min: 1.0.2 max: 1.0.2 -- integration_name: mongoengine - is_external_package: true - is_tested: true - dependency_names: - - mongoengine - tested_versions_by_dependency: - mongoengine: - min: 0.23.1 - max: 0.29.1 - - integration_name: mysql is_external_package: true is_tested: true diff --git a/ddtrace/contrib/internal/mongoengine/__init__.py b/ddtrace/contrib/internal/mongoengine/__init__.py deleted file mode 100644 index a72c861f4b7..00000000000 --- a/ddtrace/contrib/internal/mongoengine/__init__.py +++ /dev/null @@ -1,19 +0,0 @@ -"""Instrument mongoengine to report MongoDB queries. - -``import ddtrace.auto`` will automatically patch your mongoengine connect method to make it work. -:: - - from ddtrace import patch - from ddtrace.trace import Pin - import mongoengine - - # If not patched yet, you can patch mongoengine specifically - patch(mongoengine=True) - - # At that point, mongoengine is instrumented with the default settings - mongoengine.connect('db', alias='default') - - # Use a pin to specify metadata related to this client - client = mongoengine.connect('db', alias='master') - Pin.override(client, service="mongo-master") -""" diff --git a/ddtrace/contrib/internal/mongoengine/patch.py b/ddtrace/contrib/internal/mongoengine/patch.py deleted file mode 100644 index 550d1e83199..00000000000 --- a/ddtrace/contrib/internal/mongoengine/patch.py +++ /dev/null @@ -1,38 +0,0 @@ -# TODO(mabdinur): Remove the pymongoengine integration, this integration does nothing special -# it just uses the pymongo integration and creates unnecessary pin objects -from typing import Dict - -import mongoengine - -from ..pymongo.patch import patch as patch_pymongo_module -from ..pymongo.patch import unpatch as unpatch_pymongo_module -from .trace import WrappedConnect - - -# Original connect function -_connect = mongoengine.connect - - -def get_version(): - # type: () -> str - return getattr(mongoengine, "__version__", "") - - -def _supported_versions() -> Dict[str, str]: - return {"mongoengine": ">=0.23"} - - -def patch(): - if getattr(mongoengine, "_datadog_patch", False): - return - mongoengine.connect = WrappedConnect(_connect) - mongoengine._datadog_patch = True - patch_pymongo_module() - - -def unpatch(): - if not getattr(mongoengine, "_datadog_patch", False): - return - mongoengine.connect = _connect - mongoengine._datadog_patch = False - unpatch_pymongo_module() diff --git a/ddtrace/contrib/internal/mongoengine/trace.py b/ddtrace/contrib/internal/mongoengine/trace.py deleted file mode 100644 index e3deee0e4a4..00000000000 --- a/ddtrace/contrib/internal/mongoengine/trace.py +++ /dev/null @@ -1,38 +0,0 @@ -# 3p -# project -import wrapt - -from ddtrace._trace.pin import Pin - -# keep the TracedMongoClient import to avoid breaking the public api -from ddtrace.contrib.internal.pymongo.client import TracedMongoClient # noqa: F401 -from ddtrace.ext import mongo as mongox -from ddtrace.internal.schema import schematize_service_name - - -# TODO(Benjamin): we should instrument register_connection instead, because more generic -# We should also extract the "alias" attribute and set it as a meta -_SERVICE = schematize_service_name(mongox.SERVICE) - - -# TODO(mabdinur): Remove this class when ``ddtrace.contrib.mongoengine.trace`` is removed -class WrappedConnect(wrapt.ObjectProxy): - """WrappedConnect wraps mongoengines 'connect' function to ensure - that all returned connections are wrapped for tracing. - """ - - def __init__(self, connect): - super(WrappedConnect, self).__init__(connect) - Pin(_SERVICE).onto(self) - - def __call__(self, *args, **kwargs): - client = self.__wrapped__(*args, **kwargs) - pin = Pin.get_from(self) - if pin: - tracer = pin.tracer - pp = Pin(service=pin.service) - if tracer is not None: - pp._tracer = tracer - pp.onto(client) - - return client diff --git a/ddtrace/settings/_config.py b/ddtrace/settings/_config.py index 9a14793c080..41175d7a56f 100644 --- a/ddtrace/settings/_config.py +++ b/ddtrace/settings/_config.py @@ -158,7 +158,6 @@ "aiopg", "dogpile_cache", "pylibmc", - "mongoengine", "httpx", "httplib", "rq", diff --git a/docs/contributing-integrations.rst b/docs/contributing-integrations.rst index 8db0e205a2f..0ec2289013d 100644 --- a/docs/contributing-integrations.rst +++ b/docs/contributing-integrations.rst @@ -204,7 +204,6 @@ are not yet any expected spans stored for it, so we need to create some. mongo: - ddtrace/contrib/internal/pymongo/* - - ddtrace/contrib/internal/mongoengine/* - ddtrace/ext/mongo.py 15. Add a `suite` for your integration in `tests/contrib/suitespec.yml`. This defines test configuration diff --git a/docs/index.rst b/docs/index.rst index 8275e9998b2..6b3d6ffa67c 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -152,8 +152,6 @@ contacting support. +--------------------------------------------------+------------+----------+------+ | :ref:`molten` | >= 1.0 | Yes | | +--------------------------------------------------+------------+----------+------+ -| :ref:`mongoengine` | >= 0.23 | Yes | | -+--------------------------------------------------+------------+----------+------+ | :ref:`mysql-connector` | >= 8.0.5 | Yes | | +--------------------------------------------------+------------+----------+------+ | :ref:`mysqldb` | \* | Yes | | diff --git a/docs/integrations.rst b/docs/integrations.rst index ba36c26912d..b01829193c3 100644 --- a/docs/integrations.rst +++ b/docs/integrations.rst @@ -368,13 +368,6 @@ Molten .. automodule:: ddtrace.contrib.internal.molten -.. _mongoengine: - -Mongoengine -^^^^^^^^^^^ -.. automodule:: ddtrace.contrib.internal.mongoengine - - .. _mysql-connector: mysql-connector diff --git a/releasenotes/notes/remove-pymongo-engine-0584c2055377f718.yaml b/releasenotes/notes/remove-pymongo-engine-0584c2055377f718.yaml new file mode 100644 index 00000000000..772aade8185 --- /dev/null +++ b/releasenotes/notes/remove-pymongo-engine-0584c2055377f718.yaml @@ -0,0 +1,5 @@ +--- +other: + - | + mongoengine: Drops support for the ``ddtrace.Pin`` object with mongoengine. With this change, the ddtrace library no longer directly supports mongoengine. + Mongoengine will be supported through the ``pymongo`` integration. diff --git a/riotfile.py b/riotfile.py index 224a59ca7b4..6cbee9ddbc1 100644 --- a/riotfile.py +++ b/riotfile.py @@ -1632,26 +1632,6 @@ def select_pys(min_version: str = MIN_PYTHON_VERSION, max_version: str = MAX_PYT ), ], ), - Venv( - name="mongoengine", - command="pytest {cmdargs} tests/contrib/mongoengine", - pkgs={ - # pymongo v4.9.0 introduced breaking changes that are not yet supported by mongoengine - "pymongo": "<4.9.0", - "pytest-randomly": latest, - }, - venvs=[ - Venv( - pys="3.8", - pkgs={"mongoengine": ["~=0.23.0", latest]}, - ), - Venv( - # mongoengine added support for Python 3.9/3.10 in 0.24 - pys=select_pys(min_version="3.9"), - pkgs={"mongoengine": ["~=0.24.0", "~=0.24", latest]}, - ), - ], - ), Venv( name="asgi", pkgs={ diff --git a/supported_versions_output.json b/supported_versions_output.json index ba6dc49f9cb..54d2847881a 100644 --- a/supported_versions_output.json +++ b/supported_versions_output.json @@ -457,13 +457,6 @@ "max_tracer_supported": "1.0.2", "auto-instrumented": true }, - { - "dependency": "mongoengine", - "integration": "mongoengine", - "minimum_tracer_supported": "0.23.1", - "max_tracer_supported": "0.29.1", - "auto-instrumented": true - }, { "dependency": "mysql-connector-python", "integration": "mysql", diff --git a/supported_versions_table.csv b/supported_versions_table.csv index 25309eedf48..1da57e9f537 100644 --- a/supported_versions_table.csv +++ b/supported_versions_table.csv @@ -63,7 +63,6 @@ mako,mako,1.0.14,1.3.10,True mariadb,mariadb,1.0.11,1.1.13,True mcp,mcp,1.10.1,1.16.0,True molten,molten,1.0.2,1.0.2,True -mongoengine,mongoengine,0.23.1,0.29.1,True mysql-connector-python,mysql,8.0.5,9.4.0,True mysqlclient,mysqldb,2.2.1,2.2.6,True openai,openai *,1.0.0,1.109.1,True diff --git a/tests/contrib/integration_registry/registry_update_helpers/integration_registry_manager.py b/tests/contrib/integration_registry/registry_update_helpers/integration_registry_manager.py index f5990c6c6c2..4e6659b6321 100644 --- a/tests/contrib/integration_registry/registry_update_helpers/integration_registry_manager.py +++ b/tests/contrib/integration_registry/registry_update_helpers/integration_registry_manager.py @@ -39,7 +39,7 @@ def _is_valid_patch_call(self, tb_string): """Checks if the patch call originated from ddtrace.contrib.internal/*/patch.py.""" # reverse the lines to check the most recent patch call first since some integrations call # other integrations patches: - # e.g. mongoengine calls pymongo's patch + # e.g. django calls postgres's patch return any( "ddtrace/contrib/internal" in line and "/patch.py" in line for line in reversed(tb_string.splitlines()) ) diff --git a/tests/contrib/mongoengine/__init__.py b/tests/contrib/mongoengine/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/tests/contrib/mongoengine/test.py b/tests/contrib/mongoengine/test.py deleted file mode 100644 index d47c5a397e6..00000000000 --- a/tests/contrib/mongoengine/test.py +++ /dev/null @@ -1,415 +0,0 @@ -import time - -import mongoengine -import pymongo - -from ddtrace._trace.pin import Pin -from ddtrace.contrib.internal.mongoengine.patch import patch -from ddtrace.contrib.internal.mongoengine.patch import unpatch -from ddtrace.ext import mongo as mongox -from ddtrace.internal.schema import DEFAULT_SPAN_SERVICE_NAME -from tests.opentracer.utils import init_tracer -from tests.utils import DummyTracer -from tests.utils import TracerTestCase -from tests.utils import assert_is_measured - -from ..config import MONGO_CONFIG - - -class Artist(mongoengine.Document): - first_name = mongoengine.StringField(max_length=50) - last_name = mongoengine.StringField(max_length=50) - - -class MongoEngineCore(object): - # Define the service at the class level, so that each test suite can use a different service - # and therefore catch any sneaky badly-unpatched stuff. - TEST_SERVICE = "deadbeef" - - def get_tracer_and_connect(self): - # implement me - pass - - def test_insert_update_delete_query(self): - tracer = self.get_tracer_and_connect() - - start = time.time() - Artist.drop_collection() - end = time.time() - - # ensure we get a drop collection span - spans = tracer.pop() - assert len(spans) == 2 - span = spans[1] - assert span.name == "pymongo.cmd" - - assert_is_measured(span) - assert span.resource == "drop artist" - assert span.span_type == "mongodb" - assert span.service == self.TEST_SERVICE - _assert_timing(span, start, end) - - start = end - joni = Artist() - joni.first_name = "Joni" - joni.last_name = "Mitchell" - joni.save() - end = time.time() - - # ensure we get an insert span - spans = tracer.pop() - assert len(spans) == 2 - span = spans[1] - assert span.name == "pymongo.cmd" - assert_is_measured(span) - assert span.resource == "insert artist" - assert span.span_type == "mongodb" - assert span.service == self.TEST_SERVICE - _assert_timing(span, start, end) - - # ensure full scans work - start = time.time() - artists = [a for a in Artist.objects] - end = time.time() - assert len(artists) == 1 - assert artists[0].first_name == "Joni" - assert artists[0].last_name == "Mitchell" - - # query names should be used in pymongo>3.1 - name = "find" if pymongo.version_tuple >= (3, 1, 0) else "query" - - spans = tracer.pop() - assert len(spans) == 2 - span = spans[1] - assert span.name == "pymongo.cmd" - assert_is_measured(span) - assert span.resource == "{} artist".format(name) - assert span.span_type == "mongodb" - assert span.service == self.TEST_SERVICE - _assert_timing(span, start, end) - - # ensure filtered queries work - start = time.time() - artists = [a for a in Artist.objects(first_name="Joni")] - end = time.time() - assert len(artists) == 1 - joni = artists[0] - assert artists[0].first_name == "Joni" - assert artists[0].last_name == "Mitchell" - - spans = tracer.pop() - assert len(spans) == 2 - span = spans[1] - assert span.name == "pymongo.cmd" - assert_is_measured(span) - assert span.resource == '{} artist {{"first_name": "?"}}'.format(name) - assert span.span_type == "mongodb" - assert span.service == self.TEST_SERVICE - _assert_timing(span, start, end) - - # ensure updates work - start = time.time() - joni.last_name = "From Saskatoon" - joni.save() - end = time.time() - - spans = tracer.pop() - assert len(spans) == 2 - span = spans[1] - assert span.name == "pymongo.cmd" - assert_is_measured(span) - assert span.resource == 'update artist {"_id": "?"}' - assert span.span_type == "mongodb" - assert span.service == self.TEST_SERVICE - _assert_timing(span, start, end) - - # ensure deletes - start = time.time() - joni.delete() - end = time.time() - - spans = tracer.pop() - assert len(spans) == 2 - span = spans[1] - assert span.name == "pymongo.cmd" - assert_is_measured(span) - assert span.resource == 'delete artist {"_id": "?"}' - assert span.span_type == "mongodb" - assert span.service == self.TEST_SERVICE - assert span.get_tag("component") == "pymongo" - assert span.get_tag("span.kind") == "client" - assert span.get_tag("db.system") == "mongodb" - _assert_timing(span, start, end) - - def test_opentracing(self): - """Ensure the opentracer works with mongoengine.""" - tracer = self.get_tracer_and_connect() - ot_tracer = init_tracer("my_svc", tracer) - - with ot_tracer.start_active_span("ot_span"): - start = time.time() - Artist.drop_collection() - end = time.time() - - # ensure we get a drop collection span - spans = tracer.pop() - assert len(spans) == 3 - ot_span, dd_server_span, dd_cmd_span = spans - - # confirm the parenting - assert ot_span.parent_id is None - assert dd_server_span.parent_id == ot_span.span_id - - assert ot_span.name == "ot_span" - assert ot_span.service == "my_svc" - - assert_is_measured(dd_cmd_span) - assert dd_cmd_span.resource == "drop artist" - assert dd_cmd_span.span_type == "mongodb" - assert dd_cmd_span.service == self.TEST_SERVICE - _assert_timing(dd_cmd_span, start, end) - - -class TestMongoEnginePatchConnectDefault(TracerTestCase, MongoEngineCore): - """Test suite with a global Pin for the connect function with the default configuration""" - - TEST_SERVICE = mongox.SERVICE - - def setUp(self): - patch() - - def tearDown(self): - unpatch() - # Disconnect and remove the client - mongoengine.connection.disconnect() - - def get_tracer_and_connect(self): - tracer = DummyTracer() - client = mongoengine.connect(port=MONGO_CONFIG["port"]) - Pin.get_from(client)._clone(tracer=tracer).onto(client) - return tracer - - -class TestMongoEnginePatchConnectSchematization(TestMongoEnginePatchConnectDefault): - @TracerTestCase.run_in_subprocess(env_overrides=dict(DD_SERVICE="mysvc")) - def test_user_specified_service_default(self): - """ - : When a user specifies a service for the app - The mongoengine integration should not use it. - """ - from ddtrace import config - - assert config.service == "mysvc" - - tracer = self.get_tracer_and_connect() - Artist.drop_collection() - - spans = tracer.pop() - assert len(spans) == 2 - assert spans[1].name == "pymongo.cmd" - assert spans[1].service != "mysvc" - - @TracerTestCase.run_in_subprocess(env_overrides=dict(DD_TRACE_SPAN_ATTRIBUTE_SCHEMA="v0", DD_SERVICE="mysvc")) - def test_user_specified_service_v0(self): - """ - v0: When a user specifies a service for the app - The mongoengine integration should not use it. - """ - from ddtrace import config - - assert config.service == "mysvc" - - tracer = self.get_tracer_and_connect() - Artist.drop_collection() - - spans = tracer.pop() - assert len(spans) == 2 - assert spans[1].name == "pymongo.cmd" - assert spans[1].service != "mysvc" - - @TracerTestCase.run_in_subprocess(env_overrides=dict(DD_TRACE_SPAN_ATTRIBUTE_SCHEMA="v1", DD_SERVICE="mysvc")) - def test_user_specified_service_v1(self): - """ - In v1 of the span attribute schema, when a user specifies a service for the app - The mongoengine integration should use it as the default. - """ - from ddtrace import config - - assert config.service == "mysvc" - - tracer = self.get_tracer_and_connect() - Artist.drop_collection() - - spans = tracer.pop() - assert len(spans) == 2 - assert spans[1].name == "mongodb.query" - assert spans[1].service == "mysvc" - - @TracerTestCase.run_in_subprocess(env_overrides=dict(DD_TRACE_SPAN_ATTRIBUTE_SCHEMA="v0")) - def test_unspecified_service_v0(self): - """ - In v0 of the span attribute schema, when there is no specified DD_SERVICE - The mongoengine integration should use None as the default. - """ - from ddtrace import config - - assert config.service is DEFAULT_SPAN_SERVICE_NAME - - tracer = self.get_tracer_and_connect() - Artist.drop_collection() - - spans = tracer.pop() - assert len(spans) == 2 - assert spans[0].service == "mongodb" - - @TracerTestCase.run_in_subprocess(env_overrides=dict(DD_TRACE_SPAN_ATTRIBUTE_SCHEMA="v1")) - def test_unspecified_service_v1(self): - """ - In v1 of the span attribute schema, when there is no specified DD_SERVICE - The mongoengine integration should use DEFAULT_SPAN_SERVICE_NAME as the default. - """ - from ddtrace import config - - assert config.service == DEFAULT_SPAN_SERVICE_NAME - - tracer = self.get_tracer_and_connect() - Artist.drop_collection() - - spans = tracer.pop() - assert len(spans) == 2 - assert spans[0].service == DEFAULT_SPAN_SERVICE_NAME - - @TracerTestCase.run_in_subprocess(env_overrides=dict(DD_TRACE_SPAN_ATTRIBUTE_SCHEMA="v0")) - def test_span_name_v0_schema(self): - """ - When a user specifies a service for the app - The mongoengine integration should not use it. - """ - tracer = self.get_tracer_and_connect() - Artist.drop_collection() - - spans = tracer.pop() - assert len(spans) == 2 - assert spans[0].name == "pymongo.checkout" or spans[0].name == "pymongo.get_socket" - assert spans[1].name == "pymongo.cmd" - - @TracerTestCase.run_in_subprocess(env_overrides=dict(DD_TRACE_SPAN_ATTRIBUTE_SCHEMA="v1")) - def test_span_name_v1_schema(self): - """ - When a user specifies a service for the app - The mongoengine integration should not use it. - """ - tracer = self.get_tracer_and_connect() - Artist.drop_collection() - - spans = tracer.pop() - assert len(spans) == 2 - assert spans[0].name == "pymongo.checkout" or spans[0].name == "pymongo.get_socket" - assert spans[1].name == "mongodb.query" - - -class TestMongoEnginePatchConnect(TestMongoEnginePatchConnectDefault): - """Test suite with a global Pin for the connect function with custom service""" - - TEST_SERVICE = "test-mongo-patch-connect" - - def get_tracer_and_connect(self): - tracer = TestMongoEnginePatchConnectDefault.get_tracer_and_connect(self) - pin = Pin(service=self.TEST_SERVICE) - pin._tracer = tracer - pin.onto(mongoengine.connect) - mongoengine.connect(port=MONGO_CONFIG["port"]) - - return tracer - - -class TestMongoEnginePatchClientDefault(TracerTestCase, MongoEngineCore): - """Test suite with a Pin local to a specific client with default configuration""" - - TEST_SERVICE = mongox.SERVICE - - def setUp(self): - patch() - - def tearDown(self): - unpatch() - # Disconnect and remove the client - mongoengine.connection.disconnect() - - def get_tracer_and_connect(self): - tracer = DummyTracer() - client = mongoengine.connect(port=MONGO_CONFIG["port"]) - Pin.get_from(client)._clone(tracer=tracer).onto(client) - - return tracer - - -class TestMongoEnginePatchClient(TestMongoEnginePatchClientDefault): - """Test suite with a Pin local to a specific client with custom service""" - - TEST_SERVICE = "test-mongo-patch-client" - - def get_tracer_and_connect(self): - tracer = DummyTracer() - # Set a connect-level service, to check that we properly override it - Pin(service="not-%s" % self.TEST_SERVICE).onto(mongoengine.connect) - client = mongoengine.connect(port=MONGO_CONFIG["port"]) - pin = Pin(service=self.TEST_SERVICE) - pin._tracer = tracer - pin.onto(client) - - return tracer - - def test_patch_unpatch(self): - tracer = DummyTracer() - - # Test patch idempotence - patch() - patch() - - client = mongoengine.connect(port=MONGO_CONFIG["port"]) - Pin.get_from(client)._clone(tracer=tracer).onto(client) - - Artist.drop_collection() - spans = tracer.pop() - assert spans, spans - assert len(spans) == 2 - - mongoengine.connection.disconnect() - tracer.pop() - - # Test unpatch - unpatch() - - mongoengine.connect(port=MONGO_CONFIG["port"]) - - Artist.drop_collection() - spans = tracer.pop() - assert not spans, spans - - # Disconnect so a new pymongo client can be created, - # connections are patched on instantiation - mongoengine.connection.disconnect() - # Test patch again - patch() - client = mongoengine.connect(port=MONGO_CONFIG["port"]) - Pin.get_from(client)._clone(tracer=tracer).onto(client) - - Artist.drop_collection() - spans = tracer.pop() - assert spans, spans - assert len(spans) == 2 - - def test_multiple_connect_no_double_patching(self): - """Ensure we do not double patch client._topology - - Regression test for https://github.com/DataDog/dd-trace-py/issues/2474 - """ - client = mongoengine.connect(port=MONGO_CONFIG["port"]) - assert Pin.get_from(client) is Pin.get_from(client._topology) - client.close() - - -def _assert_timing(span, start, end): - assert start < span.start < end - assert span.duration < end - start diff --git a/tests/contrib/mongoengine/test_mongoengine_patch.py b/tests/contrib/mongoengine/test_mongoengine_patch.py deleted file mode 100644 index 6f219d1566e..00000000000 --- a/tests/contrib/mongoengine/test_mongoengine_patch.py +++ /dev/null @@ -1,31 +0,0 @@ -# This test script was automatically generated by the contrib-patch-tests.py -# script. If you want to make changes to it, you should make sure that you have -# removed the ``_generated`` suffix from the file name, to prevent the content -# from being overwritten by future re-generations. - -from ddtrace.contrib.internal.mongoengine.patch import get_version -from ddtrace.contrib.internal.mongoengine.patch import patch - - -try: - from ddtrace.contrib.internal.mongoengine.patch import unpatch -except ImportError: - unpatch = None -from tests.contrib.patch import PatchTestCase - - -class TestMongoenginePatch(PatchTestCase.Base): - __integration_name__ = "mongoengine" - __module_name__ = "mongoengine" - __patch_func__ = patch - __unpatch_func__ = unpatch - __get_version__ = get_version - - def assert_module_patched(self, mongoengine): - pass - - def assert_not_module_patched(self, mongoengine): - pass - - def assert_not_module_double_patched(self, mongoengine): - pass diff --git a/tests/contrib/suitespec.yml b/tests/contrib/suitespec.yml index ec373de1f66..d3ac8289e95 100644 --- a/tests/contrib/suitespec.yml +++ b/tests/contrib/suitespec.yml @@ -126,7 +126,6 @@ components: - ddtrace/contrib/internal/molten/* mongo: - ddtrace/contrib/internal/pymongo/* - - ddtrace/contrib/internal/mongoengine/* - ddtrace/ext/mongo.py mysql: - ddtrace/contrib/internal/mysql/* @@ -882,18 +881,6 @@ suites: - tests/contrib/molten/* runner: riot snapshot: true - mongoengine: - paths: - - '@bootstrap' - - '@core' - - '@contrib' - - '@tracing' - - '@mongo' - - tests/contrib/mongoengine/* - runner: riot - snapshot: true - services: - - mongo mysqlpython: paths: - '@bootstrap' From 1e1dda5ecdd1ea040162615eec67da793e9f93ce Mon Sep 17 00:00:00 2001 From: Emmett Butler <723615+emmettbutler@users.noreply.github.com> Date: Fri, 24 Oct 2025 07:10:14 -0700 Subject: [PATCH 4/5] chore: remove opentracer package (#14892) This change removes the deprecated `opentracer` package from ddtrace. Note the base branch, a staging area for breaking changes slated for 4.0. --------- Co-authored-by: brettlangdon --- ddtrace/opentracer/__init__.py | 18 - ddtrace/opentracer/helpers.py | 25 - ddtrace/opentracer/propagation/__init__.py | 6 - ddtrace/opentracer/propagation/binary.py | 0 ddtrace/opentracer/propagation/http.py | 74 --- ddtrace/opentracer/propagation/propagator.py | 13 - ddtrace/opentracer/propagation/text.py | 0 ddtrace/opentracer/settings.py | 41 -- ddtrace/opentracer/span.py | 197 ------ ddtrace/opentracer/span_context.py | 66 -- ddtrace/opentracer/tags.py | 23 - ddtrace/opentracer/tracer.py | 399 ------------ ddtrace/opentracer/utils.py | 43 -- .../opentracer-remove-b1883d26ea035c50.yaml | 4 + tests/commands/ddtrace_run_app_name.py | 6 - tests/commands/test_runner.py | 7 - tests/contrib/aiobotocore/test.py | 86 --- tests/contrib/aiohttp/test_middleware.py | 18 - tests/contrib/aiopg/test.py | 24 - tests/contrib/aredis/test_aredis.py | 14 - tests/contrib/asyncio/test_propagation.py | 57 -- tests/contrib/boto/test.py | 54 -- tests/contrib/botocore/test.py | 38 -- tests/contrib/bottle/test.py | 39 -- tests/contrib/celery/test_integration.py | 50 -- tests/contrib/django/test_django.py | 33 - tests/contrib/falcon/test_suite.py | 32 - tests/contrib/flask_cache/test.py | 39 -- tests/contrib/futures/test_propagation.py | 28 - tests/contrib/gevent/test_tracer.py | 30 - tests/contrib/httplib/test_httplib.py | 32 - tests/contrib/mysql/test_mysql.py | 88 --- tests/contrib/mysqldb/test_mysqldb.py | 84 --- tests/contrib/psycopg/test_psycopg.py | 42 -- tests/contrib/psycopg/test_psycopg_async.py | 42 -- tests/contrib/psycopg2/test_psycopg.py | 42 -- tests/contrib/pylibmc/test.py | 28 - tests/contrib/pymongo/test.py | 62 -- tests/contrib/pymysql/test_pymysql.py | 68 -- tests/contrib/pyramid/utils.py | 31 - tests/contrib/redis/test_redis.py | 49 -- tests/contrib/requests/test_requests.py | 30 - tests/contrib/snowflake/test_snowflake.py | 75 --- tests/contrib/sqlalchemy/mixins.py | 34 - tests/contrib/sqlite3/test_sqlite3.py | 42 -- tests/contrib/suitespec.yml | 9 - tests/contrib/tornado/test_tornado_web.py | 44 -- tests/contrib/urllib3/test_urllib3.py | 29 - tests/contrib/valkey/test_valkey.py | 44 -- tests/contrib/vertica/test_vertica.py | 32 - tests/contrib/yaaredis/test_yaaredis.py | 13 - tests/opentracer/__init__.py | 0 tests/opentracer/conftest.py | 60 -- tests/opentracer/core/__init__.py | 0 .../opentracer/core/test_dd_compatibility.py | 180 ------ tests/opentracer/core/test_span.py | 163 ----- tests/opentracer/core/test_span_context.py | 38 -- tests/opentracer/core/test_tracer.py | 585 ------------------ tests/opentracer/core/test_utils.py | 17 - tests/opentracer/test_tracer_asyncio.py | 143 ----- tests/opentracer/test_tracer_gevent.py | 193 ------ tests/opentracer/test_tracer_tornado.py | 30 - tests/opentracer/utils.py | 11 - tests/suitespec.yml | 2 - tests/telemetry/test_telemetry_metrics_e2e.py | 66 -- tests/tracer/test_correlation_log_context.py | 21 - tests/tracer/test_propagation.py | 16 - 67 files changed, 4 insertions(+), 3905 deletions(-) delete mode 100644 ddtrace/opentracer/__init__.py delete mode 100644 ddtrace/opentracer/helpers.py delete mode 100644 ddtrace/opentracer/propagation/__init__.py delete mode 100644 ddtrace/opentracer/propagation/binary.py delete mode 100644 ddtrace/opentracer/propagation/http.py delete mode 100644 ddtrace/opentracer/propagation/propagator.py delete mode 100644 ddtrace/opentracer/propagation/text.py delete mode 100644 ddtrace/opentracer/settings.py delete mode 100644 ddtrace/opentracer/span.py delete mode 100644 ddtrace/opentracer/span_context.py delete mode 100644 ddtrace/opentracer/tags.py delete mode 100644 ddtrace/opentracer/tracer.py delete mode 100644 ddtrace/opentracer/utils.py create mode 100644 releasenotes/notes/opentracer-remove-b1883d26ea035c50.yaml delete mode 100644 tests/commands/ddtrace_run_app_name.py delete mode 100644 tests/opentracer/__init__.py delete mode 100644 tests/opentracer/conftest.py delete mode 100644 tests/opentracer/core/__init__.py delete mode 100644 tests/opentracer/core/test_dd_compatibility.py delete mode 100644 tests/opentracer/core/test_span.py delete mode 100644 tests/opentracer/core/test_span_context.py delete mode 100644 tests/opentracer/core/test_tracer.py delete mode 100644 tests/opentracer/core/test_utils.py delete mode 100644 tests/opentracer/test_tracer_asyncio.py delete mode 100644 tests/opentracer/test_tracer_gevent.py delete mode 100644 tests/opentracer/test_tracer_tornado.py delete mode 100644 tests/opentracer/utils.py diff --git a/ddtrace/opentracer/__init__.py b/ddtrace/opentracer/__init__.py deleted file mode 100644 index 815cdae0022..00000000000 --- a/ddtrace/opentracer/__init__.py +++ /dev/null @@ -1,18 +0,0 @@ -from ddtrace.vendor.debtcollector import deprecate - -from .helpers import set_global_tracer -from .tracer import Tracer - - -deprecate( - "The `ddtrace.opentracer` package is deprecated", - message="The ddtrace library no longer supports the OpenTracing API. " - "Use the OpenTelemetry API instead (`ddtrace.opentelemetry`).", - removal_version="4.0.0", -) - - -__all__ = [ - "Tracer", - "set_global_tracer", -] diff --git a/ddtrace/opentracer/helpers.py b/ddtrace/opentracer/helpers.py deleted file mode 100644 index e8e6c4896a4..00000000000 --- a/ddtrace/opentracer/helpers.py +++ /dev/null @@ -1,25 +0,0 @@ -from typing import TYPE_CHECKING - -import opentracing - -import ddtrace - - -if TYPE_CHECKING: # pragma: no cover - from ddtrace.opentracer import Tracer # noqa:F401 - - -""" -Helper routines for Datadog OpenTracing. -""" - - -def set_global_tracer(tracer): - # type: (Tracer) -> None - """Sets the global tracers to the given tracer.""" - - # overwrite the opentracer reference - opentracing.tracer = tracer - - # overwrite the Datadog tracer reference - ddtrace.tracer = tracer._dd_tracer diff --git a/ddtrace/opentracer/propagation/__init__.py b/ddtrace/opentracer/propagation/__init__.py deleted file mode 100644 index 04ddde7014d..00000000000 --- a/ddtrace/opentracer/propagation/__init__.py +++ /dev/null @@ -1,6 +0,0 @@ -from .http import HTTPPropagator - - -__all__ = [ - "HTTPPropagator", -] diff --git a/ddtrace/opentracer/propagation/binary.py b/ddtrace/opentracer/propagation/binary.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/ddtrace/opentracer/propagation/http.py b/ddtrace/opentracer/propagation/http.py deleted file mode 100644 index 539f8dc2ebd..00000000000 --- a/ddtrace/opentracer/propagation/http.py +++ /dev/null @@ -1,74 +0,0 @@ -from typing import Dict # noqa:F401 - -from opentracing import InvalidCarrierException - -from ddtrace.propagation.http import HTTPPropagator as DDHTTPPropagator - -from ...internal.logger import get_logger -from ..span_context import SpanContext -from .propagator import Propagator - - -log = get_logger(__name__) - -_HTTP_BAGGAGE_PREFIX = "ot-baggage-" -_HTTP_BAGGAGE_PREFIX_LEN = len(_HTTP_BAGGAGE_PREFIX) - - -class HTTPPropagator(Propagator): - """OpenTracing compatible HTTP_HEADER and TEXT_MAP format propagator. - - `HTTPPropagator` provides compatibility by using existing OpenTracing - compatible methods from the ddtracer along with new logic supporting the - outstanding OpenTracing-defined functionality. - """ - - @staticmethod - def inject(span_context, carrier): - # type: (SpanContext, Dict[str, str]) -> None - """Inject a span context into a carrier. - - *span_context* is injected into the carrier by first using an - :class:`ddtrace.propagation.http.HTTPPropagator` to inject the ddtracer - specific fields. - - Then the baggage is injected into *carrier*. - - :param span_context: span context to inject. - - :param carrier: carrier to inject into. - """ - if not isinstance(carrier, dict): - raise InvalidCarrierException("propagator expects carrier to be a dict") - - DDHTTPPropagator.inject(span_context._dd_context, carrier) - - # Add the baggage - if span_context.baggage is not None: - for key in span_context.baggage: - carrier[_HTTP_BAGGAGE_PREFIX + key] = span_context.baggage[key] - - @staticmethod - def extract(carrier): - # type: (Dict[str, str]) -> SpanContext - """Extract a span context from a carrier. - - :class:`ddtrace.propagation.http.HTTPPropagator` is used to extract - ddtracer supported fields into a `ddtrace.Context` context which is - combined with new logic to extract the baggage which is returned in an - OpenTracing compatible span context. - - :param carrier: carrier to extract from. - - :return: extracted span context. - """ - if not isinstance(carrier, dict): - raise InvalidCarrierException("propagator expects carrier to be a dict") - - ddspan_ctx = DDHTTPPropagator.extract(carrier) - baggage = {} - for key in carrier: - if key.startswith(_HTTP_BAGGAGE_PREFIX): - baggage[key[_HTTP_BAGGAGE_PREFIX_LEN:]] = carrier[key] - - return SpanContext(ddcontext=ddspan_ctx, baggage=baggage) diff --git a/ddtrace/opentracer/propagation/propagator.py b/ddtrace/opentracer/propagation/propagator.py deleted file mode 100644 index 77eadf3912b..00000000000 --- a/ddtrace/opentracer/propagation/propagator.py +++ /dev/null @@ -1,13 +0,0 @@ -import abc - - -class Propagator(metaclass=abc.ABCMeta): - @staticmethod - @abc.abstractmethod - def inject(span_context, carrier): - pass - - @staticmethod - @abc.abstractmethod - def extract(carrier): - pass diff --git a/ddtrace/opentracer/propagation/text.py b/ddtrace/opentracer/propagation/text.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/ddtrace/opentracer/settings.py b/ddtrace/opentracer/settings.py deleted file mode 100644 index 944df88233b..00000000000 --- a/ddtrace/opentracer/settings.py +++ /dev/null @@ -1,41 +0,0 @@ -from collections import namedtuple -from typing import Any # noqa:F401 -from typing import Dict # noqa:F401 -from typing import List # noqa:F401 - - -# Keys used for the configuration dict -ConfigKeyNames = namedtuple( - "ConfigKeyNames", - [ - "AGENT_HOSTNAME", - "AGENT_HTTPS", - "AGENT_PORT", - "DEBUG", - "ENABLED", - "GLOBAL_TAGS", - "SAMPLER", - "PRIORITY_SAMPLING", - "UDS_PATH", - "SETTINGS", - ], -) - -ConfigKeys = ConfigKeyNames( - AGENT_HOSTNAME="agent_hostname", - AGENT_HTTPS="agent_https", - AGENT_PORT="agent_port", - DEBUG="debug", - ENABLED="enabled", - GLOBAL_TAGS="global_tags", - SAMPLER="sampler", - PRIORITY_SAMPLING="priority_sampling", - UDS_PATH="uds_path", - SETTINGS="settings", -) - - -def config_invalid_keys(config): - # type: (Dict[str, Any]) -> List[str] - """Returns a list of keys that exist in *config* and not in KEYS.""" - return [key for key in config.keys() if key not in ConfigKeys] diff --git a/ddtrace/opentracer/span.py b/ddtrace/opentracer/span.py deleted file mode 100644 index 3aea2eda580..00000000000 --- a/ddtrace/opentracer/span.py +++ /dev/null @@ -1,197 +0,0 @@ -import threading -from typing import TYPE_CHECKING # noqa:F401 -from typing import Any # noqa:F401 -from typing import Dict # noqa:F401 -from typing import Optional # noqa:F401 -from typing import Text # noqa:F401 -from typing import Union # noqa:F401 - -from opentracing import Span as OpenTracingSpan -from opentracing.ext import tags as OTTags - -from ddtrace.constants import ERROR_MSG -from ddtrace.constants import ERROR_STACK -from ddtrace.constants import ERROR_TYPE -from ddtrace.internal.compat import NumericType # noqa:F401 -from ddtrace.internal.constants import SPAN_API_OPENTRACING -from ddtrace.trace import Context as DatadogContext # noqa:F401 -from ddtrace.trace import Span as DatadogSpan - -from .span_context import SpanContext -from .tags import Tags - - -if TYPE_CHECKING: # pragma: no cover - from ddtrace.trace import Tracer # noqa:F401 - - -_TagNameType = Union[Text, bytes] - - -class Span(OpenTracingSpan): - """Datadog implementation of :class:`opentracing.Span`""" - - def __init__(self, tracer, context, operation_name): - # type: (Tracer, Optional[SpanContext], str) -> None - if context is not None: - context = SpanContext(ddcontext=context._dd_context, baggage=context.baggage) - else: - context = SpanContext() - - super(Span, self).__init__(tracer, context) - - self.finished = False - self._lock = threading.Lock() - # use a datadog span - self._dd_span = DatadogSpan(operation_name, context=context._dd_context, span_api=SPAN_API_OPENTRACING) - - def finish(self, finish_time=None): - # type: (Optional[float]) -> None - """Finish the span. - - This calls finish on the ddspan. - - :param finish_time: specify a custom finish time with a unix timestamp - per time.time() - :type timestamp: float - """ - if self.finished: - return - - # finish the datadog span - self._dd_span.finish(finish_time) - self.finished = True - - def set_baggage_item(self, key, value): - # type: (str, Any) -> Span - """Sets a baggage item in the span context of this span. - - Baggage is used to propagate state between spans. - - :param key: baggage item key - :type key: str - - :param value: baggage item value - :type value: a type that can be str'd - - :rtype: Span - :return: itself for chaining calls - """ - new_ctx = self.context.with_baggage_item(key, value) - with self._lock: - self._context = new_ctx - return self - - def get_baggage_item(self, key): - # type: (str) -> Optional[str] - """Gets a baggage item from the span context of this span. - - :param key: baggage item key - :type key: str - - :rtype: str - :return: the baggage value for the given key or ``None``. - """ - return self.context.get_baggage_item(key) - - def set_operation_name(self, operation_name): - # type: (str) -> Span - """Set the operation name.""" - self._dd_span.name = operation_name - return self - - def log_kv(self, key_values, timestamp=None): - # type: (Dict[_TagNameType, Any], Optional[float]) -> Span - """Add a log record to this span. - - Passes on relevant opentracing key values onto the datadog span. - - :param key_values: a dict of string keys and values of any type - :type key_values: dict - - :param timestamp: a unix timestamp per time.time() - :type timestamp: float - - :return: the span itself, for call chaining - :rtype: Span - """ - - # match opentracing defined keys to datadog functionality - # opentracing/specification/blob/1be630515dafd4d2a468d083300900f89f28e24d/semantic_conventions.md#log-fields-table # noqa: E501 - for key, val in key_values.items(): - if key == "event" and val == "error": - # TODO: not sure if it's actually necessary to set the error manually - self._dd_span.error = 1 - self.set_tag("error", 1) - elif key == "error" or key == "error.object": - self.set_tag(ERROR_TYPE, val) - elif key == "message": - self.set_tag(ERROR_MSG, val) - elif key == "stack": - self.set_tag(ERROR_STACK, val) - else: - pass - - return self - - def set_tag(self, key, value): - # type: (_TagNameType, Any) -> Span - """Set a tag on the span. - - This sets the tag on the underlying datadog span. - """ - if key == Tags.SPAN_TYPE: - self._dd_span.span_type = value - elif key == Tags.SERVICE_NAME: - self._dd_span.service = value - elif key == Tags.RESOURCE_NAME or key == OTTags.DATABASE_STATEMENT: - self._dd_span.resource = value - elif key == OTTags.PEER_HOSTNAME: - self._dd_span._set_tag_str(Tags.TARGET_HOST, value) - elif key == OTTags.PEER_PORT: - self._dd_span.set_tag(Tags.TARGET_PORT, value) - elif key == Tags.SAMPLING_PRIORITY: - self._dd_span.context.sampling_priority = value - else: - self._dd_span.set_tag(key, value) - return self - - def _get_tag(self, key): - # type: (_TagNameType) -> Optional[Text] - """Gets a tag from the span. - - This method retrieves the tag from the underlying datadog span. - """ - return self._dd_span.get_tag(key) - - def _get_metric(self, key): - # type: (_TagNameType) -> Optional[NumericType] - """Gets a metric from the span. - - This method retrieves the metric from the underlying datadog span. - """ - return self._dd_span.get_metric(key) - - def __enter__(self): - return self - - def __exit__(self, exc_type, exc_val, exc_tb): - if exc_type: - self._dd_span.set_exc_info(exc_type, exc_val, exc_tb) - - # note: self.finish() AND _dd_span.__exit__ will call _span.finish() but - # it is idempotent - self._dd_span.__exit__(exc_type, exc_val, exc_tb) - self.finish() - - def _associate_dd_span(self, ddspan): - # type: (DatadogSpan) -> None - """Associates a DD span with this span.""" - # get the datadog span context - self._dd_span = ddspan - self.context._dd_context = ddspan.context - - @property - def _dd_context(self): - # type: () -> DatadogContext - return self._dd_span.context diff --git a/ddtrace/opentracer/span_context.py b/ddtrace/opentracer/span_context.py deleted file mode 100644 index 171142d18a8..00000000000 --- a/ddtrace/opentracer/span_context.py +++ /dev/null @@ -1,66 +0,0 @@ -from typing import Any # noqa:F401 -from typing import Dict # noqa:F401 -from typing import Optional # noqa:F401 - -from opentracing import SpanContext as OpenTracingSpanContext - -from ddtrace.internal.compat import NumericType # noqa:F401 -from ddtrace.trace import Context as DatadogContext - - -class SpanContext(OpenTracingSpanContext): - """Implementation of the OpenTracing span context.""" - - def __init__( - self, - trace_id=None, # type: Optional[int] - span_id=None, # type: Optional[int] - sampling_priority=None, # type: Optional[NumericType] - baggage=None, # type: Optional[Dict[str, Any]] - ddcontext=None, # type: Optional[DatadogContext] - ): - # type: (...) -> None - # create a new dict for the baggage if it is not provided - # NOTE: it would be preferable to use opentracing.SpanContext.EMPTY_BAGGAGE - # but it is mutable. - # see: opentracing-python/blob/8775c7bfc57fd66e1c8bcf9a54d3e434d37544f9/opentracing/span.py#L30 - baggage = baggage or {} - - if ddcontext is not None: - self._dd_context = ddcontext - else: - self._dd_context = DatadogContext( - trace_id=trace_id, - span_id=span_id, - sampling_priority=sampling_priority, - ) - - self._baggage = dict(baggage) - - @property - def baggage(self): - # type: () -> Dict[str, Any] - return self._baggage - - def set_baggage_item(self, key, value): - # type: (str, Any) -> None - """Sets a baggage item in this span context. - - Note that this operation mutates the baggage of this span context - """ - self.baggage[key] = value - - def with_baggage_item(self, key, value): - # type: (str, Any) -> SpanContext - """Returns a copy of this span with a new baggage item. - - Useful for instantiating new child span contexts. - """ - baggage = dict(self._baggage) - baggage[key] = value - return SpanContext(ddcontext=self._dd_context, baggage=baggage) - - def get_baggage_item(self, key): - # type: (str) -> Optional[Any] - """Gets a baggage item in this span context.""" - return self.baggage.get(key, None) diff --git a/ddtrace/opentracer/tags.py b/ddtrace/opentracer/tags.py deleted file mode 100644 index ebc2d86d146..00000000000 --- a/ddtrace/opentracer/tags.py +++ /dev/null @@ -1,23 +0,0 @@ -from collections import namedtuple - - -TagNames = namedtuple( - "TagNames", - [ - "RESOURCE_NAME", - "SAMPLING_PRIORITY", - "SERVICE_NAME", - "SPAN_TYPE", - "TARGET_HOST", - "TARGET_PORT", - ], -) - -Tags = TagNames( - RESOURCE_NAME="resource.name", - SAMPLING_PRIORITY="sampling.priority", - SERVICE_NAME="service.name", - TARGET_HOST="out.host", - TARGET_PORT="network.destination.port", - SPAN_TYPE="span.type", -) diff --git a/ddtrace/opentracer/tracer.py b/ddtrace/opentracer/tracer.py deleted file mode 100644 index a783d3263dc..00000000000 --- a/ddtrace/opentracer/tracer.py +++ /dev/null @@ -1,399 +0,0 @@ -from typing import Any # noqa:F401 -from typing import Dict # noqa:F401 -from typing import List # noqa:F401 -from typing import Optional # noqa:F401 -from typing import Union # noqa:F401 -from urllib.parse import urlparse - -import opentracing -from opentracing import Format -from opentracing import Scope # noqa:F401 -from opentracing import ScopeManager # noqa:F401 -from opentracing.scope_managers import ThreadLocalScopeManager - -import ddtrace -from ddtrace import config as ddconfig -from ddtrace.internal.constants import SPAN_API_OPENTRACING -from ddtrace.internal.utils.config import get_application_name -from ddtrace.internal.writer import AgentWriterInterface -from ddtrace.settings.exceptions import ConfigException -from ddtrace.trace import Context as DatadogContext # noqa:F401 -from ddtrace.trace import Span as DatadogSpan -from ddtrace.trace import Tracer as DatadogTracer - -from ..internal.logger import get_logger -from .propagation import HTTPPropagator -from .settings import ConfigKeys as keys -from .settings import config_invalid_keys -from .span import Span -from .span_context import SpanContext -from .utils import get_context_provider_for_scope_manager - - -log = get_logger(__name__) - -DEFAULT_CONFIG: Dict[str, Optional[Any]] = { - keys.AGENT_HOSTNAME: None, - keys.AGENT_HTTPS: None, - keys.AGENT_PORT: None, - keys.DEBUG: False, - keys.ENABLED: None, - keys.GLOBAL_TAGS: {}, - keys.SAMPLER: None, - # Not used, priority sampling can not be disabled in +v3.0 - keys.PRIORITY_SAMPLING: None, - keys.UDS_PATH: None, - keys.SETTINGS: { - "FILTERS": [], - }, -} - - -class Tracer(opentracing.Tracer): - """A wrapper providing an OpenTracing API for the Datadog tracer.""" - - def __init__( - self, - service_name: Optional[str] = None, - config: Optional[Dict[str, Any]] = None, - scope_manager: Optional[ScopeManager] = None, - _dd_tracer: Optional[DatadogTracer] = None, - ) -> None: - """Initialize a new Datadog opentracer. - - :param service_name: (optional) the name of the service that this - tracer will be used with. Note if not provided, a service name will - try to be determined based off of ``sys.argv``. If this fails a - :class:`ddtrace.settings.ConfigException` will be raised. - :param config: (optional) a configuration object to specify additional - options. See the documentation for further information. - :param scope_manager: (optional) the scope manager for this tracer to - use. The available managers are listed in the Python OpenTracing repo - here: https://github.com/opentracing/opentracing-python#scope-managers. - If ``None`` is provided, defaults to - :class:`opentracing.scope_managers.ThreadLocalScopeManager`. - """ - # Merge the given config with the default into a new dict - self._config = DEFAULT_CONFIG.copy() - if config is not None: - self._config.update(config) - # Pull out commonly used properties for performance - self._service_name = service_name or get_application_name() - self._debug = self._config.get(keys.DEBUG) - - if self._debug and ddconfig._raise: - # Ensure there are no typos in any of the keys - invalid_keys = config_invalid_keys(self._config) - if invalid_keys: - str_invalid_keys = ",".join(invalid_keys) - raise ConfigException("invalid key(s) given ({})".format(str_invalid_keys)) - - if not self._service_name and ddconfig._raise: - raise ConfigException( - """ Cannot detect the \'service_name\'. - Please set the \'service_name=\' - keyword argument. - """ - ) - - self._scope_manager = scope_manager or ThreadLocalScopeManager() - self._dd_tracer = _dd_tracer or ddtrace.tracer - self._dd_tracer.context_provider = get_context_provider_for_scope_manager(self._scope_manager) - - self._dd_tracer.set_tags(self._config.get(keys.GLOBAL_TAGS)) # type: ignore[arg-type] - trace_processors = None - if isinstance(self._config.get(keys.SETTINGS), dict) and self._config[keys.SETTINGS].get("FILTERS"): # type: ignore[union-attr] - trace_processors = self._config[keys.SETTINGS]["FILTERS"] # type: ignore[index] - self._dd_tracer._span_aggregator.user_processors = trace_processors - - if self._config[keys.ENABLED]: - self._dd_tracer.enabled = self._config[keys.ENABLED] - - if ( - self._config[keys.AGENT_HOSTNAME] - or self._config[keys.AGENT_HTTPS] - or self._config[keys.AGENT_PORT] - or self._config[keys.UDS_PATH] - ): - scheme = "https" if self._config[keys.AGENT_HTTPS] else "http" - hostname = self._config[keys.AGENT_HOSTNAME] - port = self._config[keys.AGENT_PORT] - if self._dd_tracer._agent_url: - curr_agent_url = urlparse(self._dd_tracer._agent_url) - scheme = "https" if self._config[keys.AGENT_HTTPS] else curr_agent_url.scheme - hostname = hostname or curr_agent_url.hostname - port = port or curr_agent_url.port - uds_path = self._config[keys.UDS_PATH] - - if uds_path: - new_url = f"unix://{uds_path}" - else: - new_url = f"{scheme}://{hostname}:{port}" - if isinstance(self._dd_tracer._span_aggregator.writer, AgentWriterInterface): - self._dd_tracer._span_aggregator.writer.intake_url = new_url - self._dd_tracer._recreate() - - if self._config[keys.SAMPLER]: - self._dd_tracer._sampler = self._config[keys.SAMPLER] - - self._propagators = { - Format.HTTP_HEADERS: HTTPPropagator, - Format.TEXT_MAP: HTTPPropagator, - } - - @property - def scope_manager(self): - # type: () -> ScopeManager - """Returns the scope manager being used by this tracer.""" - return self._scope_manager - - def start_active_span( - self, - operation_name, # type: str - child_of=None, # type: Optional[Union[Span, SpanContext]] - references=None, # type: Optional[List[Any]] - tags=None, # type: Optional[Dict[str, str]] - start_time=None, # type: Optional[int] - ignore_active_span=False, # type: bool - finish_on_close=True, # type: bool - ): - # type: (...) -> Scope - """Returns a newly started and activated `Scope`. - The returned `Scope` supports with-statement contexts. For example:: - - with tracer.start_active_span('...') as scope: - scope.span.set_tag('http.method', 'GET') - do_some_work() - # Span.finish() is called as part of Scope deactivation through - # the with statement. - - It's also possible to not finish the `Span` when the `Scope` context - expires:: - - with tracer.start_active_span('...', - finish_on_close=False) as scope: - scope.span.set_tag('http.method', 'GET') - do_some_work() - # Span.finish() is not called as part of Scope deactivation as - # `finish_on_close` is `False`. - - :param operation_name: name of the operation represented by the new - span from the perspective of the current service. - :param child_of: (optional) a Span or SpanContext instance representing - the parent in a REFERENCE_CHILD_OF Reference. If specified, the - `references` parameter must be omitted. - :param references: (optional) a list of Reference objects that identify - one or more parent SpanContexts. (See the Reference documentation - for detail). - :param tags: an optional dictionary of Span Tags. The caller gives up - ownership of that dictionary, because the Tracer may use it as-is - to avoid extra data copying. - :param start_time: an explicit Span start time as a unix timestamp per - time.time(). - :param ignore_active_span: (optional) an explicit flag that ignores - the current active `Scope` and creates a root `Span`. - :param finish_on_close: whether span should automatically be finished - when `Scope.close()` is called. - :return: a `Scope`, already registered via the `ScopeManager`. - """ - otspan = self.start_span( - operation_name=operation_name, - child_of=child_of, - references=references, - tags=tags, - start_time=start_time, - ignore_active_span=ignore_active_span, - ) - - # activate this new span - scope = self._scope_manager.activate(otspan, finish_on_close) - self._dd_tracer.context_provider.activate(otspan._dd_span) - return scope - - def start_span( - self, - operation_name: Optional[str] = None, - child_of: Optional[Union[Span, SpanContext]] = None, - references: Optional[List[Any]] = None, - tags: Optional[Dict[str, str]] = None, - start_time: Optional[int] = None, - ignore_active_span: bool = False, - ) -> Span: - """Starts and returns a new Span representing a unit of work. - - Starting a root Span (a Span with no causal references):: - - tracer.start_span('...') - - Starting a child Span (see also start_child_span()):: - - tracer.start_span( - '...', - child_of=parent_span) - - Starting a child Span in a more verbose way:: - - tracer.start_span( - '...', - references=[opentracing.child_of(parent_span)]) - - Note: the precedence when defining a relationship is the following, from highest to lowest: - 1. *child_of* - 2. *references* - 3. `scope_manager.active` (unless *ignore_active_span* is True) - 4. None - - Currently Datadog only supports `child_of` references. - - :param operation_name: name of the operation represented by the new - span from the perspective of the current service. - :param child_of: (optional) a Span or SpanContext instance representing - the parent in a REFERENCE_CHILD_OF Reference. If specified, the - `references` parameter must be omitted. - :param references: (optional) a list of Reference objects that identify - one or more parent SpanContexts. (See the Reference documentation - for detail) - :param tags: an optional dictionary of Span Tags. The caller gives up - ownership of that dictionary, because the Tracer may use it as-is - to avoid extra data copying. - :param start_time: an explicit Span start time as a unix timestamp per - time.time() - :param ignore_active_span: an explicit flag that ignores the current - active `Scope` and creates a root `Span`. - :return: an already-started Span instance. - """ - ot_parent = None # 'ot_parent' is more readable than 'child_of' - ot_parent_context = None # the parent span's context - # dd_parent: the child_of to pass to the ddtracer - dd_parent = None # type: Optional[Union[DatadogSpan, DatadogContext]] - - if child_of is not None: - ot_parent = child_of # 'ot_parent' is more readable than 'child_of' - elif references and isinstance(references, list): - # we currently only support child_of relations to one span - ot_parent = references[0].referenced_context - - # - whenever child_of is not None ddspans with parent-child - # relationships will share a ddcontext which maintains a hierarchy of - # ddspans for the execution flow - # - when child_of is a ddspan then the ddtracer uses this ddspan to - # create the child ddspan - # - when child_of is a ddcontext then the ddtracer uses the ddcontext to - # get_current_span() for the parent - if ot_parent is None and not ignore_active_span: - # attempt to get the parent span from the scope manager - scope = self._scope_manager.active - parent_span = getattr(scope, "span", None) - ot_parent_context = getattr(parent_span, "context", None) - - # Compare the active ot and dd spans. Using the one which - # was created later as the parent. - active_dd_parent = self._dd_tracer.context_provider.active() - if parent_span and isinstance(active_dd_parent, DatadogSpan): - dd_parent_span = parent_span._dd_span - if active_dd_parent.start_ns >= dd_parent_span.start_ns: - dd_parent = active_dd_parent - else: - dd_parent = dd_parent_span - else: - dd_parent = active_dd_parent - elif ot_parent is not None and isinstance(ot_parent, Span): - # a span is given to use as a parent - ot_parent_context = ot_parent.context - dd_parent = ot_parent._dd_span - elif ot_parent is not None and isinstance(ot_parent, SpanContext): - # a span context is given to use to find the parent ddspan - dd_parent = ot_parent._dd_context - elif ot_parent is None: - # user wants to create a new parent span we don't have to do - # anything - pass - elif ddconfig._raise: - raise TypeError("invalid span configuration given") - - # create a new otspan and ddspan using the ddtracer and associate it - # with the new otspan - ddspan = self._dd_tracer.start_span( - name=operation_name, # type: ignore[arg-type] - child_of=dd_parent, - service=self._service_name, - activate=False, - span_api=SPAN_API_OPENTRACING, - ) - - # set the start time if one is specified - ddspan.start = start_time or ddspan.start - - otspan = Span(self, ot_parent_context, operation_name) # type: ignore[arg-type] - # sync up the OT span with the DD span - otspan._associate_dd_span(ddspan) - - if tags is not None: - for k in tags: - # Make sure we set the tags on the otspan to ensure that the special compatibility tags - # are handled correctly (resource name, span type, sampling priority, etc). - otspan.set_tag(k, tags[k]) - - return otspan - - @property - def active_span(self): - # type: () -> Optional[Span] - """Retrieves the active span from the opentracing scope manager - - Falls back to using the datadog active span if one is not found. This - allows opentracing users to use datadog instrumentation. - """ - scope = self._scope_manager.active - if scope: - return scope.span - else: - dd_span = self._dd_tracer.current_span() - ot_span = None # type: Optional[Span] - if dd_span: - ot_span = Span(self, None, dd_span.name) - ot_span._associate_dd_span(dd_span) - return ot_span - - def inject(self, span_context, format, carrier): # noqa: A002 - # type: (SpanContext, str, Dict[str, str]) -> None - """Injects a span context into a carrier. - - :param span_context: span context to inject. - :param format: format to encode the span context with. - :param carrier: the carrier of the encoded span context. - """ - propagator = self._propagators.get(format, None) - - if propagator is None: - raise opentracing.UnsupportedFormatException - - propagator.inject(span_context, carrier) - - def extract(self, format, carrier): # noqa: A002 - # type: (str, Dict[str, str]) -> SpanContext - """Extracts a span context from a carrier. - - :param format: format that the carrier is encoded with. - :param carrier: the carrier to extract from. - """ - propagator = self._propagators.get(format, None) - - if propagator is None: - raise opentracing.UnsupportedFormatException - - # we have to manually activate the returned context from a distributed - # trace - ot_span_ctx = propagator.extract(carrier) - dd_span_ctx = ot_span_ctx._dd_context - self._dd_tracer.context_provider.activate(dd_span_ctx) - return ot_span_ctx - - def get_log_correlation_context(self): - # type: () -> Dict[str, str] - """Retrieves the data used to correlate a log with the current active trace. - Generates a dictionary for custom logging instrumentation including the trace id and - span id of the current active span, as well as the configured service, version, and environment names. - If there is no active span, a dictionary with an empty string for each value will be returned. - """ - return self._dd_tracer.get_log_correlation_context() diff --git a/ddtrace/opentracer/utils.py b/ddtrace/opentracer/utils.py deleted file mode 100644 index 886e998d8a3..00000000000 --- a/ddtrace/opentracer/utils.py +++ /dev/null @@ -1,43 +0,0 @@ -from opentracing import ScopeManager # noqa:F401 - -from ddtrace._trace.provider import BaseContextProvider -from ddtrace._trace.provider import DefaultContextProvider - - -# DEV: If `asyncio` or `gevent` are unavailable we do not throw an error, -# `context_provider` will just not be set and we'll get an `AttributeError` instead - - -def get_context_provider_for_scope_manager(scope_manager: ScopeManager) -> BaseContextProvider: - """Returns the context_provider to use with a given scope_manager.""" - - dd_context_provider = DefaultContextProvider() - _patch_scope_manager(scope_manager, dd_context_provider) - - return dd_context_provider - - -def _patch_scope_manager(scope_manager: ScopeManager, context_provider: BaseContextProvider) -> None: - """ - Patches a scope manager so that any time a span is activated - it'll also activate the underlying ddcontext with the underlying - datadog context provider. - - This allows opentracing users to rely on ddtrace.contrib patches and - have them parent correctly. - - :param scope_manager: Something that implements `opentracing.ScopeManager` - :param context_provider: Something that implements `datadog.provider.BaseContextProvider` - """ - if getattr(scope_manager, "_datadog_patch", False): - return - scope_manager._datadog_patch = True - - old_method = scope_manager.activate - - def _patched_activate(*args, **kwargs): - otspan = kwargs.get("span", args[0]) - context_provider.activate(otspan._dd_context) - return old_method(*args, **kwargs) - - scope_manager.activate = _patched_activate diff --git a/releasenotes/notes/opentracer-remove-b1883d26ea035c50.yaml b/releasenotes/notes/opentracer-remove-b1883d26ea035c50.yaml new file mode 100644 index 00000000000..6d248930d9c --- /dev/null +++ b/releasenotes/notes/opentracer-remove-b1883d26ea035c50.yaml @@ -0,0 +1,4 @@ +--- +upgrade: + - | + opentracer: This change removes the deprecated ``opentracer`` package diff --git a/tests/commands/ddtrace_run_app_name.py b/tests/commands/ddtrace_run_app_name.py deleted file mode 100644 index 4cf41192e79..00000000000 --- a/tests/commands/ddtrace_run_app_name.py +++ /dev/null @@ -1,6 +0,0 @@ -from ddtrace.opentracer import Tracer - - -if __name__ == "__main__": - tracer = Tracer() - print(tracer._service_name) diff --git a/tests/commands/test_runner.py b/tests/commands/test_runner.py index 967db4a7f5e..4b29dff8ea3 100644 --- a/tests/commands/test_runner.py +++ b/tests/commands/test_runner.py @@ -197,13 +197,6 @@ def test_argv_passed(self): out = subprocess.check_output(["ddtrace-run", "python", "tests/commands/ddtrace_run_argv.py", "foo", "bar"]) assert out.startswith(b"Test success") - def test_got_app_name(self): - """ - apps run with ddtrace-run have a proper app name - """ - out = subprocess.check_output(["ddtrace-run", "python", "tests/commands/ddtrace_run_app_name.py"]) - assert out.startswith(b"ddtrace_run_app_name.py") - def test_global_trace_tags(self): """Ensure global tags are passed in from environment""" with self.override_env(dict(DD_TRACE_GLOBAL_TAGS="a:True,b:0,c:C")): diff --git a/tests/contrib/aiobotocore/test.py b/tests/contrib/aiobotocore/test.py index 5e7151797b0..0fdf25414e8 100644 --- a/tests/contrib/aiobotocore/test.py +++ b/tests/contrib/aiobotocore/test.py @@ -303,92 +303,6 @@ async def test_double_patch(tracer): assert len(traces[0]) == 1 -@pytest.mark.asyncio -async def test_opentraced_client(tracer): - from tests.opentracer.utils import init_tracer - - ot_tracer = init_tracer("my_svc", tracer) - - with ot_tracer.start_active_span("ot_outer_span"): - async with aiobotocore_client("ec2", tracer) as ec2: - await ec2.describe_instances() - - traces = tracer.pop_traces() - assert len(traces) == 1 - assert len(traces[0]) == 2 - ot_span = traces[0][0] - dd_span = traces[0][1] - - assert ot_span.resource == "ot_outer_span" - assert ot_span.service == "my_svc" - - # confirm the parenting - assert ot_span.parent_id is None - assert dd_span.parent_id == ot_span.span_id - - assert_is_measured(dd_span) - assert dd_span.get_tag("aws.agent") == "aiobotocore" - assert dd_span.get_tag("aws.region") == "us-west-2" - assert dd_span.get_tag("region") == "us-west-2" - assert dd_span.get_tag("aws.operation") == "DescribeInstances" - assert_span_http_status_code(dd_span, 200) - assert dd_span.get_metric("retry_attempts") == 0 - assert dd_span.service == "aws.ec2" - assert dd_span.resource == "ec2.describeinstances" - assert dd_span.name == "ec2.command" - assert dd_span.get_tag("component") == "aiobotocore" - assert dd_span.get_tag("span.kind") == "client" - - -@pytest.mark.asyncio -async def test_opentraced_s3_client(tracer): - from tests.opentracer.utils import init_tracer - - ot_tracer = init_tracer("my_svc", tracer) - - with ot_tracer.start_active_span("ot_outer_span"): - async with aiobotocore_client("s3", tracer) as s3: - await s3.list_buckets() - with ot_tracer.start_active_span("ot_inner_span1"): - await s3.list_buckets() - with ot_tracer.start_active_span("ot_inner_span2"): - pass - - traces = tracer.pop_traces() - assert len(traces) == 1 - assert len(traces[0]) == 5 - ot_outer_span = traces[0][0] - dd_span = traces[0][1] - ot_inner_span = traces[0][2] - dd_span2 = traces[0][3] - ot_inner_span2 = traces[0][4] - - assert ot_outer_span.resource == "ot_outer_span" - assert ot_inner_span.resource == "ot_inner_span1" - assert ot_inner_span2.resource == "ot_inner_span2" - - # confirm the parenting - assert ot_outer_span.parent_id is None - assert dd_span.parent_id == ot_outer_span.span_id - assert ot_inner_span.parent_id == ot_outer_span.span_id - assert dd_span2.parent_id == ot_inner_span.span_id - assert ot_inner_span2.parent_id == ot_outer_span.span_id - - assert_is_measured(dd_span) - assert dd_span.get_tag("aws.operation") == "ListBuckets" - assert_span_http_status_code(dd_span, 200) - assert dd_span.service == "aws.s3" - assert dd_span.resource == "s3.listbuckets" - assert dd_span.name == "s3.command" - - assert dd_span2.get_tag("aws.operation") == "ListBuckets" - assert_span_http_status_code(dd_span2, 200) - assert dd_span2.service == "aws.s3" - assert dd_span2.resource == "s3.listbuckets" - assert dd_span2.name == "s3.command" - assert dd_span.get_tag("component") == "aiobotocore" - - @pytest.mark.asyncio async def test_user_specified_service(tracer): """ diff --git a/tests/contrib/aiohttp/test_middleware.py b/tests/contrib/aiohttp/test_middleware.py index 37e6ea2e3de..e067c197685 100644 --- a/tests/contrib/aiohttp/test_middleware.py +++ b/tests/contrib/aiohttp/test_middleware.py @@ -1,6 +1,5 @@ import os -from opentracing.scope_managers.asyncio import AsyncioScopeManager import pytest import pytest_asyncio @@ -14,7 +13,6 @@ from ddtrace.contrib.internal.aiohttp.middlewares import trace_middleware from ddtrace.ext import http from ddtrace.internal.utils.version import parse_version -from tests.opentracer.utils import init_tracer from tests.tracer.utils_inferred_spans.test_helpers import assert_web_and_inferred_aws_api_gateway_span_data from tests.utils import assert_span_http_status_code from tests.utils import override_global_config @@ -545,22 +543,6 @@ async def test_parenting_200_dd(app_tracer, aiohttp_client): _assert_200_parenting(client, traces) -async def test_parenting_200_ot(app_tracer, aiohttp_client): - """OpenTracing version of test_handler.""" - app, tracer = app_tracer - client = await aiohttp_client(app) - ot_tracer = init_tracer("aiohttp_svc", tracer, scope_manager=AsyncioScopeManager()) - - with ot_tracer.start_active_span("aiohttp_op"): - request = await client.request("GET", "/") - assert 200 == request.status - text = await request.text() - - assert "What's tracing?" == text - traces = tracer.pop_traces() - _assert_200_parenting(client, traces) - - @pytest.mark.parametrize( "test_app", [ diff --git a/tests/contrib/aiopg/test.py b/tests/contrib/aiopg/test.py index b60e5989dda..63f2b89a379 100644 --- a/tests/contrib/aiopg/test.py +++ b/tests/contrib/aiopg/test.py @@ -11,7 +11,6 @@ from ddtrace.internal.schema import DEFAULT_SPAN_SERVICE_NAME from tests.contrib.asyncio.utils import AsyncioTestCase from tests.contrib.config import POSTGRES_CONFIG -from tests.opentracer.utils import init_tracer from tests.subprocesstest import run_in_subprocess from tests.utils import assert_is_measured @@ -75,29 +74,6 @@ async def assert_conn_is_traced(self, tracer, db, service): assert span.get_tag("component") == "aiopg" assert span.get_tag("span.kind") == "client" - # Ensure OpenTracing compatibility - ot_tracer = init_tracer("aiopg_svc", tracer) - with ot_tracer.start_active_span("aiopg_op"): - cursor = await db.cursor() - await cursor.execute(q) - rows = await cursor.fetchall() - assert rows == [("foobarblah",)] - spans = self.pop_spans() - assert len(spans) == 2 - ot_span, dd_span = spans - # confirm the parenting - assert ot_span.parent_id is None - assert dd_span.parent_id == ot_span.span_id - assert ot_span.name == "aiopg_op" - assert ot_span.service == "aiopg_svc" - assert dd_span.name == "postgres.query" - assert dd_span.resource == q - assert dd_span.service == service - assert dd_span.error == 0 - assert dd_span.span_type == "sql" - assert dd_span.get_tag("component") == "aiopg" - assert span.get_tag("span.kind") == "client" - # run a query with an error and ensure all is well q = "select * from some_non_existant_table" cur = await db.cursor() diff --git a/tests/contrib/aredis/test_aredis.py b/tests/contrib/aredis/test_aredis.py index baa8b7f6c30..a40415e4c06 100644 --- a/tests/contrib/aredis/test_aredis.py +++ b/tests/contrib/aredis/test_aredis.py @@ -9,7 +9,6 @@ from ddtrace.contrib.internal.aredis.patch import patch from ddtrace.contrib.internal.aredis.patch import unpatch from tests.conftest import DEFAULT_DDTRACE_SUBPROCESS_TEST_SERVICE_NAME -from tests.opentracer.utils import init_tracer from tests.utils import override_config from ..config import REDIS_CONFIG @@ -185,19 +184,6 @@ async def test(tracer, test_spans): assert err == b"", err.decode() -@pytest.mark.asyncio -async def test_opentracing(tracer, snapshot_context): - """Ensure OpenTracing works with redis.""" - - with snapshot_context(): - r = aredis.StrictRedis(port=REDIS_CONFIG["port"]) - pin = Pin.get_from(r) - ot_tracer = init_tracer("redis_svc", pin.tracer) - - with ot_tracer.start_active_span("redis_get"): - await r.get("cheese") - - @pytest.mark.subprocess(ddtrace_run=True, env=dict(DD_REDIS_RESOURCE_ONLY_COMMAND="false")) @pytest.mark.snapshot def test_full_command_in_resource_env(): diff --git a/tests/contrib/asyncio/test_propagation.py b/tests/contrib/asyncio/test_propagation.py index fd962e544ea..fc976d59ea8 100644 --- a/tests/contrib/asyncio/test_propagation.py +++ b/tests/contrib/asyncio/test_propagation.py @@ -7,7 +7,6 @@ from ddtrace.contrib.internal.asyncio.patch import patch from ddtrace.contrib.internal.asyncio.patch import unpatch from ddtrace.trace import Context -from tests.opentracer.utils import init_tracer _orig_create_task = asyncio.BaseEventLoop.create_task @@ -115,59 +114,3 @@ async def test_propagation_with_new_context(tracer): span = traces[0][0] assert span.trace_id == 100 assert span.parent_id == 101 - - -@pytest.mark.asyncio -async def test_trace_multiple_coroutines_ot_outer(tracer): - """OpenTracing version of test_trace_multiple_coroutines.""" - - # if multiple coroutines have nested tracing, they must belong - # to the same trace - async def coro(): - # another traced coroutine - with tracer.trace("coroutine_2"): - return 42 - - ot_tracer = init_tracer("asyncio_svc", tracer) - with ot_tracer.start_active_span("coroutine_1"): - value = await coro() - - # the coroutine has been called correctly - assert 42 == value - # a single trace has been properly reported - traces = tracer.pop_traces() - assert 1 == len(traces) - assert 2 == len(traces[0]) - assert "coroutine_1" == traces[0][0].name - assert "coroutine_2" == traces[0][1].name - # the parenting is correct - assert traces[0][0] == traces[0][1]._parent - assert traces[0][0].trace_id == traces[0][1].trace_id - - -@pytest.mark.asyncio -async def test_trace_multiple_coroutines_ot_inner(tracer): - """OpenTracing version of test_trace_multiple_coroutines.""" - # if multiple coroutines have nested tracing, they must belong - # to the same trace - ot_tracer = init_tracer("asyncio_svc", tracer) - - async def coro(): - # another traced coroutine - with ot_tracer.start_active_span("coroutine_2"): - return 42 - - with tracer.trace("coroutine_1"): - value = await coro() - - # the coroutine has been called correctly - assert 42 == value - # a single trace has been properly reported - traces = tracer.pop_traces() - assert 1 == len(traces) - assert 2 == len(traces[0]) - assert "coroutine_1" == traces[0][0].name - assert "coroutine_2" == traces[0][1].name - # the parenting is correct - assert traces[0][0] == traces[0][1]._parent - assert traces[0][0].trace_id == traces[0][1].trace_id diff --git a/tests/contrib/boto/test.py b/tests/contrib/boto/test.py index 91c626e6cbc..76dd974692a 100644 --- a/tests/contrib/boto/test.py +++ b/tests/contrib/boto/test.py @@ -20,7 +20,6 @@ from ddtrace.contrib.internal.boto.patch import unpatch from ddtrace.ext import http from ddtrace.internal.schema import DEFAULT_SPAN_SERVICE_NAME -from tests.opentracer.utils import init_tracer from tests.utils import TracerTestCase from tests.utils import assert_is_measured from tests.utils import assert_span_http_status_code @@ -759,56 +758,3 @@ def test_elasticache_client(self): self.assertEqual(span.get_tag("span.kind"), "client") self.assertEqual(span.service, "test-boto-tracing.elasticache") self.assertEqual(span.resource, "elasticache") - - @mock_ec2 - def test_ec2_client_ot(self): - """OpenTracing compatibility check of the test_ec2_client test.""" - ec2 = boto.ec2.connect_to_region("us-west-2") - ot_tracer = init_tracer("my_svc", self.tracer) - pin = Pin(service=self.TEST_SERVICE) - pin._tracer = self.tracer - pin.onto(ec2) - - with ot_tracer.start_active_span("ot_span"): - ec2.get_all_instances() - spans = self.pop_spans() - assert spans - self.assertEqual(len(spans), 2) - ot_span, dd_span = spans - - # confirm the parenting - self.assertIsNone(ot_span.parent_id) - self.assertEqual(dd_span.parent_id, ot_span.span_id) - - self.assertEqual(ot_span.resource, "ot_span") - self.assertEqual(dd_span.get_tag("aws.operation"), "DescribeInstances") - self.assertEqual(dd_span.get_tag("component"), "boto") - self.assertEqual(dd_span.get_tag("span.kind"), "client") - assert_span_http_status_code(dd_span, 200) - self.assertEqual(dd_span.get_tag(http.METHOD), "POST") - self.assertEqual(dd_span.get_tag("aws.region"), "us-west-2") - self.assertEqual(dd_span.get_tag("region"), "us-west-2") - self.assertEqual(dd_span.get_tag("aws.partition"), "aws") - - with ot_tracer.start_active_span("ot_span"): - ec2.run_instances(21) - spans = self.pop_spans() - assert spans - self.assertEqual(len(spans), 2) - ot_span, dd_span = spans - - # confirm the parenting - self.assertIsNone(ot_span.parent_id) - self.assertEqual(dd_span.parent_id, ot_span.span_id) - - self.assertEqual(dd_span.get_tag("aws.operation"), "RunInstances") - assert_span_http_status_code(dd_span, 200) - self.assertEqual(dd_span.get_tag(http.METHOD), "POST") - self.assertEqual(dd_span.get_tag("aws.region"), "us-west-2") - self.assertEqual(dd_span.get_tag("region"), "us-west-2") - self.assertEqual(dd_span.get_tag("aws.partition"), "aws") - self.assertEqual(dd_span.get_tag("component"), "boto") - self.assertEqual(dd_span.get_tag("span.kind"), "client") - self.assertEqual(dd_span.service, "test-boto-tracing.ec2") - self.assertEqual(dd_span.resource, "ec2.runinstances") - self.assertEqual(dd_span.name, "ec2.command") diff --git a/tests/contrib/botocore/test.py b/tests/contrib/botocore/test.py index 5270f69f021..1cfdb2306fd 100644 --- a/tests/contrib/botocore/test.py +++ b/tests/contrib/botocore/test.py @@ -47,7 +47,6 @@ from ddtrace.internal.utils.version import parse_version from ddtrace.propagation.http import HTTP_HEADER_PARENT_ID from ddtrace.propagation.http import HTTP_HEADER_TRACE_ID -from tests.opentracer.utils import init_tracer from tests.utils import TracerTestCase from tests.utils import assert_is_measured from tests.utils import assert_span_http_status_code @@ -2245,43 +2244,6 @@ def test_schematized_unspecified_service_kms_client_v1(self): assert span.service == DEFAULT_SPAN_SERVICE_NAME assert span.name == "aws.kms.request" - @mock_ec2 - def test_traced_client_ot(self): - """OpenTracing version of test_traced_client.""" - ot_tracer = init_tracer("ec2_svc", self.tracer) - - with ot_tracer.start_active_span("ec2_op"): - ec2 = self.session.create_client("ec2", region_name="us-west-2") - pin = Pin(service=self.TEST_SERVICE) - pin._tracer = self.tracer - pin.onto(ec2) - ec2.describe_instances() - - spans = self.get_spans() - assert spans - assert len(spans) == 2 - - ot_span, dd_span = spans - - # confirm the parenting - assert ot_span.parent_id is None - assert dd_span.parent_id == ot_span.span_id - - assert ot_span.name == "ec2_op" - assert ot_span.service == "ec2_svc" - - assert dd_span.get_tag("aws.agent") == "botocore" - assert dd_span.get_tag("aws.region") == "us-west-2" - assert dd_span.get_tag("region") == "us-west-2" - assert dd_span.get_tag("aws.operation") == "DescribeInstances" - assert dd_span.get_tag("component") == "botocore" - assert dd_span.get_tag("span.kind"), "client" - assert_span_http_status_code(dd_span, 200) - assert dd_span.get_metric("retry_attempts") == 0 - assert dd_span.service == "test-botocore-tracing.ec2" - assert dd_span.resource == "ec2.describeinstances" - assert dd_span.name == "ec2.command" - @unittest.skipIf(BOTOCORE_VERSION < (1, 9, 0), "Skipping for older versions of botocore without Stubber") def test_stubber_no_response_metadata(self): """When no ResponseMetadata key is provided in the response""" diff --git a/tests/contrib/bottle/test.py b/tests/contrib/bottle/test.py index 5a274802d85..d74ceb4935d 100644 --- a/tests/contrib/bottle/test.py +++ b/tests/contrib/bottle/test.py @@ -7,7 +7,6 @@ from ddtrace.contrib.internal.bottle.patch import TracePlugin from ddtrace.ext import http from ddtrace.internal.schema import DEFAULT_SPAN_SERVICE_NAME -from tests.opentracer.utils import init_tracer from tests.tracer.utils_inferred_spans.test_helpers import assert_web_and_inferred_aws_api_gateway_span_data from tests.utils import TracerTestCase from tests.utils import assert_is_measured @@ -316,44 +315,6 @@ def home(): assert s.get_tag("span.kind") == "server" assert s.get_tag("http.route") == "/home/" - def test_200_ot(self): - ot_tracer = init_tracer("my_svc", self.tracer) - - # setup our test app - @self.app.route("/hi/") - def hi(name): - return "hi %s" % name - - self._trace_app(self.tracer) - - # make a request - with ot_tracer.start_active_span("ot_span"): - resp = self.app.get("/hi/dougie") - - assert resp.status_int == 200 - assert resp.body.decode("utf-8", errors="ignore") == "hi dougie" - # validate it's traced - spans = self.pop_spans() - assert len(spans) == 2 - ot_span, dd_span = spans - - # confirm the parenting - assert ot_span.parent_id is None - assert dd_span.parent_id == ot_span.span_id - - assert ot_span.resource == "ot_span" - - assert_is_measured(dd_span) - assert dd_span.name == "bottle.request" - assert dd_span.service == "bottle-app" - assert dd_span.resource == "GET /hi/" - assert_span_http_status_code(dd_span, 200) - assert dd_span.get_tag("http.method") == "GET" - assert dd_span.get_tag(http.URL) == "http://localhost:80/hi/dougie" - assert dd_span.get_tag("component") == "bottle" - assert dd_span.get_tag("span.kind") == "server" - assert dd_span.get_tag("http.route") == "/hi/" - @TracerTestCase.run_in_subprocess(env_overrides=dict(DD_SERVICE="mysvc")) def test_user_specified_service_default_schema(self): """ diff --git a/tests/contrib/celery/test_integration.py b/tests/contrib/celery/test_integration.py index 9646c0aceda..8a831e2c709 100644 --- a/tests/contrib/celery/test_integration.py +++ b/tests/contrib/celery/test_integration.py @@ -15,7 +15,6 @@ import ddtrace.internal.forksafe as forksafe from ddtrace.propagation.http import HTTPPropagator from ddtrace.trace import Context -from tests.opentracer.utils import init_tracer from ...utils import override_global_config from .base import CeleryBaseTestCase @@ -599,55 +598,6 @@ def fn_task(): assert run_trace[1].name == "test" assert run_trace[1].parent_id == run_trace[0].span_id - def test_fn_task_apply_async_ot(self): - """OpenTracing version of test_fn_task_apply_async.""" - ot_tracer = init_tracer("celery_svc", self.tracer) - - # it should execute a traced async task that has parameters - @self.app.task - def fn_task_parameters(user, force_logout=False): - return (user, force_logout) - - with ot_tracer.start_active_span("celery_op"): - t = fn_task_parameters.apply_async(args=["user"], kwargs={"force_logout": True}) - assert tuple(t.get(timeout=self.ASYNC_GET_TIMEOUT)) == ("user", True) - - ot_span = self.find_span(name="celery_op") - assert ot_span.parent_id is None - assert ot_span.name == "celery_op" - assert ot_span.service == "celery_svc" - - if self.ASYNC_USE_CELERY_FIXTURES: - async_span = self.find_span(name="celery.apply") - self.assert_is_measured(async_span) - assert async_span.error == 0 - - # confirm the parenting - assert async_span.parent_id == ot_span.span_id - assert async_span.name == "celery.apply" - assert async_span.resource == "tests.contrib.celery.test_integration.fn_task_parameters" - assert async_span.service == "celery-producer" - assert async_span.get_tag("celery.id") == t.task_id - assert async_span.get_tag("celery.action") == "apply_async" - assert async_span.get_tag("celery.routing_key") == "celery" - assert async_span.get_tag("component") == "celery" - assert async_span.get_tag("span.kind") == "producer" - assert async_span.get_tag("out.host") == "memory://" - - run_span = self.find_span(name="celery.run") - assert run_span.name == "celery.run" - assert run_span.parent_id is None - assert run_span.resource == "tests.contrib.celery.test_integration.fn_task_parameters" - assert run_span.service == "celery-worker" - assert run_span.get_tag("celery.id") == t.task_id - assert run_span.get_tag("celery.action") == "run" - assert run_span.get_tag("component") == "celery" - assert run_span.get_tag("span.kind") == "consumer" - - traces = self.pop_traces() - assert len(traces) == 2 - assert len(traces[0]) + len(traces[1]) == 3 - @pytest.mark.no_getattr_patch # this mark is added to prevent patching of getattr necessary for integration registry update # see: https://github.com/DataDog/dd-trace-py/pull/13215 diff --git a/tests/contrib/django/test_django.py b/tests/contrib/django/test_django.py index 7b58471c1d7..a10478fb143 100644 --- a/tests/contrib/django/test_django.py +++ b/tests/contrib/django/test_django.py @@ -36,7 +36,6 @@ from ddtrace.propagation.http import HTTP_HEADER_SAMPLING_PRIORITY from ddtrace.propagation.http import HTTP_HEADER_TRACE_ID from tests.conftest import DEFAULT_DDTRACE_SUBPROCESS_TEST_SERVICE_NAME -from tests.opentracer.utils import init_tracer from tests.tracer.utils_inferred_spans.test_helpers import assert_web_and_inferred_aws_api_gateway_span_data from tests.utils import assert_dict_issuperset from tests.utils import override_config @@ -1952,38 +1951,6 @@ def test_template_name(test_spans): assert span.resource == "/my-template" -""" -OpenTracing tests -""" - - -@pytest.mark.django_db -def test_middleware_trace_request_ot(client, test_spans, tracer): - """OpenTracing version of test_middleware_trace_request.""" - ot_tracer = init_tracer("my_svc", tracer) - - # ensures that the internals are properly traced - with ot_tracer.start_active_span("ot_span"): - assert client.get("/users/").status_code == 200 - - # check for spans - spans = test_spans.get_spans() - ot_span = spans[0] - sp_request = spans[1] - - # confirm parenting - assert ot_span.parent_id is None - assert sp_request.parent_id == ot_span.span_id - - assert ot_span.resource == "ot_span" - assert ot_span.service == "my_svc" - - assert sp_request.get_tag("http.status_code") == "200" - assert sp_request.get_tag(http.URL) == "http://testserver/users/" - assert sp_request.get_tag("django.user.is_authenticated") == "False" - assert sp_request.get_tag("http.method") == "GET" - - def test_collecting_requests_handles_improperly_configured_error(client, test_spans): """ Since it's difficult to reproduce the ImproperlyConfigured error via django (server setup), will instead diff --git a/tests/contrib/falcon/test_suite.py b/tests/contrib/falcon/test_suite.py index 2cb912ee760..9771158e34d 100644 --- a/tests/contrib/falcon/test_suite.py +++ b/tests/contrib/falcon/test_suite.py @@ -3,7 +3,6 @@ from ddtrace.constants import USER_KEEP from ddtrace.contrib.internal.falcon.patch import FALCON_VERSION from ddtrace.ext import http as httpx -from tests.opentracer.utils import init_tracer from tests.tracer.utils_inferred_spans.test_helpers import assert_web_and_inferred_aws_api_gateway_span_data from tests.utils import assert_is_measured from tests.utils import assert_span_http_status_code @@ -225,37 +224,6 @@ def test_404_exception_no_stacktracer(self): assert span.get_tag("component") == "falcon" assert span.get_tag("span.kind") == "server" - def test_200_ot(self): - """OpenTracing version of test_200.""" - writer = self.tracer._span_aggregator.writer - ot_tracer = init_tracer("my_svc", self.tracer) - ot_tracer._dd_tracer._span_aggregator.writer = writer - ot_tracer._dd_tracer._recreate() - - with ot_tracer.start_active_span("ot_span"): - out = self.make_test_call("/200", expected_status_code=200) - assert out.content.decode("utf-8") == "Success" - - traces = self.tracer.pop_traces() - assert len(traces) == 1 - assert len(traces[0]) == 2 - ot_span, dd_span = traces[0] - - # confirm the parenting - assert ot_span.parent_id is None - assert dd_span.parent_id == ot_span.span_id - - assert ot_span.service == "my_svc" - assert ot_span.resource == "ot_span" - - assert_is_measured(dd_span) - assert dd_span.name == "falcon.request" - assert dd_span.service == self._service - assert dd_span.resource == "GET tests.contrib.falcon.app.resources.Resource200" - assert_span_http_status_code(dd_span, 200) - assert dd_span.get_tag(httpx.URL) == "http://falconframework.org/200" - assert dd_span.error == 0 - def test_falcon_request_hook(self): @config.falcon.hooks.on("request") def on_falcon_request(span, request, response): diff --git a/tests/contrib/flask_cache/test.py b/tests/contrib/flask_cache/test.py index 25ed861dbe2..6e23414eace 100644 --- a/tests/contrib/flask_cache/test.py +++ b/tests/contrib/flask_cache/test.py @@ -5,7 +5,6 @@ from ddtrace.contrib.internal.flask_cache.patch import get_traced_cache from ddtrace.ext import net from ddtrace.internal.schema import DEFAULT_SPAN_SERVICE_NAME -from tests.opentracer.utils import init_tracer from tests.utils import TracerTestCase from tests.utils import assert_dict_issuperset from tests.utils import assert_is_measured @@ -317,44 +316,6 @@ def test_default_span_tags_memcached(self): self.assertEqual(span.get_tag(net.TARGET_HOST), "127.0.0.1") self.assertEqual(span.get_metric("network.destination.port"), self.TEST_MEMCACHED_PORT) - def test_simple_cache_get_ot(self): - """OpenTracing version of test_simple_cache_get.""" - ot_tracer = init_tracer("my_svc", self.tracer) - - # create the TracedCache instance for a Flask app - Cache = get_traced_cache(self.tracer, service=self.SERVICE) - app = Flask(__name__) - cache = Cache(app, config={"CACHE_TYPE": "simple"}) - - with ot_tracer.start_active_span("ot_span"): - cache.get("á_complex_operation") - - spans = self.get_spans() - self.assertEqual(len(spans), 2) - ot_span, dd_span = spans - - # confirm the parenting - self.assertIsNone(ot_span.parent_id) - self.assertEqual(dd_span.parent_id, ot_span.span_id) - - self.assertEqual(ot_span.resource, "ot_span") - self.assertEqual(ot_span.service, "my_svc") - - assert_is_measured(dd_span) - self.assertEqual(dd_span.service, self.SERVICE) - self.assertEqual(dd_span.resource, "get") - self.assertEqual(dd_span.name, "flask_cache.cmd") - self.assertEqual(dd_span.span_type, "cache") - self.assertEqual(dd_span.error, 0) - - expected_meta = { - "flask_cache.key": "á_complex_operation", - "flask_cache.backend": "simple", - "component": "flask_cache", - } - - assert_dict_issuperset(dd_span.get_tags(), expected_meta) - class TestFlaskCacheSchematization(TracerTestCase): TEST_REDIS_PORT = REDIS_CONFIG["port"] diff --git a/tests/contrib/futures/test_propagation.py b/tests/contrib/futures/test_propagation.py index 77a9e2f25a1..763052dda0c 100644 --- a/tests/contrib/futures/test_propagation.py +++ b/tests/contrib/futures/test_propagation.py @@ -6,7 +6,6 @@ from ddtrace.contrib.internal.futures.patch import patch from ddtrace.contrib.internal.futures.patch import unpatch -from tests.opentracer.utils import init_tracer from tests.utils import DummyTracer from tests.utils import TracerTestCase @@ -408,33 +407,6 @@ def fn(): assert spans[1].trace_id == spans[0].trace_id assert spans[1].parent_id == spans[0].span_id - def test_propagation_ot(self): - """OpenTracing version of test_propagation.""" - # it must propagate the tracing context if available - ot_tracer = init_tracer("my_svc", self.tracer) - - def fn(): - # an active context must be available - self.assertTrue(self.tracer.context_provider.active() is not None) - with self.tracer.trace("executor.thread"): - return 42 - - with self.override_global_tracer(): - with ot_tracer.start_active_span("main.thread"): - with concurrent.futures.ThreadPoolExecutor(max_workers=2) as executor: - future = executor.submit(fn) - result = future.result() - # assert the right result - self.assertEqual(result, 42) - - # the trace must be completed - self.assert_span_count(2) - spans = self.get_spans() - assert spans[0].name == "main.thread" - assert spans[1].name == "executor.thread" - assert spans[1].trace_id == spans[0].trace_id - assert spans[1].parent_id == spans[0].span_id - @pytest.mark.skipif(sys.version_info > (3, 12), reason="Fails on 3.13") @pytest.mark.subprocess(ddtrace_run=True, timeout=5) diff --git a/tests/contrib/gevent/test_tracer.py b/tests/contrib/gevent/test_tracer.py index dc72ccc08ca..a7505d56f7d 100644 --- a/tests/contrib/gevent/test_tracer.py +++ b/tests/contrib/gevent/test_tracer.py @@ -2,7 +2,6 @@ import gevent import gevent.pool -from opentracing.scope_managers.gevent import GeventScopeManager import ddtrace from ddtrace.constants import ERROR_MSG @@ -11,7 +10,6 @@ from ddtrace.trace import Context from ddtrace.contrib.internal.gevent.patch import patch from ddtrace.contrib.internal.gevent.patch import unpatch -from tests.opentracer.utils import init_tracer from tests.utils import TracerTestCase from .utils import silence_errors @@ -356,34 +354,6 @@ def green_2(): spans = self.pop_spans() self._assert_spawn_multiple_greenlets(spans) - def test_trace_spawn_multiple_greenlets_multiple_traces_ot(self): - """OpenTracing version of the same test.""" - - ot_tracer = init_tracer("my_svc", self.tracer, scope_manager=GeventScopeManager()) - - def entrypoint(): - with ot_tracer.start_active_span("greenlet.main") as span: - span.resource = "base" - jobs = [gevent.spawn(green_1), gevent.spawn(green_2)] - gevent.joinall(jobs) - - def green_1(): - with self.tracer.trace("greenlet.worker1") as span: - span.set_tag("worker_id", "1") - gevent.sleep(0.01) - - # note that replacing the `tracer.trace` call here with the - # OpenTracing equivalent will cause the checks to fail - def green_2(): - with ot_tracer.start_active_span("greenlet.worker2") as scope: - scope.span.set_tag("worker_id", "2") - gevent.sleep(0.01) - - gevent.spawn(entrypoint).join() - - spans = self.pop_spans() - self._assert_spawn_multiple_greenlets(spans) - def test_ddtracerun(self): """ Regression test case for the following issue. diff --git a/tests/contrib/httplib/test_httplib.py b/tests/contrib/httplib/test_httplib.py index 7a2f4a07463..867afad7687 100644 --- a/tests/contrib/httplib/test_httplib.py +++ b/tests/contrib/httplib/test_httplib.py @@ -18,7 +18,6 @@ from ddtrace.ext import http from ddtrace.internal.constants import _HTTPLIB_NO_TRACE_REQUEST from ddtrace.internal.schema import DEFAULT_SPAN_SERVICE_NAME -from tests.opentracer.utils import init_tracer from tests.utils import TracerTestCase from tests.utils import assert_span_http_status_code from tests.utils import override_global_tracer @@ -529,37 +528,6 @@ def test_urllib_request_opener(self): self.assertEqual(span.get_tag("span.kind"), "client") self.assertEqual(span.get_tag("out.host"), "localhost") - def test_httplib_request_get_request_ot(self): - """OpenTracing version of test with same name.""" - ot_tracer = init_tracer("my_svc", self.tracer) - - with ot_tracer.start_active_span("ot_span"): - conn = self.get_http_connection(SOCKET) - with contextlib.closing(conn): - conn.request("GET", "/status/200") - resp = conn.getresponse() - self.assertEqual(self.to_str(resp.read()), "") - self.assertEqual(resp.status, 200) - - spans = self.pop_spans() - self.assertEqual(len(spans), 2) - ot_span, dd_span = spans - - # confirm the parenting - self.assertEqual(ot_span.parent_id, None) - self.assertEqual(dd_span.parent_id, ot_span.span_id) - - self.assertEqual(ot_span.service, "my_svc") - self.assertEqual(ot_span.name, "ot_span") - - self.assert_is_not_measured(dd_span) - self.assertEqual(dd_span.span_type, "http") - self.assertEqual(dd_span.name, self.SPAN_NAME) - self.assertEqual(dd_span.error, 0) - assert dd_span.get_tag("http.method") == "GET" - assert_span_http_status_code(dd_span, 200) - assert dd_span.get_tag("http.url") == URL_200 - def test_httplib_bad_url(self): conn = self.get_http_connection("DNE", "80") with contextlib.closing(conn): diff --git a/tests/contrib/mysql/test_mysql.py b/tests/contrib/mysql/test_mysql.py index a071731d470..edb7fed2076 100644 --- a/tests/contrib/mysql/test_mysql.py +++ b/tests/contrib/mysql/test_mysql.py @@ -6,7 +6,6 @@ from ddtrace.contrib.internal.mysql.patch import unpatch from tests.contrib import shared_tests from tests.contrib.config import MYSQL_CONFIG -from tests.opentracer.utils import init_tracer from tests.utils import TracerTestCase from tests.utils import assert_dict_issuperset from tests.utils import assert_is_measured @@ -253,93 +252,6 @@ def test_query_proc(self): ) assert span.get_tag("sql.query") is None - def test_simple_query_ot(self): - """OpenTracing version of test_simple_query.""" - conn, tracer = self._get_conn_tracer() - - ot_tracer = init_tracer("mysql_svc", tracer) - - with ot_tracer.start_active_span("mysql_op"): - cursor = conn.cursor() - cursor.execute("SELECT 1") - rows = cursor.fetchall() - assert len(rows) == 1 - - spans = tracer.pop() - assert len(spans) == 2 - - ot_span, dd_span = spans - - # confirm parenting - assert ot_span.parent_id is None - assert dd_span.parent_id == ot_span.span_id - - assert ot_span.service == "mysql_svc" - assert ot_span.name == "mysql_op" - - assert_is_measured(dd_span) - assert dd_span.service == "mysql" - assert dd_span.name == "mysql.query" - assert dd_span.span_type == "sql" - assert dd_span.error == 0 - assert dd_span.get_metric("network.destination.port") == 3306 - assert_dict_issuperset( - dd_span.get_tags(), - { - "out.host": "127.0.0.1", - "db.name": "test", - "db.system": "mysql", - "db.user": "test", - "component": "mysql", - "span.kind": "client", - }, - ) - - def test_simple_query_ot_fetchall(self): - """OpenTracing version of test_simple_query.""" - with self.override_config("mysql", dict(trace_fetch_methods=True)): - conn, tracer = self._get_conn_tracer() - - ot_tracer = init_tracer("mysql_svc", tracer) - - with ot_tracer.start_active_span("mysql_op"): - cursor = conn.cursor() - cursor.execute("SELECT 1") - rows = cursor.fetchall() - assert len(rows) == 1 - - spans = tracer.pop() - assert len(spans) == 3 - - ot_span, dd_span, fetch_span = spans - - # confirm parenting - assert ot_span.parent_id is None - assert dd_span.parent_id == ot_span.span_id - - assert ot_span.service == "mysql_svc" - assert ot_span.name == "mysql_op" - - assert_is_measured(dd_span) - assert dd_span.service == "mysql" - assert dd_span.name == "mysql.query" - assert dd_span.span_type == "sql" - assert dd_span.error == 0 - assert dd_span.get_metric("network.destination.port") == 3306 - assert_dict_issuperset( - dd_span.get_tags(), - { - "out.host": "127.0.0.1", - "db.name": "test", - "db.system": "mysql", - "db.user": "test", - "component": "mysql", - "span.kind": "client", - }, - ) - - assert fetch_span.name == "mysql.query.fetchall" - def test_commit(self): conn, tracer = self._get_conn_tracer() conn.commit() diff --git a/tests/contrib/mysqldb/test_mysqldb.py b/tests/contrib/mysqldb/test_mysqldb.py index 344e42c46ad..82c99afd968 100644 --- a/tests/contrib/mysqldb/test_mysqldb.py +++ b/tests/contrib/mysqldb/test_mysqldb.py @@ -7,7 +7,6 @@ from ddtrace.contrib.internal.mysqldb.patch import unpatch from ddtrace.internal.schema import DEFAULT_SPAN_SERVICE_NAME from tests.contrib import shared_tests -from tests.opentracer.utils import init_tracer from tests.utils import TracerTestCase from tests.utils import assert_dict_issuperset from tests.utils import assert_is_measured @@ -323,89 +322,6 @@ def test_query_proc(self): ) assert span.get_tag("sql.query") is None - def test_simple_query_ot(self): - """OpenTracing version of test_simple_query.""" - conn, tracer = self._get_conn_tracer() - - ot_tracer = init_tracer("mysql_svc", tracer) - with ot_tracer.start_active_span("mysql_op"): - cursor = conn.cursor() - cursor.execute("SELECT 1") - rows = cursor.fetchall() - assert len(rows) == 1 - - spans = tracer.pop() - assert len(spans) == 2 - ot_span, dd_span = spans - - # confirm parenting - assert ot_span.parent_id is None - assert dd_span.parent_id == ot_span.span_id - - assert ot_span.service == "mysql_svc" - assert ot_span.name == "mysql_op" - - assert_is_measured(dd_span) - assert dd_span.service == "mysql" - assert dd_span.name == "mysql.query" - assert dd_span.span_type == "sql" - assert dd_span.error == 0 - assert dd_span.get_metric("network.destination.port") == 3306 - assert_dict_issuperset( - dd_span.get_tags(), - { - "out.host": "127.0.0.1", - "db.name": "test", - "db.system": "mysql", - "db.user": "test", - "component": "mysqldb", - "span.kind": "client", - }, - ) - - def test_simple_query_ot_fetchall(self): - """OpenTracing version of test_simple_query.""" - with self.override_config("mysqldb", dict(trace_fetch_methods=True)): - conn, tracer = self._get_conn_tracer() - - ot_tracer = init_tracer("mysql_svc", tracer) - with ot_tracer.start_active_span("mysql_op"): - cursor = conn.cursor() - cursor.execute("SELECT 1") - rows = cursor.fetchall() - assert len(rows) == 1 - - spans = tracer.pop() - assert len(spans) == 3 - ot_span, dd_span, fetch_span = spans - - # confirm parenting - assert ot_span.parent_id is None - assert dd_span.parent_id == ot_span.span_id - - assert ot_span.service == "mysql_svc" - assert ot_span.name == "mysql_op" - - assert_is_measured(dd_span) - assert dd_span.service == "mysql" - assert dd_span.name == "mysql.query" - assert dd_span.span_type == "sql" - assert dd_span.error == 0 - assert dd_span.get_metric("network.destination.port") == 3306 - assert_dict_issuperset( - dd_span.get_tags(), - { - "out.host": "127.0.0.1", - "db.name": "test", - "db.system": "mysql", - "db.user": "test", - "component": "mysqldb", - "span.kind": "client", - }, - ) - - assert fetch_span.name == "mysql.query.fetchall" - def test_commit(self): conn, tracer = self._get_conn_tracer() diff --git a/tests/contrib/psycopg/test_psycopg.py b/tests/contrib/psycopg/test_psycopg.py index 987890dbbd7..b433bcb68f3 100644 --- a/tests/contrib/psycopg/test_psycopg.py +++ b/tests/contrib/psycopg/test_psycopg.py @@ -14,7 +14,6 @@ from ddtrace.internal.schema import DEFAULT_SPAN_SERVICE_NAME from ddtrace.internal.utils.version import parse_version from tests.contrib.config import POSTGRES_CONFIG -from tests.opentracer.utils import init_tracer from tests.utils import TracerTestCase from tests.utils import assert_is_measured from tests.utils import snapshot @@ -142,47 +141,6 @@ def test_psycopg3_connection_with_string(self): Pin.get_from(conn)._clone(service="postgres", tracer=self.tracer).onto(conn) self.assert_conn_is_traced(conn, "postgres") - def test_opentracing_propagation(self): - # ensure OpenTracing plays well with our integration - query = """SELECT 'tracing'""" - - db = self._get_conn() - ot_tracer = init_tracer("psycopg-svc", self.tracer) - - with ot_tracer.start_active_span("db.access"): - cursor = db.cursor() - cursor.execute(query) - rows = cursor.fetchall() - - self.assertEqual(rows, [("tracing",)]) - - self.assert_structure( - dict(name="db.access", service="psycopg-svc"), - (dict(name="postgres.query", resource=query, service="postgres", error=0, span_type="sql"),), - ) - assert_is_measured(self.get_spans()[1]) - self.reset() - - with self.override_config("psycopg", dict(trace_fetch_methods=True)): - db = self._get_conn() - ot_tracer = init_tracer("psycopg-svc", self.tracer) - - with ot_tracer.start_active_span("db.access"): - cursor = db.cursor() - cursor.execute(query) - rows = cursor.fetchall() - - self.assertEqual(rows, [("tracing",)]) - - self.assert_structure( - dict(name="db.access", service="psycopg-svc"), - ( - dict(name="postgres.query", resource=query, service="postgres", error=0, span_type="sql"), - dict(name="postgres.query.fetchall", resource=query, service="postgres", error=0, span_type="sql"), - ), - ) - assert_is_measured(self.get_spans()[1]) - def test_cursor_ctx_manager(self): # ensure cursors work with context managers # https://github.com/DataDog/dd-trace-py/issues/228 diff --git a/tests/contrib/psycopg/test_psycopg_async.py b/tests/contrib/psycopg/test_psycopg_async.py index b4778e0693a..a21dc2d794c 100644 --- a/tests/contrib/psycopg/test_psycopg_async.py +++ b/tests/contrib/psycopg/test_psycopg_async.py @@ -10,7 +10,6 @@ from ddtrace.contrib.internal.psycopg.patch import unpatch from tests.contrib.asyncio.utils import AsyncioTestCase from tests.contrib.config import POSTGRES_CONFIG -from tests.opentracer.utils import init_tracer from tests.utils import assert_is_measured @@ -127,47 +126,6 @@ async def assert_conn_is_traced_async(self, db, service): self.assertIsNone(root.get_tag("sql.query")) self.reset() - async def test_opentracing_propagation(self): - # ensure OpenTracing plays well with our integration - query = """SELECT 'tracing'""" - - db = await self._get_conn() - ot_tracer = init_tracer("psycopg-svc", self.tracer) - - with ot_tracer.start_active_span("db.access"): - cursor = db.cursor() - await cursor.execute(query) - rows = await cursor.fetchall() - - self.assertEqual(rows, [("tracing",)]) - - self.assert_structure( - dict(name="db.access", service="psycopg-svc"), - (dict(name="postgres.query", resource=query, service="postgres", error=0, span_type="sql"),), - ) - assert_is_measured(self.get_spans()[1]) - self.reset() - - with self.override_config("psycopg", dict(trace_fetch_methods=True)): - db = await self._get_conn() - ot_tracer = init_tracer("psycopg-svc", self.tracer) - - with ot_tracer.start_active_span("db.access"): - cursor = db.cursor() - await cursor.execute(query) - rows = await cursor.fetchall() - - self.assertEqual(rows, [("tracing",)]) - - self.assert_structure( - dict(name="db.access", service="psycopg-svc"), - ( - dict(name="postgres.query", resource=query, service="postgres", error=0, span_type="sql"), - dict(name="postgres.query.fetchall", resource=query, service="postgres", error=0, span_type="sql"), - ), - ) - assert_is_measured(self.get_spans()[1]) - async def test_cursor_ctx_manager(self): # ensure cursors work with context managers # https://github.com/DataDog/dd-trace-py/issues/228 diff --git a/tests/contrib/psycopg2/test_psycopg.py b/tests/contrib/psycopg2/test_psycopg.py index 209de02c880..10051da0cff 100644 --- a/tests/contrib/psycopg2/test_psycopg.py +++ b/tests/contrib/psycopg2/test_psycopg.py @@ -13,7 +13,6 @@ from ddtrace.internal.schema import DEFAULT_SPAN_SERVICE_NAME from ddtrace.internal.utils.version import parse_version from tests.contrib.config import POSTGRES_CONFIG -from tests.opentracer.utils import init_tracer from tests.utils import TracerTestCase from tests.utils import assert_is_measured from tests.utils import snapshot @@ -148,47 +147,6 @@ def test_psycopg2_connection_with_string(self): Pin.get_from(conn)._clone(service="postgres", tracer=self.tracer).onto(conn) self.assert_conn_is_traced(conn, "postgres") - def test_opentracing_propagation(self): - # ensure OpenTracing plays well with our integration - query = """SELECT 'tracing'""" - - db = self._get_conn() - ot_tracer = init_tracer("psycopg-svc", self.tracer) - - with ot_tracer.start_active_span("db.access"): - cursor = db.cursor() - cursor.execute(query) - rows = cursor.fetchall() - - self.assertEqual(rows, [("tracing",)]) - - self.assert_structure( - dict(name="db.access", service="psycopg-svc"), - (dict(name="postgres.query", resource=query, service="postgres", error=0, span_type="sql"),), - ) - assert_is_measured(self.get_spans()[1]) - self.reset() - - with self.override_config("psycopg", dict(trace_fetch_methods=True)): - db = self._get_conn() - ot_tracer = init_tracer("psycopg-svc", self.tracer) - - with ot_tracer.start_active_span("db.access"): - cursor = db.cursor() - cursor.execute(query) - rows = cursor.fetchall() - - self.assertEqual(rows, [("tracing",)]) - - self.assert_structure( - dict(name="db.access", service="psycopg-svc"), - ( - dict(name="postgres.query", resource=query, service="postgres", error=0, span_type="sql"), - dict(name="postgres.query.fetchall", resource=query, service="postgres", error=0, span_type="sql"), - ), - ) - assert_is_measured(self.get_spans()[1]) - @skipIf(PSYCOPG2_VERSION < (2, 5), "context manager not available in psycopg2==2.4") def test_cursor_ctx_manager(self): # ensure cursors work with context managers diff --git a/tests/contrib/pylibmc/test.py b/tests/contrib/pylibmc/test.py index da5823fc6b3..91242bbe871 100644 --- a/tests/contrib/pylibmc/test.py +++ b/tests/contrib/pylibmc/test.py @@ -12,7 +12,6 @@ from ddtrace.contrib.internal.pylibmc.patch import unpatch from ddtrace.ext import memcached from tests.contrib.config import MEMCACHED_CONFIG as cfg -from tests.opentracer.utils import init_tracer from tests.utils import TracerTestCase from tests.utils import assert_is_measured @@ -78,33 +77,6 @@ def test_incr_decr(self): resources = sorted(s.resource for s in spans) assert expected_resources == resources - def test_incr_decr_ot(self): - """OpenTracing version of test_incr_decr.""" - client, tracer = self.get_client() - ot_tracer = init_tracer("memcached", tracer) - - start = time.time() - with ot_tracer.start_active_span("mc_ops"): - client.set("a", 1) - client.incr("a", 2) - client.decr("a", 1) - v = client.get("a") - assert v == 2 - end = time.time() - - # verify spans - spans = tracer.pop() - ot_span = spans[0] - - assert ot_span.name == "mc_ops" - - for s in spans[1:]: - assert s.parent_id == ot_span.span_id - self._verify_cache_span(s, start, end) - expected_resources = sorted(["get", "set", "incr", "decr"]) - resources = sorted(s.resource for s in spans[1:]) - assert expected_resources == resources - def test_clone(self): # ensure cloned connections are traced as well. client, tracer = self.get_client() diff --git a/tests/contrib/pymongo/test.py b/tests/contrib/pymongo/test.py index 236fa582910..ccabc218ce9 100644 --- a/tests/contrib/pymongo/test.py +++ b/tests/contrib/pymongo/test.py @@ -10,7 +10,6 @@ from ddtrace.contrib.internal.pymongo.patch import patch from ddtrace.contrib.internal.pymongo.patch import unpatch from ddtrace.ext import SpanTypes -from tests.opentracer.utils import init_tracer from tests.utils import DummyTracer from tests.utils import TracerTestCase from tests.utils import assert_is_measured @@ -298,67 +297,6 @@ def test_insert_find(self): assert spans[-1].resource == 'find teams {"name": "?"}' assert spans[-1].get_tag("mongodb.query") == '{"name": "?"}' - def test_update_ot(self): - """OpenTracing version of test_update.""" - tracer, client = self.get_tracer_and_client() - ot_tracer = init_tracer("mongo_svc", tracer) - - with ot_tracer.start_active_span("mongo_op"): - db = client["testdb"] - db.drop_collection("songs") - input_songs = [ - {"name": "Powderfinger", "artist": "Neil"}, - {"name": "Harvest", "artist": "Neil"}, - {"name": "Suzanne", "artist": "Leonard"}, - {"name": "Partisan", "artist": "Leonard"}, - ] - db.songs.insert_many(input_songs) - result = db.songs.update_many( - {"artist": "Neil"}, - {"$set": {"artist": "Shakey"}}, - ) - - assert result.matched_count == 2 - assert result.modified_count == 2 - - # ensure all is traced. - spans = tracer.pop() - assert spans, spans - assert len(spans) == 7 - - ot_span = spans[0] - assert ot_span.parent_id is None - assert ot_span.name == "mongo_op" - assert ot_span.service == "mongo_svc" - - # remove pymongo.get_socket and pymongo.checkout spans - spans = [s for s in spans if s.name == "pymongo.cmd"] - assert len(spans) == 3 - for span in spans: - # ensure all the of the common metadata is set - assert_is_measured(span) - assert span.service == "pymongo" - assert span.span_type == "mongodb" - assert span.get_tag("component") == "pymongo" - assert span.get_tag("span.kind") == "client" - assert span.get_tag("db.system") == "mongodb" - assert span.get_tag("mongodb.collection") == "songs" - assert span.get_tag("mongodb.db") == "testdb" - assert span.get_tag("out.host") - assert span.get_metric("network.destination.port") - - expected_resources = set( - [ - "drop songs", - 'update songs {"artist": "?"}', - "insert songs", - "pymongo.get_socket", - "pymongo.checkout", - ] - ) - - assert {s.resource for s in spans[1:]}.issubset(expected_resources) - def test_rowcount(self): tracer, client = self.get_tracer_and_client() db = client["testdb"] diff --git a/tests/contrib/pymysql/test_pymysql.py b/tests/contrib/pymysql/test_pymysql.py index 762f55bed08..8fb5ef78621 100644 --- a/tests/contrib/pymysql/test_pymysql.py +++ b/tests/contrib/pymysql/test_pymysql.py @@ -6,7 +6,6 @@ from ddtrace.contrib.internal.pymysql.patch import unpatch from ddtrace.internal.schema import DEFAULT_SPAN_SERVICE_NAME from tests.contrib import shared_tests -from tests.opentracer.utils import init_tracer from tests.utils import TracerTestCase from tests.utils import assert_dict_issuperset from tests.utils import assert_is_measured @@ -249,73 +248,6 @@ def test_query_proc(self): meta.update(self.DB_INFO) assert_dict_issuperset(span.get_tags(), meta) - def test_simple_query_ot(self): - """OpenTracing version of test_simple_query.""" - conn, tracer = self._get_conn_tracer() - - ot_tracer = init_tracer("mysql_svc", tracer) - with ot_tracer.start_active_span("mysql_op"): - cursor = conn.cursor() - cursor.execute("SELECT 1") - rows = cursor.fetchall() - assert len(rows) == 1 - - spans = tracer.pop() - assert len(spans) == 2 - ot_span, dd_span = spans - - # confirm parenting - assert ot_span.parent_id is None - assert dd_span.parent_id == ot_span.span_id - - assert ot_span.service == "mysql_svc" - assert ot_span.name == "mysql_op" - - assert_is_measured(dd_span) - assert dd_span.service == "pymysql" - assert dd_span.name == "pymysql.query" - assert dd_span.span_type == "sql" - assert dd_span.error == 0 - assert dd_span.get_metric("network.destination.port") == MYSQL_CONFIG.get("port") - meta = {} - meta.update(self.DB_INFO) - assert_dict_issuperset(dd_span.get_tags(), meta) - - def test_simple_query_ot_fetchall(self): - """OpenTracing version of test_simple_query.""" - with self.override_config("pymysql", dict(trace_fetch_methods=True)): - conn, tracer = self._get_conn_tracer() - - ot_tracer = init_tracer("mysql_svc", tracer) - with ot_tracer.start_active_span("mysql_op"): - cursor = conn.cursor() - cursor.execute("SELECT 1") - rows = cursor.fetchall() - assert len(rows) == 1 - - spans = tracer.pop() - assert len(spans) == 3 - ot_span, dd_span, fetch_span = spans - - # confirm parenting - assert ot_span.parent_id is None - assert dd_span.parent_id == ot_span.span_id - - assert ot_span.service == "mysql_svc" - assert ot_span.name == "mysql_op" - - assert_is_measured(dd_span) - assert dd_span.service == "pymysql" - assert dd_span.name == "pymysql.query" - assert dd_span.span_type == "sql" - assert dd_span.error == 0 - assert dd_span.get_metric("network.destination.port") == MYSQL_CONFIG.get("port") - meta = {} - meta.update(self.DB_INFO) - assert_dict_issuperset(dd_span.get_tags(), meta) - - assert fetch_span.name == "pymysql.query.fetchall" - def test_commit(self): conn, tracer = self._get_conn_tracer() diff --git a/tests/contrib/pyramid/utils.py b/tests/contrib/pyramid/utils.py index 3dec370d500..2f663258ac5 100644 --- a/tests/contrib/pyramid/utils.py +++ b/tests/contrib/pyramid/utils.py @@ -11,7 +11,6 @@ from tests.utils import assert_is_measured from tests.utils import assert_span_http_status_code -from ...opentracer.utils import init_tracer from .app import create_app @@ -273,33 +272,3 @@ def test_include_conflicts(self): self.app.get("/404", status=404) spans = self.pop_spans() assert len(spans) == 1 - - def test_200_ot(self): - """OpenTracing version of test_200.""" - ot_tracer = init_tracer("pyramid_svc", self.tracer) - - with ot_tracer.start_active_span("pyramid_get"): - res = self.app.get("/", status=200) - assert b"idx" in res.body - - spans = self.pop_spans() - assert len(spans) == 2 - - ot_span, dd_span = spans - - # confirm the parenting - assert ot_span.parent_id is None - assert dd_span.parent_id == ot_span.span_id - - assert ot_span.name == "pyramid_get" - assert ot_span.service == "pyramid_svc" - - assert_is_measured(dd_span) - assert dd_span.service == "foobar" - assert dd_span.resource == "GET index" - assert dd_span.error == 0 - assert dd_span.span_type == "web" - assert dd_span.get_tag("http.method") == "GET" - assert_span_http_status_code(dd_span, 200) - assert dd_span.get_tag(http.URL) == "http://localhost/" - assert dd_span.get_tag("pyramid.route.name") == "index" diff --git a/tests/contrib/redis/test_redis.py b/tests/contrib/redis/test_redis.py index 31fe287fdf1..f2a42b83d19 100644 --- a/tests/contrib/redis/test_redis.py +++ b/tests/contrib/redis/test_redis.py @@ -4,12 +4,10 @@ import pytest import redis -import ddtrace from ddtrace._trace.pin import Pin from ddtrace.contrib.internal.redis.patch import patch from ddtrace.contrib.internal.redis.patch import unpatch from ddtrace.internal.schema import DEFAULT_SPAN_SERVICE_NAME -from tests.opentracer.utils import init_tracer from tests.utils import DummyTracer from tests.utils import TracerTestCase from tests.utils import snapshot @@ -238,39 +236,6 @@ def test_patch_unpatch(self): assert spans, spans assert len(spans) == 1 - def test_opentracing(self): - """Ensure OpenTracing works with redis.""" - ot_tracer = init_tracer("redis_svc", self.tracer) - - with ot_tracer.start_active_span("redis_get"): - us = self.r.get("cheese") - assert us is None - - spans = self.get_spans() - assert len(spans) == 2 - ot_span, dd_span = spans - - # confirm the parenting - assert ot_span.parent_id is None - assert dd_span.parent_id == ot_span.span_id - - assert ot_span.name == "redis_get" - assert ot_span.service == "redis_svc" - - self.assert_is_measured(dd_span) - assert dd_span.service == "redis" - assert dd_span.name == "redis.command" - assert dd_span.span_type == "redis" - assert dd_span.error == 0 - assert dd_span.get_metric("out.redis_db") == 0 - assert dd_span.get_tag("out.host") == "localhost" - assert dd_span.get_tag("redis.raw_command") == "GET cheese" - assert dd_span.get_tag("component") == "redis" - assert dd_span.get_tag("span.kind") == "client" - assert dd_span.get_tag("db.system") == "redis" - assert dd_span.get_metric("redis.args_length") == 2 - assert dd_span.resource == "GET" - def test_redis_rowcount_all_keys_valid(self): self.r.set("key1", "value1") @@ -540,20 +505,6 @@ def test_patch_unpatch(self): assert spans, spans assert len(spans) == 1 - @snapshot() - def test_opentracing(self): - """Ensure OpenTracing works with redis.""" - writer = ddtrace.tracer._span_aggregator.writer - ot_tracer = init_tracer("redis_svc", ddtrace.tracer) - # FIXME: OpenTracing always overrides the hostname/port and creates a new - # writer so we have to reconfigure with the previous one - ddtrace.tracer._span_aggregator.writer = writer - ddtrace.tracer._recreate() - - with ot_tracer.start_active_span("redis_get"): - us = self.r.get("cheese") - assert us is None - @TracerTestCase.run_in_subprocess(env_overrides=dict(DD_SERVICE="mysvc")) @snapshot() def test_user_specified_service(self): diff --git a/tests/contrib/requests/test_requests.py b/tests/contrib/requests/test_requests.py index e1a8d2672d6..f7f7c24bc07 100644 --- a/tests/contrib/requests/test_requests.py +++ b/tests/contrib/requests/test_requests.py @@ -18,7 +18,6 @@ from ddtrace.contrib.internal.requests.patch import unpatch from ddtrace.ext import http from ddtrace.internal.schema import DEFAULT_SPAN_SERVICE_NAME -from tests.opentracer.utils import init_tracer from tests.utils import TracerTestCase from tests.utils import assert_is_measured from tests.utils import assert_span_http_status_code @@ -580,35 +579,6 @@ def test_global_config_service(self): spans = self.pop_spans() assert spans[0].service == "override" - def test_200_ot(self): - """OpenTracing version of test_200.""" - - ot_tracer = init_tracer("requests_svc", self.tracer) - - with ot_tracer.start_active_span("requests_get"): - out = self.session.get(URL_200) - assert out.status_code == 200 - - # validation - spans = self.pop_spans() - assert len(spans) == 2 - - ot_span, dd_span = spans - - # confirm the parenting - assert ot_span.parent_id is None - assert dd_span.parent_id == ot_span.span_id - - assert ot_span.name == "requests_get" - assert ot_span.service == "requests_svc" - - assert_is_measured(dd_span) - assert dd_span.get_tag(http.METHOD) == "GET" - assert_span_http_status_code(dd_span, 200) - assert dd_span.error == 0 - assert dd_span.span_type == "http" - assert dd_span.resource == "GET /status/200" - def test_request_and_response_headers(self): # Disabled when not configured self.session.get(URL_200, headers={"my-header": "my_value"}) diff --git a/tests/contrib/snowflake/test_snowflake.py b/tests/contrib/snowflake/test_snowflake.py index f4995255b4c..67ce242b8e4 100644 --- a/tests/contrib/snowflake/test_snowflake.py +++ b/tests/contrib/snowflake/test_snowflake.py @@ -9,8 +9,6 @@ from ddtrace._trace.pin import Pin from ddtrace.contrib.internal.snowflake.patch import patch from ddtrace.contrib.internal.snowflake.patch import unpatch -from ddtrace.trace import tracer -from tests.opentracer.utils import init_tracer from tests.utils import override_config from tests.utils import snapshot @@ -93,13 +91,6 @@ def client(): yield ctx -@contextlib.contextmanager -def ot_trace(): - ot = init_tracer("snowflake_svc", tracer) - with ot.start_active_span("snowflake_op"): - yield - - @snapshot() @req_mock.activate def test_snowflake_fetchone(client): @@ -224,72 +215,6 @@ def test_snowflake_executemany_insert(client): assert res.rowcount == 2 -@snapshot() -@req_mock.activate -def test_snowflake_ot_fetchone(client): - add_snowflake_query_response( - rowtype=["TEXT"], - rows=[("4.30.2",)], - ) - with ot_trace(): - with client.cursor() as cur: - res = cur.execute("select current_version();") - assert res == cur - assert cur.fetchone() == ("4.30.2",) - - -@snapshot() -@req_mock.activate -def test_snowflake_ot_fetchall(client): - add_snowflake_query_response( - rowtype=["TEXT"], - rows=[("4.30.2",)], - ) - with ot_trace(): - with client.cursor() as cur: - res = cur.execute("select current_version();") - assert res == cur - assert cur.fetchall() == [("4.30.2",)] - - -@snapshot() -@req_mock.activate -def test_snowflake_ot_fetchall_multiple_rows(client): - add_snowflake_query_response( - rowtype=["TEXT", "TEXT"], - rows=[("1a", "1b"), ("2a", "2b")], - ) - with ot_trace(): - with client.cursor() as cur: - res = cur.execute("select a, b from t;") - assert res == cur - assert cur.fetchall() == [ - ("1a", "1b"), - ("2a", "2b"), - ] - - -@snapshot() -@req_mock.activate -def test_snowflake_ot_executemany_insert(client): - add_snowflake_query_response( - rowtype=[], - rows=[], - total=2, - ) - with ot_trace(): - with client.cursor() as cur: - res = cur.executemany( - "insert into t (a, b) values (%s, %s);", - [ - ("1a", "1b"), - ("2a", "2b"), - ], - ) - assert res == cur - assert res.rowcount == 2 - - @pytest.mark.snapshot() @pytest.mark.parametrize( "service_schema", diff --git a/tests/contrib/sqlalchemy/mixins.py b/tests/contrib/sqlalchemy/mixins.py index 18b180db2d3..031c9ca3aea 100644 --- a/tests/contrib/sqlalchemy/mixins.py +++ b/tests/contrib/sqlalchemy/mixins.py @@ -9,7 +9,6 @@ from sqlalchemy.orm import sessionmaker from ddtrace.contrib.internal.sqlalchemy.engine import trace_engine -from tests.opentracer.utils import init_tracer Base = declarative_base() @@ -166,36 +165,3 @@ def test_engine_connect_execute(self): assert span.span_type == "sql" assert span.error == 0 assert span.duration > 0 - - def test_opentracing(self): - """Ensure that sqlalchemy works with the opentracer.""" - ot_tracer = init_tracer("sqlalch_svc", self.tracer) - - with ot_tracer.start_active_span("sqlalch_op"): - with self.connection() as conn: - rows = conn.execute(text("SELECT * FROM players")).fetchall() - assert len(rows) == 0 - - traces = self.pop_traces() - # trace composition - assert len(traces) == 1 - assert len(traces[0]) == 2 - ot_span, dd_span = traces[0] - - # confirm the parenting - assert ot_span.parent_id is None - assert dd_span.parent_id == ot_span.span_id - - assert ot_span.name == "sqlalch_op" - assert ot_span.service == "sqlalch_svc" - - # span fields - assert dd_span.name == "{}.query".format(self.VENDOR) - assert dd_span.service == self.SERVICE - assert dd_span.resource == "SELECT * FROM players" - assert dd_span.get_tag("sql.db") == self.SQL_DB - assert dd_span.get_tag("component") == "sqlalchemy" - assert dd_span.get_tag("span.kind") == "client" - assert dd_span.span_type == "sql" - assert dd_span.error == 0 - assert dd_span.duration > 0 diff --git a/tests/contrib/sqlite3/test_sqlite3.py b/tests/contrib/sqlite3/test_sqlite3.py index e4b12d7b4e8..de2b18f72b4 100644 --- a/tests/contrib/sqlite3/test_sqlite3.py +++ b/tests/contrib/sqlite3/test_sqlite3.py @@ -21,7 +21,6 @@ from ddtrace.contrib.internal.sqlite3.patch import patch from ddtrace.contrib.internal.sqlite3.patch import unpatch from ddtrace.internal.schema import DEFAULT_SPAN_SERVICE_NAME -from tests.opentracer.utils import init_tracer from tests.utils import TracerTestCase from tests.utils import assert_is_measured from tests.utils import assert_is_not_measured @@ -206,47 +205,6 @@ def test_sqlite_fetchmany_is_traced(self): self.assertIsNone(fetchmany_span.get_tag("sql.query")) self.assertEqual(fetchmany_span.get_tag("db.system"), "sqlite") - def test_sqlite_ot(self): - """Ensure sqlite works with the opentracer.""" - ot_tracer = init_tracer("sqlite_svc", self.tracer) - - # Ensure we can run a query and it's correctly traced - q = "select * from sqlite_master" - with ot_tracer.start_active_span("sqlite_op"): - db = sqlite3.connect(":memory:") - pin = Pin.get_from(db) - assert pin - pin._clone(tracer=self.tracer).onto(db) - cursor = db.execute(q) - rows = cursor.fetchall() - assert not rows - - self.assert_structure( - dict(name="sqlite_op", service="sqlite_svc"), - (dict(name="sqlite.query", service="sqlite", span_type="sql", resource=q, error=0),), - ) - assert_is_measured(self.get_spans()[1]) - self.reset() - - with self.override_config("sqlite", dict(trace_fetch_methods=True)): - with ot_tracer.start_active_span("sqlite_op"): - db = sqlite3.connect(":memory:") - pin = Pin.get_from(db) - assert pin - pin._clone(tracer=self.tracer).onto(db) - cursor = db.execute(q) - rows = cursor.fetchall() - assert not rows - - self.assert_structure( - dict(name="sqlite_op", service="sqlite_svc"), - ( - dict(name="sqlite.query", span_type="sql", resource=q, error=0), - dict(name="sqlite.query.fetchall", span_type="sql", resource=q, error=0), - ), - ) - assert_is_measured(self.get_spans()[1]) - def test_commit(self): connection = self._given_a_traced_connection(self.tracer) connection.commit() diff --git a/tests/contrib/suitespec.yml b/tests/contrib/suitespec.yml index d3ac8289e95..35e712500fa 100644 --- a/tests/contrib/suitespec.yml +++ b/tests/contrib/suitespec.yml @@ -908,15 +908,6 @@ suites: - tests/snapshots/tests.opentelemetry.* runner: riot snapshot: true - opentracer: - parallelism: 1 - paths: - - '@bootstrap' - - '@core' - - '@tracing' - - '@opentracer' - - tests/opentracer/* - runner: riot protobuf: parallelism: 1 paths: diff --git a/tests/contrib/tornado/test_tornado_web.py b/tests/contrib/tornado/test_tornado_web.py index 642246aa244..cbb4d2c7785 100644 --- a/tests/contrib/tornado/test_tornado_web.py +++ b/tests/contrib/tornado/test_tornado_web.py @@ -1,6 +1,3 @@ -import pytest -import tornado - from ddtrace import config from ddtrace.constants import _ORIGIN_KEY from ddtrace.constants import _SAMPLING_PRIORITY_KEY @@ -8,7 +5,6 @@ from ddtrace.constants import USER_KEEP from ddtrace.ext import http from ddtrace.internal.schema import DEFAULT_SPAN_SERVICE_NAME -from tests.opentracer.utils import init_tracer from tests.tracer.utils_inferred_spans.test_helpers import assert_web_and_inferred_aws_api_gateway_span_data from tests.utils import assert_is_measured from tests.utils import assert_span_http_status_code @@ -385,46 +381,6 @@ def test_propagation(self): assert request_span.get_tag("component") == "tornado" assert request_span.get_tag("span.kind") == "server" - # Opentracing support depends on new AsyncioScopeManager - # See: https://github.com/opentracing/opentracing-python/pull/118 - @pytest.mark.skipif( - tornado.version_info >= (5, 0), reason="Opentracing ScopeManager not available for Tornado >= 5" - ) - def test_success_handler_ot(self): - """OpenTracing version of test_success_handler.""" - from opentracing.scope_managers.tornado import TornadoScopeManager - - ot_tracer = init_tracer("tornado_svc", self.tracer, scope_manager=TornadoScopeManager()) - - with ot_tracer.start_active_span("tornado_op"): - response = self.fetch("/success/") - assert 200 == response.code - - traces = self.pop_traces() - assert 1 == len(traces) - assert 2 == len(traces[0]) - # dd_span will start and stop before the ot_span finishes - ot_span, dd_span = traces[0] - - # confirm the parenting - assert ot_span.parent_id is None - assert dd_span.parent_id == ot_span.span_id - - assert ot_span.name == "tornado_op" - assert ot_span.service == "tornado_svc" - - assert_is_measured(dd_span) - assert "tornado-web" == dd_span.service - assert "tornado.request" == dd_span.name - assert "web" == dd_span.span_type - assert "tests.contrib.tornado.web.app.SuccessHandler" == dd_span.resource - assert "GET" == dd_span.get_tag("http.method") - assert_span_http_status_code(dd_span, 200) - assert self.get_url("/success/") == dd_span.get_tag(http.URL) - assert 0 == dd_span.error - assert dd_span.get_tag("component") == "tornado" - assert dd_span.get_tag("span.kind") == "server" - class TestNoPropagationTornadoWebViaSetting(TornadoTestCase): """ diff --git a/tests/contrib/urllib3/test_urllib3.py b/tests/contrib/urllib3/test_urllib3.py index 01d3b87893c..c1a6434c0bc 100644 --- a/tests/contrib/urllib3/test_urllib3.py +++ b/tests/contrib/urllib3/test_urllib3.py @@ -14,7 +14,6 @@ from ddtrace.internal.schema import DEFAULT_SPAN_SERVICE_NAME from ddtrace.settings.asm import config as asm_config from tests.contrib.config import HTTPBIN_CONFIG -from tests.opentracer.utils import init_tracer from tests.utils import TracerTestCase from tests.utils import snapshot @@ -399,34 +398,6 @@ def test_split_by_domain_includes_port(self): assert s.error == 1 assert s.service == "httpbin.org:8000" - def test_200_ot(self): - """OpenTracing version of test_200.""" - - ot_tracer = init_tracer("urllib3_svc", self.tracer) - - with ot_tracer.start_active_span("urllib3_get"): - out = self.http.request("GET", URL_200) - assert out.status == 200 - - spans = self.pop_spans() - assert len(spans) == 2 - - ot_span, dd_span = spans - - # confirm the parenting - assert ot_span.parent_id is None - assert dd_span.parent_id == ot_span.span_id - - assert ot_span.name == "urllib3_get" - assert ot_span.service == "urllib3_svc" - - assert dd_span.get_tag(http.METHOD) == "GET" - assert dd_span.get_tag(http.STATUS_CODE) == "200" - assert dd_span.get_tag("component") == "urllib3" - assert dd_span.get_tag("span.kind") == "client" - assert dd_span.error == 0 - assert dd_span.span_type == "http" - def test_request_and_response_headers(self): """Tests the headers are added as tag when the headers are whitelisted""" self.http.request("GET", URL_200, headers={"my-header": "my_value"}) diff --git a/tests/contrib/valkey/test_valkey.py b/tests/contrib/valkey/test_valkey.py index 867f435939e..447ae932771 100644 --- a/tests/contrib/valkey/test_valkey.py +++ b/tests/contrib/valkey/test_valkey.py @@ -4,12 +4,10 @@ import pytest import valkey -import ddtrace from ddtrace._trace.pin import Pin from ddtrace.contrib.internal.valkey.patch import patch from ddtrace.contrib.internal.valkey.patch import unpatch from ddtrace.internal.schema import DEFAULT_SPAN_SERVICE_NAME -from tests.opentracer.utils import init_tracer from tests.utils import DummyTracer from tests.utils import TracerTestCase from tests.utils import snapshot @@ -238,39 +236,6 @@ def test_patch_unpatch(self): assert spans, spans assert len(spans) == 1 - def test_opentracing(self): - """Ensure OpenTracing works with valkey.""" - ot_tracer = init_tracer("valkey_svc", self.tracer) - - with ot_tracer.start_active_span("valkey_get"): - us = self.r.get("cheese") - assert us is None - - spans = self.get_spans() - assert len(spans) == 2 - ot_span, dd_span = spans - - # confirm the parenting - assert ot_span.parent_id is None - assert dd_span.parent_id == ot_span.span_id - - assert ot_span.name == "valkey_get" - assert ot_span.service == "valkey_svc" - - self.assert_is_measured(dd_span) - assert dd_span.service == "valkey" - assert dd_span.name == "valkey.command" - assert dd_span.span_type == "valkey" - assert dd_span.error == 0 - assert dd_span.get_metric("out.valkey_db") == 0 - assert dd_span.get_tag("out.host") == "localhost" - assert dd_span.get_tag("valkey.raw_command") == "GET cheese" - assert dd_span.get_tag("component") == "valkey" - assert dd_span.get_tag("span.kind") == "client" - assert dd_span.get_tag("db.system") == "valkey" - assert dd_span.get_metric("valkey.args_length") == 2 - assert dd_span.resource == "GET" - def test_valkey_rowcount_all_keys_valid(self): self.r.set("key1", "value1") @@ -540,15 +505,6 @@ def test_patch_unpatch(self): assert spans, spans assert len(spans) == 1 - @snapshot() - def test_opentracing(self): - """Ensure OpenTracing works with valkey.""" - ot_tracer = init_tracer("valkey_svc", ddtrace.tracer) - - with ot_tracer.start_active_span("valkey_get"): - us = self.r.get("cheese") - assert us is None - @TracerTestCase.run_in_subprocess(env_overrides=dict(DD_SERVICE="mysvc")) @snapshot() def test_user_specified_service(self): diff --git a/tests/contrib/vertica/test_vertica.py b/tests/contrib/vertica/test_vertica.py index c65b19dd0fd..07c640965ee 100644 --- a/tests/contrib/vertica/test_vertica.py +++ b/tests/contrib/vertica/test_vertica.py @@ -12,7 +12,6 @@ from ddtrace.internal.schema import DEFAULT_SPAN_SERVICE_NAME from ddtrace.settings._config import _deepmerge from tests.contrib.config import VERTICA_CONFIG -from tests.opentracer.utils import init_tracer from tests.utils import DummyTracer from tests.utils import TracerTestCase from tests.utils import assert_is_measured @@ -367,37 +366,6 @@ def test_copy(self): assert spans[1].name == "vertica.query" assert spans[1].resource == "COMMIT;" - def test_opentracing(self): - """Ensure OpenTracing works with vertica.""" - conn, cur = self.test_conn - - ot_tracer = init_tracer("vertica_svc", self.test_tracer) - - with ot_tracer.start_active_span("vertica_execute"): - cur.execute("INSERT INTO {} (a, b) VALUES (1, 'aa');".format(TEST_TABLE)) - conn.close() - - spans = self.test_tracer.pop() - assert len(spans) == 2 - ot_span, dd_span = spans - - # confirm the parenting - assert ot_span.parent_id is None - assert dd_span.parent_id == ot_span.span_id - - assert_is_measured(dd_span) - assert dd_span.service == "vertica" - assert dd_span.span_type == "sql" - assert dd_span.name == "vertica.query" - assert dd_span.get_metric("db.row_count") == -1 - query = "INSERT INTO test_table (a, b) VALUES (1, 'aa');" - assert dd_span.resource == query - assert dd_span.get_tag("out.host") == "127.0.0.1" - assert dd_span.get_tag("span.kind") == "client" - assert dd_span.get_metric("network.destination.port") == 5433 - assert dd_span.get_tag("db.system") == "vertica" - assert dd_span.get_tag("component") == "vertica" - @TracerTestCase.run_in_subprocess(env_overrides=dict(DD_SERVICE="mysvc"), use_pytest=True) @pytest.mark.usefixtures("test_tracer", "test_conn") def test_user_specified_service_default(self): diff --git a/tests/contrib/yaaredis/test_yaaredis.py b/tests/contrib/yaaredis/test_yaaredis.py index fd9fb02c0f4..04ebc8d8709 100644 --- a/tests/contrib/yaaredis/test_yaaredis.py +++ b/tests/contrib/yaaredis/test_yaaredis.py @@ -9,7 +9,6 @@ from ddtrace._trace.pin import Pin from ddtrace.contrib.internal.yaaredis.patch import patch from ddtrace.contrib.internal.yaaredis.patch import unpatch -from tests.opentracer.utils import init_tracer from tests.utils import override_config from ..config import REDIS_CONFIG @@ -149,18 +148,6 @@ async def test_service_name_config(tracer, test_spans, traced_yaaredis): assert test_spans.spans[0].service == service -@pytest.mark.asyncio -async def test_opentracing(tracer, snapshot_context, traced_yaaredis): - """Ensure OpenTracing works with redis.""" - - with snapshot_context(): - pin = Pin.get_from(traced_yaaredis) - ot_tracer = init_tracer("redis_svc", pin.tracer) - - with ot_tracer.start_active_span("redis_get"): - await traced_yaaredis.get("cheese") - - @pytest.mark.parametrize( "service_schema", [ diff --git a/tests/opentracer/__init__.py b/tests/opentracer/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/tests/opentracer/conftest.py b/tests/opentracer/conftest.py deleted file mode 100644 index 09a4dad886c..00000000000 --- a/tests/opentracer/conftest.py +++ /dev/null @@ -1,60 +0,0 @@ -""" -pytest local plugin used to automatically make the following fixtures -available for all tests in this directory - -https://docs.pytest.org/en/latest/writing_plugins.html#testing-plugins -""" -import pytest - -from ddtrace.opentracer import Tracer as OTTracer -from ddtrace.opentracer import set_global_tracer -from tests.utils import DummyTracer -from tests.utils import TracerSpanContainer - - -@pytest.fixture() -def ot_tracer_factory(): - """Fixture which returns an opentracer ready to use for testing.""" - - def make_ot_tracer(service_name="my_svc", config=None, scope_manager=None, context_provider=None): - config = config or {} - tracer = OTTracer(service_name=service_name, config=config, scope_manager=scope_manager) - - # similar to how we test the ddtracer, use a dummy tracer - dd_tracer = DummyTracer() - if context_provider: - dd_tracer.context_provider = context_provider - - # attach the dummy tracer to the opentracer - tracer._dd_tracer = dd_tracer - return tracer - - return make_ot_tracer - - -@pytest.fixture() -def ot_tracer(ot_tracer_factory): - """Fixture for a default opentracer.""" - return ot_tracer_factory() - - -@pytest.fixture -def test_spans(ot_tracer): - container = TracerSpanContainer(ot_tracer._dd_tracer) - yield container - container.reset() - - -@pytest.fixture() -def global_tracer(ot_tracer): - """A function similar to one OpenTracing users would write to initialize - their OpenTracing tracer. - """ - set_global_tracer(ot_tracer) - - return ot_tracer - - -@pytest.fixture() -def dd_tracer(ot_tracer): - return ot_tracer._dd_tracer diff --git a/tests/opentracer/core/__init__.py b/tests/opentracer/core/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/tests/opentracer/core/test_dd_compatibility.py b/tests/opentracer/core/test_dd_compatibility.py deleted file mode 100644 index c68b5ca6d6c..00000000000 --- a/tests/opentracer/core/test_dd_compatibility.py +++ /dev/null @@ -1,180 +0,0 @@ -import opentracing -from opentracing import Format - -import ddtrace -from ddtrace.opentracer.span_context import SpanContext - - -class TestTracerCompatibility(object): - """Ensure that our opentracer produces results in the underlying ddtracer.""" - - def test_ottracer_uses_global_ddtracer(self): - """Ensure that the opentracer will by default use the global ddtracer - as its underlying Datadog tracer. - """ - tracer = ddtrace.opentracer.Tracer() - assert tracer._dd_tracer is ddtrace.tracer - - def test_ot_dd_global_tracers(self, global_tracer): - """Ensure our test function opentracer_init() prep""" - ot_tracer = global_tracer - dd_tracer = global_tracer._dd_tracer - - # check all the global references - assert ot_tracer is opentracing.tracer - assert ot_tracer._dd_tracer is dd_tracer - assert dd_tracer is ddtrace.tracer - - def test_ot_dd_nested_trace(self, ot_tracer, dd_tracer, test_spans): - """Ensure intertwined usage of the opentracer and ddtracer.""" - - with ot_tracer.start_span("my_ot_span") as ot_span: - with dd_tracer.trace("my_dd_span") as dd_span: - pass - spans = test_spans.pop() - assert len(spans) == 2 - - # confirm the ordering - assert spans[1] is ot_span._dd_span - assert spans[0] is dd_span - - # check the parenting - assert spans[0].parent_id is None - assert spans[1].parent_id is None - - def test_dd_ot_nested_trace(self, ot_tracer, dd_tracer, test_spans): - """Ensure intertwined usage of the opentracer and ddtracer.""" - with dd_tracer.trace("my_dd_span") as dd_span: - with ot_tracer.start_span("my_ot_span") as ot_span: - pass - spans = test_spans.pop() - assert len(spans) == 2 - - # confirm the ordering - assert spans[0] is dd_span - assert spans[1] is ot_span._dd_span - - # check the parenting - assert spans[0].parent_id is None - assert spans[1].parent_id is spans[0].span_id - - def test_ot_dd_ot_dd_nested_trace(self, ot_tracer, dd_tracer, test_spans): - """Ensure intertwined usage of the opentracer and ddtracer.""" - with ot_tracer.start_active_span("ot_span") as ot_scope: - with dd_tracer.trace("dd_span") as dd_span: - with ot_tracer.start_active_span("ot_span2") as ot_scope2: - with dd_tracer.trace("dd_span2") as dd_span2: - pass - - spans = test_spans.pop() - assert len(spans) == 4 - - spans = {span.name: span for span in spans} - assert spans["ot_span"] == ot_scope.span._dd_span - assert spans["dd_span"] == dd_span - assert spans["ot_span2"] == ot_scope2.span._dd_span - assert spans["dd_span2"] == dd_span2 - - # check the parenting - assert spans["ot_span"].parent_id is None - assert spans["dd_span"].parent_id is spans["ot_span"].span_id - assert spans["ot_span2"].parent_id is spans["dd_span"].span_id - assert spans["dd_span2"].parent_id is spans["ot_span2"].span_id - - def test_ot_ot_dd_ot_dd_nested_trace_active(self, ot_tracer, dd_tracer, test_spans): - """Ensure intertwined usage of the opentracer and ddtracer.""" - with ot_tracer.start_active_span("my_ot_span") as ot_scope: - with ot_tracer.start_active_span("my_ot_span") as ot_scope2: - with dd_tracer.trace("my_dd_span") as dd_span: - with ot_tracer.start_active_span("my_ot_span") as ot_scope3: - with dd_tracer.trace("my_dd_span") as dd_span2: - pass - - spans = test_spans.pop() - assert len(spans) == 5 - - # confirm the ordering - assert spans[0] is ot_scope.span._dd_span - assert spans[1] is ot_scope2.span._dd_span - assert spans[2] is dd_span - assert spans[3] is ot_scope3.span._dd_span - assert spans[4] is dd_span2 - - # check the parenting - assert spans[0].parent_id is None - assert spans[1].parent_id == spans[0].span_id - assert spans[2].parent_id == spans[1].span_id - assert spans[3].parent_id == spans[2].span_id - assert spans[4].parent_id == spans[3].span_id - - def test_consecutive_trace(self, ot_tracer, dd_tracer, test_spans): - """Ensure consecutive usage of the opentracer and ddtracer.""" - with ot_tracer.start_active_span("my_ot_span") as ot_scope: - pass - - with dd_tracer.trace("my_dd_span") as dd_span: - pass - - with ot_tracer.start_active_span("my_ot_span") as ot_scope2: - pass - - with dd_tracer.trace("my_dd_span") as dd_span2: - pass - - spans = test_spans.pop() - assert len(spans) == 4 - - # confirm the ordering - assert spans[0] is ot_scope.span._dd_span - assert spans[1] is dd_span - assert spans[2] is ot_scope2.span._dd_span - assert spans[3] is dd_span2 - - # check the parenting - assert spans[0].parent_id is None - assert spans[1].parent_id is None - assert spans[2].parent_id is None - assert spans[3].parent_id is None - - def test_ddtrace_wrapped_fn(self, ot_tracer, dd_tracer, test_spans): - """Ensure ddtrace wrapped functions work with the opentracer""" - - @dd_tracer.wrap() - def fn(): - with ot_tracer.start_span("ot_span_inner"): - pass - - with ot_tracer.start_active_span("ot_span_outer"): - fn() - - spans = test_spans.pop() - assert len(spans) == 3 - - # confirm the ordering - assert spans[0].name == "ot_span_outer" - assert spans[1].name == "tests.opentracer.core.test_dd_compatibility.fn" - assert spans[2].name == "ot_span_inner" - - # check the parenting - assert spans[0].parent_id is None - assert spans[1].parent_id is spans[0].span_id - assert spans[2].parent_id is spans[1].span_id - - def test_distributed_trace_propagation(self, ot_tracer, dd_tracer, test_spans): - """Ensure that a propagated span context is properly activated.""" - span_ctx = SpanContext(trace_id=123, span_id=456) - carrier = {} - ot_tracer.inject(span_ctx, Format.HTTP_HEADERS, carrier) - - # extract should activate the span so that a subsequent start_span - # will inherit from the propagated span context - ot_tracer.extract(Format.HTTP_HEADERS, carrier) - - with dd_tracer.trace("test") as span: - pass - - assert span.parent_id == 456 - assert span.trace_id == 123 - - spans = test_spans.pop() - assert len(spans) == 1 diff --git a/tests/opentracer/core/test_span.py b/tests/opentracer/core/test_span.py deleted file mode 100644 index ea2fc3bbbc1..00000000000 --- a/tests/opentracer/core/test_span.py +++ /dev/null @@ -1,163 +0,0 @@ -import pytest - -from ddtrace.opentracer.span import Span -from tests.utils import DummyTracer - - -@pytest.fixture -def nop_tracer(): - from ddtrace.opentracer import Tracer - - tracer = Tracer(service_name="mysvc", config={}) - # use the same test tracer used by the primary tests - tracer._tracer = DummyTracer() - return tracer - - -@pytest.fixture -def nop_span_ctx(): - from ddtrace.constants import AUTO_KEEP - from ddtrace.opentracer.span_context import SpanContext - - return SpanContext(sampling_priority=AUTO_KEEP) - - -@pytest.fixture -def nop_span(nop_tracer, nop_span_ctx): - return Span(nop_tracer, nop_span_ctx, "my_op_name") - - -class TestSpan(object): - """Test the Datadog OpenTracing Span implementation.""" - - def test_init(self, nop_tracer, nop_span_ctx): - """Very basic test for skeleton code""" - span = Span(nop_tracer, nop_span_ctx, "my_op_name") - assert not span.finished - - def test_tags(self, nop_span): - """Set a tag and get it back.""" - r = nop_span.set_tag("test", 23) - assert nop_span._get_metric("test") == 23 - assert r is nop_span - - def test_set_baggage(self, nop_span): - """Test setting baggage.""" - r = nop_span.set_baggage_item("test", 23) - assert r is nop_span - - r = nop_span.set_baggage_item("1", 1).set_baggage_item("2", 2) - assert r is nop_span - - def test_get_baggage(self, nop_span): - """Test setting and getting baggage.""" - # test a single item - nop_span.set_baggage_item("test", 23) - assert int(nop_span.get_baggage_item("test")) == 23 - - # test multiple items - nop_span.set_baggage_item("1", "1").set_baggage_item("2", 2) - assert int(nop_span.get_baggage_item("test")) == 23 - assert nop_span.get_baggage_item("1") == "1" - assert int(nop_span.get_baggage_item("2")) == 2 - - def test_log_kv(self, nop_span): - """Ensure logging values doesn't break anything.""" - # just log a bunch of values - nop_span.log_kv({"myval": 2}) - nop_span.log_kv({"myval2": 3}) - nop_span.log_kv({"myval3": 5}) - nop_span.log_kv({"myval": 2}) - - def test_log_dd_kv(self, nop_span): - """Ensure keys that can be handled by our impl. are indeed handled.""" - import traceback - - from ddtrace.constants import ERROR_MSG - from ddtrace.constants import ERROR_STACK - from ddtrace.constants import ERROR_TYPE - - stack_trace = str(traceback.format_stack()) - nop_span.log_kv( - { - "event": "error", - "error": 3, - "message": "my error message", - "stack": stack_trace, - } - ) - - # Ensure error flag is set... - assert nop_span._dd_span.error - # ...and that error tags are set with the correct key - assert nop_span._get_tag(ERROR_STACK) == stack_trace - assert nop_span._get_tag(ERROR_MSG) == "my error message" - assert nop_span._get_metric(ERROR_TYPE) == 3 - - def test_operation_name(self, nop_span): - """Sanity check for setting the operation name.""" - # just try setting the operation name - r = nop_span.set_operation_name("new_op_name") - assert nop_span._dd_span.name == "new_op_name" - assert r is nop_span - - def test_context_manager(self, nop_span): - """Test the span context manager.""" - import time - - assert not nop_span.finished - # run the context manager but since the span has not been added - # to the span context, we will not get any traces - with nop_span: - time.sleep(0.005) - - # span should be finished when the context manager exits - assert nop_span.finished - - # there should be no traces (see above comment) - spans = nop_span.tracer._tracer.pop() - assert len(spans) == 0 - - def test_immutable_span_context(self, nop_span): - """Ensure span contexts are immutable.""" - before_ctx = nop_span._context - nop_span.set_baggage_item("key", "value") - after_ctx = nop_span._context - # should be different contexts - assert before_ctx is not after_ctx - - -class TestSpanCompatibility(object): - """Ensure our opentracer spans features correspond to datadog span features.""" - - def test_set_tag(self, nop_span): - nop_span.set_tag("test", 2) - assert nop_span._get_metric("test") == 2 - - def test_tag_resource_name(self, nop_span): - nop_span.set_tag("resource.name", "myresource") - assert nop_span._dd_span.resource == "myresource" - - def test_tag_span_type(self, nop_span): - nop_span.set_tag("span.type", "db") - assert nop_span._dd_span.span_type == "db" - - def test_tag_service_name(self, nop_span): - nop_span.set_tag("service.name", "mysvc234") - assert nop_span._dd_span.service == "mysvc234" - - def test_tag_db_statement(self, nop_span): - nop_span.set_tag("db.statement", "SELECT * FROM USERS") - assert nop_span._dd_span.resource == "SELECT * FROM USERS" - - def test_tag_peer_hostname(self, nop_span): - nop_span.set_tag("peer.hostname", "peername") - assert nop_span._dd_span.get_tag("out.host") == "peername" - - def test_tag_peer_port(self, nop_span): - nop_span.set_tag("peer.port", 55555) - assert nop_span._get_metric("network.destination.port") == 55555 - - def test_tag_sampling_priority(self, nop_span): - nop_span.set_tag("sampling.priority", "2") - assert nop_span._dd_span.context.sampling_priority == "2" diff --git a/tests/opentracer/core/test_span_context.py b/tests/opentracer/core/test_span_context.py deleted file mode 100644 index 2c7038fe327..00000000000 --- a/tests/opentracer/core/test_span_context.py +++ /dev/null @@ -1,38 +0,0 @@ -from ddtrace.opentracer.span_context import SpanContext - - -class TestSpanContext(object): - def test_init(self): - """Make sure span context creation is fine.""" - span_ctx = SpanContext() - assert span_ctx - - def test_baggage(self): - """Ensure baggage passed is the resulting baggage of the span context.""" - baggage = { - "some": "stuff", - } - - span_ctx = SpanContext(baggage=baggage) - - assert span_ctx.baggage == baggage - - def test_with_baggage_item(self): - """Should allow immutable extension of new span contexts.""" - baggage = { - "1": 1, - } - - first_ctx = SpanContext(baggage=baggage) - - second_ctx = first_ctx.with_baggage_item("2", 2) - - assert "2" not in first_ctx.baggage - assert second_ctx.baggage is not first_ctx.baggage - - def test_span_context_immutable_baggage(self): - """Ensure that two different span contexts do not share baggage.""" - ctx1 = SpanContext() - ctx1.set_baggage_item("test", 3) - ctx2 = SpanContext() - assert "test" not in ctx2._baggage diff --git a/tests/opentracer/core/test_tracer.py b/tests/opentracer/core/test_tracer.py deleted file mode 100644 index 5d9f11ab74f..00000000000 --- a/tests/opentracer/core/test_tracer.py +++ /dev/null @@ -1,585 +0,0 @@ -import time - -import mock -import opentracing -from opentracing import Format -from opentracing import InvalidCarrierException -from opentracing import UnsupportedFormatException -from opentracing import child_of -import pytest - -import ddtrace -from ddtrace.constants import AUTO_KEEP -from ddtrace.opentracer import Tracer -from ddtrace.opentracer import set_global_tracer -from ddtrace.opentracer.span_context import SpanContext -from ddtrace.propagation.http import HTTP_HEADER_TRACE_ID -from ddtrace.settings.exceptions import ConfigException - - -class TestTracerConfig(object): - def test_config(self): - """Test the configuration of the tracer""" - config = {"enabled": True} - tracer = Tracer(service_name="myservice", config=config) - - assert tracer._service_name == "myservice" - assert tracer._dd_tracer.enabled is True - - def test_no_service_name(self): - """A service_name should be generated if one is not provided.""" - tracer = Tracer() - assert tracer._service_name in {"pytest.py", "pytest", "__main__.py"} - - def test_multiple_tracer_configs(self): - """Ensure that a tracer config is a copy of the passed config.""" - config = {"enabled": True} - - tracer1 = Tracer(service_name="serv1", config=config) - assert tracer1._service_name == "serv1" - - config["enabled"] = False - tracer2 = Tracer(service_name="serv2", config=config) - - # Ensure tracer1's config was not mutated - assert tracer1._service_name == "serv1" - assert tracer2._service_name == "serv2" - - def test_invalid_config_key(self): - """A config with an invalid key should raise a ConfigException.""" - - config = {"enabeld": False} # codespell:ignore - - # No debug flag should not raise an error - tracer = Tracer(service_name="mysvc", config=config) - - # With debug flag should raise an error - config["debug"] = True - with pytest.raises(ConfigException) as ce_info: - tracer = Tracer(config=config) - assert "enabeld" in str(ce_info) # codespell:ignore - assert tracer is not None - - # Test with multiple incorrect keys - config["setttings"] = {} - with pytest.raises(ConfigException) as ce_info: - tracer = Tracer(service_name="mysvc", config=config) - assert ["enabeld", "setttings"] in str(ce_info) # codespell:ignore - assert tracer is not None - - def test_global_tags(self): - """Global tags should be passed from the opentracer to the tracer.""" - config = { - "global_tags": { - "tag1": "value1", - "tag2": 2, - }, - } - - tracer = Tracer(service_name="mysvc", config=config) - with tracer.start_span("myop") as span: - # global tags should be attached to generated all datadog spans - assert span._dd_span.get_tag("tag1") == "value1" - assert span._dd_span.get_metric("tag2") == 2 - - with tracer.start_span("myop2") as span2: - assert span2._dd_span.get_tag("tag1") == "value1" - assert span2._dd_span.get_metric("tag2") == 2 - - -class TestTracer(object): - def test_start_span(self, ot_tracer, test_spans): - """Start and finish a span.""" - with ot_tracer.start_span("myop") as span: - pass - - # span should be finished when the context manager exits - assert span.finished - - spans = test_spans.get_spans() - assert len(spans) == 1 - - def test_start_span_references(self, ot_tracer, test_spans): - """Start a span using references.""" - - with ot_tracer.start_span("one", references=[child_of()]): - pass - - spans = test_spans.pop() - assert spans[0].parent_id is None - - root = ot_tracer.start_active_span("root") - # create a child using a parent reference that is not the context parent - with ot_tracer.start_active_span("one"): - with ot_tracer.start_active_span("two", references=[child_of(root.span)]): - pass - root.close() - - spans = test_spans.pop() - assert spans[1].parent_id == spans[0].span_id - assert spans[2].parent_id == spans[0].span_id - - def test_start_span_custom_start_time(self, ot_tracer): - """Start a span with a custom start time.""" - t = 100 - with mock.patch("ddtrace._trace.span.Time.time_ns") as time: - time.return_value = 102 * 1e9 - with ot_tracer.start_span("myop", start_time=t) as span: - pass - - assert span._dd_span.start == t - assert span._dd_span.duration == 2 - - def test_start_span_with_spancontext(self, ot_tracer, test_spans): - """Start and finish a span using a span context as the child_of - reference. - """ - with ot_tracer.start_span("myop") as span: - with ot_tracer.start_span("myop", child_of=span.context) as span2: - pass - - # span should be finished when the context manager exits - assert span.finished - assert span2.finished - - spans = test_spans.pop() - assert len(spans) == 2 - - # ensure proper parenting - assert spans[1].parent_id is spans[0].span_id - - def test_start_span_with_tags(self, ot_tracer): - """Create a span with initial tags.""" - tags = {"key": "value", "key2": "value2"} - with ot_tracer.start_span("myop", tags=tags) as span: - pass - - assert span._dd_span.get_tag("key") == "value" - assert span._dd_span.get_tag("key2") == "value2" - - def test_start_span_with_resource_name_tag(self, ot_tracer): - """Create a span with the tag to set the resource name""" - tags = {"resource.name": "value", "key2": "value2"} - with ot_tracer.start_span("myop", tags=tags) as span: - pass - - # Span resource name should be set to tag value, and should not get set as - # a tag on the underlying span. - assert span._dd_span.resource == "value" - assert span._dd_span.get_tag("resource.name") is None - - # Other tags are set as normal - assert span._dd_span.get_tag("key2") == "value2" - - def test_start_active_span_multi_child(self, ot_tracer, test_spans): - """Start and finish multiple child spans. - This should ensure that child spans can be created 2 levels deep. - """ - with ot_tracer.start_active_span("myfirstop") as scope1: - time.sleep(0.009) - with ot_tracer.start_active_span("mysecondop") as scope2: - time.sleep(0.007) - with ot_tracer.start_active_span("mythirdop") as scope3: - time.sleep(0.005) - - # spans should be finished when the context manager exits - assert scope1.span.finished - assert scope2.span.finished - assert scope3.span.finished - - spans = test_spans.pop() - - # check spans are captured in the trace - assert scope1.span._dd_span is spans[0] - assert scope2.span._dd_span is spans[1] - assert scope3.span._dd_span is spans[2] - - # ensure proper parenting - assert spans[1].parent_id is spans[0].span_id - assert spans[2].parent_id is spans[1].span_id - - # sanity check a lower bound on the durations - assert spans[0].duration >= 0.009 + 0.007 + 0.005 - assert spans[1].duration >= 0.007 + 0.005 - assert spans[2].duration >= 0.005 - - def test_start_active_span_multi_child_siblings(self, ot_tracer, test_spans): - """Start and finish multiple span at the same level. - This should test to ensure a parent can have multiple child spans at the - same level. - """ - with ot_tracer.start_active_span("myfirstop") as scope1: - time.sleep(0.009) - with ot_tracer.start_active_span("mysecondop") as scope2: - time.sleep(0.007) - with ot_tracer.start_active_span("mythirdop") as scope3: - time.sleep(0.005) - - # spans should be finished when the context manager exits - assert scope1.span.finished - assert scope2.span.finished - assert scope3.span.finished - - spans = test_spans.pop() - - # check spans are captured in the trace - assert scope1.span._dd_span is spans[0] - assert scope2.span._dd_span is spans[1] - assert scope3.span._dd_span is spans[2] - - # ensure proper parenting - assert spans[1].parent_id is spans[0].span_id - assert spans[2].parent_id is spans[0].span_id - - # sanity check a lower bound on the durations - assert spans[0].duration >= 0.009 + 0.007 + 0.005 - assert spans[1].duration >= 0.007 - assert spans[2].duration >= 0.005 - - def test_start_span_manual_child_of(self, ot_tracer, test_spans): - """Start spans without using a scope manager. - Spans should be created without parents since there will be no call - for the active span. - """ - root = ot_tracer.start_span("zero") - - with ot_tracer.start_span("one", child_of=root): - with ot_tracer.start_span("two", child_of=root): - with ot_tracer.start_span("three", child_of=root): - pass - root.finish() - - spans = test_spans.pop() - - assert spans[0].parent_id is None - # ensure each child span is a child of root - assert spans[1].parent_id is root._dd_span.span_id - assert spans[2].parent_id is root._dd_span.span_id - assert spans[3].parent_id is root._dd_span.span_id - assert spans[0].trace_id == spans[1].trace_id and spans[1].trace_id == spans[2].trace_id - - def test_start_span_no_active_span(self, ot_tracer, test_spans): - """Start spans without using a scope manager. - Spans should be created without parents since there will be no call - for the active span. - """ - with ot_tracer.start_span("one", ignore_active_span=True): - with ot_tracer.start_span("two", ignore_active_span=True): - pass - with ot_tracer.start_span("three", ignore_active_span=True): - pass - - spans = test_spans.pop() - - # ensure each span does not have a parent - assert spans[0].parent_id is None - assert spans[1].parent_id is None - assert spans[2].parent_id is None - # and that each span is a new trace - assert ( - spans[0].trace_id != spans[1].trace_id - and spans[1].trace_id != spans[2].trace_id - and spans[0].trace_id != spans[2].trace_id - ) - - def test_start_active_span_child_finish_after_parent(self, ot_tracer, test_spans): - """Start a child span and finish it after its parent.""" - span1 = ot_tracer.start_active_span("one").span - span2 = ot_tracer.start_active_span("two").span - span1.finish() - time.sleep(0.005) - span2.finish() - - spans = test_spans.pop() - assert len(spans) == 2 - assert spans[0].parent_id is None - assert spans[1].parent_id is span1._dd_span.span_id - assert spans[1].duration > spans[0].duration - - def test_start_span_multi_intertwined(self, ot_tracer, test_spans): - """Start multiple spans at the top level intertwined. - Alternate calling between two traces. - """ - import threading - - # synchronize threads with a threading event object - event = threading.Event() - - def trace_one(): - _id = 11 - with ot_tracer.start_active_span(str(_id)): - _id += 1 - with ot_tracer.start_active_span(str(_id)): - _id += 1 - with ot_tracer.start_active_span(str(_id)): - pass - event.set() - - def trace_two(): - _id = 21 - event.wait() - with ot_tracer.start_active_span(str(_id)): - _id += 1 - with ot_tracer.start_active_span(str(_id)): - _id += 1 - with ot_tracer.start_active_span(str(_id)): - pass - - # the ordering should be - # t1.span1/t2.span1, t2.span2, t1.span2, t1.span3, t2.span3 - t1 = threading.Thread(target=trace_one) - t2 = threading.Thread(target=trace_two) - - t1.start() - t2.start() - # wait for threads to finish - t1.join() - t2.join() - - spans = test_spans.pop() - - # trace_one will finish before trace_two so its spans should be written - # before the spans from trace_two, let's confirm this - assert spans[0].name == "11" - assert spans[1].name == "12" - assert spans[2].name == "13" - assert spans[3].name == "21" - assert spans[4].name == "22" - assert spans[5].name == "23" - - # next let's ensure that each span has the correct parent: - # trace_one - assert spans[0].parent_id is None - assert spans[1].parent_id is spans[0].span_id - assert spans[2].parent_id is spans[1].span_id - # trace_two - assert spans[3].parent_id is None - assert spans[4].parent_id is spans[3].span_id - assert spans[5].parent_id is spans[3].span_id - - # finally we should ensure that the trace_ids are reasonable - # trace_one - assert spans[0].trace_id == spans[1].trace_id and spans[1].trace_id == spans[2].trace_id - # traces should be independent - assert spans[2].trace_id != spans[3].trace_id - # trace_two - assert spans[3].trace_id == spans[4].trace_id and spans[4].trace_id == spans[5].trace_id - - def test_start_active_span(self, ot_tracer, test_spans): - with ot_tracer.start_active_span("one") as scope: - pass - - assert scope.span._dd_span.name == "one" - assert scope.span.finished - spans = test_spans.pop() - assert spans - - def test_start_active_span_finish_on_close(self, ot_tracer, test_spans): - with ot_tracer.start_active_span("one", finish_on_close=False) as scope: - pass - - assert scope.span._dd_span.name == "one" - assert not scope.span.finished - spans = test_spans.pop() - assert not spans - scope.span.finish() - - def test_start_active_span_nested(self, ot_tracer): - """Test the active span of multiple nested calls of start_active_span.""" - with ot_tracer.start_active_span("one") as outer_scope: - assert ot_tracer.active_span == outer_scope.span - with ot_tracer.start_active_span("two") as inner_scope: - assert ot_tracer.active_span == inner_scope.span - with ot_tracer.start_active_span("three") as innest_scope: # why isn't it innest? innermost so verbose - assert ot_tracer.active_span == innest_scope.span - with ot_tracer.start_active_span("two") as inner_scope: - assert ot_tracer.active_span == inner_scope.span - assert ot_tracer.active_span == outer_scope.span - assert ot_tracer.active_span is None - - def test_start_active_span_trace(self, ot_tracer, test_spans): - """Test the active span of multiple nested calls of start_active_span.""" - with ot_tracer.start_active_span("one") as outer_scope: - outer_scope.span.set_tag("outer", 2) - with ot_tracer.start_active_span("two") as inner_scope: - inner_scope.span.set_tag("inner", 3) - with ot_tracer.start_active_span("two") as inner_scope: - inner_scope.span.set_tag("inner", 3) - with ot_tracer.start_active_span("three") as innest_scope: - innest_scope.span.set_tag("innerest", 4) - - spans = test_spans.pop() - - assert spans[0].parent_id is None - assert spans[1].parent_id is spans[0].span_id - assert spans[2].parent_id is spans[0].span_id - assert spans[3].parent_id is spans[2].span_id - - def test_interleave(self, dd_tracer, ot_tracer, test_spans): - with ot_tracer.start_active_span("ot_root_1", ignore_active_span=True): - with dd_tracer.trace("dd_child"): - with ot_tracer.start_active_span("ot_child_1"): - pass - with ot_tracer.start_active_span("ot_child_2"): - pass - - spans = test_spans.pop() - assert len(spans) == 4 - assert spans[0].name == "ot_root_1" and spans[0].parent_id is None - assert spans[1].name == "dd_child" and spans[1].parent_id == spans[0].span_id - assert spans[2].name == "ot_child_1" and spans[2].parent_id == spans[1].span_id - assert spans[3].name == "ot_child_2" and spans[3].parent_id == spans[0].span_id - - def test_active_span(self, ot_tracer, test_spans): - with ot_tracer._dd_tracer.trace("dd") as span: - assert ot_tracer.active_span is not None - assert ot_tracer.active_span._dd_span is span - - -@pytest.fixture -def nop_span_ctx(): - return SpanContext(sampling_priority=AUTO_KEEP) - - -class TestTracerSpanContextPropagation(object): - """Test the injection and extraction of a span context from a tracer.""" - - def test_invalid_format(self, ot_tracer, nop_span_ctx): - """An invalid format should raise an UnsupportedFormatException.""" - # test inject - with pytest.raises(UnsupportedFormatException): - ot_tracer.inject(nop_span_ctx, None, {}) - - # test extract - with pytest.raises(UnsupportedFormatException): - ot_tracer.extract(None, {}) - - def test_inject_invalid_carrier(self, ot_tracer, nop_span_ctx): - """Only dicts should be supported as a carrier.""" - with pytest.raises(InvalidCarrierException): - ot_tracer.inject(nop_span_ctx, Format.HTTP_HEADERS, None) - - def test_extract_invalid_carrier(self, ot_tracer): - """Only dicts should be supported as a carrier.""" - with pytest.raises(InvalidCarrierException): - ot_tracer.extract(Format.HTTP_HEADERS, None) - - def test_http_headers_base(self, ot_tracer): - """extract should undo inject for http headers.""" - - span_ctx = SpanContext(trace_id=123, span_id=456) - carrier = {} - - ot_tracer.inject(span_ctx, Format.HTTP_HEADERS, carrier) - assert len(carrier.keys()) > 0 - - ext_span_ctx = ot_tracer.extract(Format.HTTP_HEADERS, carrier) - assert ext_span_ctx._dd_context.trace_id == 123 - assert ext_span_ctx._dd_context.span_id == 456 - - def test_http_headers_baggage(self, ot_tracer): - """extract should undo inject for http headers.""" - span_ctx = SpanContext(trace_id=123, span_id=456, baggage={"test": 4, "test2": "string"}) - carrier = {} - - ot_tracer.inject(span_ctx, Format.HTTP_HEADERS, carrier) - assert len(carrier.keys()) > 0 - - ext_span_ctx = ot_tracer.extract(Format.HTTP_HEADERS, carrier) - assert ext_span_ctx._dd_context.trace_id == 123 - assert ext_span_ctx._dd_context.span_id == 456 - assert ext_span_ctx.baggage == span_ctx.baggage - - def test_empty_propagated_context(self, ot_tracer): - """An empty propagated context should not raise a - SpanContextCorruptedException when extracted. - """ - carrier = {} - ot_tracer.extract(Format.HTTP_HEADERS, carrier) - - def test_text(self, ot_tracer): - """extract should undo inject for http headers""" - span_ctx = SpanContext(trace_id=123, span_id=456, baggage={"test": 4, "test2": "string"}) - carrier = {} - - ot_tracer.inject(span_ctx, Format.TEXT_MAP, carrier) - assert len(carrier.keys()) > 0 - - ext_span_ctx = ot_tracer.extract(Format.TEXT_MAP, carrier) - assert ext_span_ctx._dd_context.trace_id == 123 - assert ext_span_ctx._dd_context.span_id == 456 - assert ext_span_ctx.baggage == span_ctx.baggage - - def test_corrupted_propagated_context(self, ot_tracer): - """Corrupted context should raise a SpanContextCorruptedException.""" - span_ctx = SpanContext(trace_id=123, span_id=456, baggage={"test": 4, "test2": "string"}) - carrier = {} - - ot_tracer.inject(span_ctx, Format.TEXT_MAP, carrier) - assert len(carrier.keys()) > 0 - - # manually alter a key in the carrier baggage - del carrier[HTTP_HEADER_TRACE_ID] - corrupted_key = HTTP_HEADER_TRACE_ID[2:] - carrier[corrupted_key] = 123 - - ot_tracer.extract(Format.TEXT_MAP, carrier) - - def test_immutable_span_context(self, ot_tracer): - """Span contexts should be immutable.""" - with ot_tracer.start_span("root") as root: - ctx_before = root.context - root.set_baggage_item("test", 2) - assert ctx_before is not root.context - with ot_tracer.start_span("child") as level1: - with ot_tracer.start_span("child") as level2: - pass - assert root.context is not level1.context - assert level2.context is not level1.context - assert level2.context is not root.context - - def test_inherited_baggage(self, ot_tracer): - """Baggage should be inherited by child spans.""" - with ot_tracer.start_active_span("root") as root: - # this should be passed down to the child - root.span.set_baggage_item("root", 1) - root.span.set_baggage_item("root2", 1) - with ot_tracer.start_active_span("child") as level1: - level1.span.set_baggage_item("level1", 1) - with ot_tracer.start_active_span("child") as level2: - level2.span.set_baggage_item("level2", 1) - # ensure immutability - assert level1.span.context is not root.span.context - assert level2.span.context is not level1.span.context - - # level1 should have inherited the baggage of root - assert level1.span.get_baggage_item("root") - assert level1.span.get_baggage_item("root2") - - # level2 should have inherited the baggage of both level1 and level2 - assert level2.span.get_baggage_item("root") - assert level2.span.get_baggage_item("root2") - assert level2.span.get_baggage_item("level1") - assert level2.span.get_baggage_item("level2") - - -class TestTracerCompatibility(object): - """Ensure that our opentracer produces results in the underlying datadog tracer.""" - - def test_required_dd_fields(self): - """Ensure required fields needed for successful tracing are possessed - by the underlying datadog tracer. - """ - # a service name is required - tracer = Tracer("service") - with tracer.start_span("my_span") as span: - assert span._dd_span.service - - -def test_set_global_tracer(): - """Sanity check for set_global_tracer""" - my_tracer = Tracer("service") - set_global_tracer(my_tracer) - - assert opentracing.tracer is my_tracer - assert ddtrace.tracer is my_tracer._dd_tracer diff --git a/tests/opentracer/core/test_utils.py b/tests/opentracer/core/test_utils.py deleted file mode 100644 index 37c9e9dd305..00000000000 --- a/tests/opentracer/core/test_utils.py +++ /dev/null @@ -1,17 +0,0 @@ -from opentracing.scope_managers import ThreadLocalScopeManager -from opentracing.scope_managers.asyncio import AsyncioScopeManager - -import ddtrace -from ddtrace.opentracer.utils import get_context_provider_for_scope_manager - - -class TestOpentracerUtils(object): - def test_get_context_provider_for_scope_manager_thread(self): - scope_manager = ThreadLocalScopeManager() - ctx_prov = get_context_provider_for_scope_manager(scope_manager) - assert isinstance(ctx_prov, ddtrace._trace.provider.DefaultContextProvider) - - def test_get_context_provider_for_asyncio_scope_manager(self): - scope_manager = AsyncioScopeManager() - ctx_prov = get_context_provider_for_scope_manager(scope_manager) - assert isinstance(ctx_prov, ddtrace._trace.provider.DefaultContextProvider) diff --git a/tests/opentracer/test_tracer_asyncio.py b/tests/opentracer/test_tracer_asyncio.py deleted file mode 100644 index 35ece48c126..00000000000 --- a/tests/opentracer/test_tracer_asyncio.py +++ /dev/null @@ -1,143 +0,0 @@ -import asyncio - -import pytest - -from ddtrace.constants import ERROR_MSG - - -@pytest.mark.asyncio -def test_trace_coroutine(test_spans): - # it should use the task context when invoked in a coroutine - with test_spans.tracer.start_span("coroutine"): - pass - - traces = test_spans.pop_traces() - - assert len(traces) == 1 - assert len(traces[0]) == 1 - assert traces[0][0].name == "coroutine" - - -@pytest.mark.asyncio -async def test_trace_multiple_coroutines(ot_tracer, test_spans): - # if multiple coroutines have nested tracing, they must belong - # to the same trace - - async def coro(): - # another traced coroutine - with ot_tracer.start_active_span("coroutine_2"): - return 42 - - with ot_tracer.start_active_span("coroutine_1"): - value = await coro() - - # the coroutine has been called correctly - assert value == 42 - # a single trace has been properly reported - traces = test_spans.pop_traces() - assert len(traces) == 1 - assert len(traces[0]) == 2 - assert traces[0][0].name == "coroutine_1" - assert traces[0][1].name == "coroutine_2" - # the parenting is correct - assert traces[0][0] == traces[0][1]._parent - assert traces[0][0].trace_id == traces[0][1].trace_id - - -@pytest.mark.asyncio -async def test_exception(ot_tracer, test_spans): - async def f1(): - with ot_tracer.start_span("f1"): - raise Exception("f1 error") - - with pytest.raises(Exception, match="f1 error"): - await f1() - - traces = test_spans.pop_traces() - assert len(traces) == 1 - spans = traces[0] - assert len(spans) == 1 - span = spans[0] - assert span.error == 1 - assert span.get_tag(ERROR_MSG) == "f1 error" - assert "Exception: f1 error" in span.get_tag("error.stack") - - -@pytest.mark.asyncio -async def test_trace_multiple_calls(ot_tracer, test_spans): - # create multiple futures so that we expect multiple - # traces instead of a single one (helper not used) - async def coro(): - # another traced coroutine - with ot_tracer.start_span("coroutine"): - await asyncio.sleep(0.01) - - futures = [asyncio.ensure_future(coro()) for x in range(10)] - for future in futures: - await future - - traces = test_spans.pop_traces() - - assert len(traces) == 10 - assert len(traces[0]) == 1 - assert traces[0][0].name == "coroutine" - - -@pytest.mark.asyncio -async def test_trace_multiple_coroutines_ot_dd(ot_tracer): - """ - Ensure we can trace from opentracer to ddtracer across asyncio - context switches. - """ - - # if multiple coroutines have nested tracing, they must belong - # to the same trace - async def coro(): - # another traced coroutine - with ot_tracer._dd_tracer.trace("coroutine_2"): - return 42 - - with ot_tracer.start_active_span("coroutine_1"): - value = await coro() - - # the coroutine has been called correctly - assert value == 42 - # a single trace has been properly reported - traces = ot_tracer._dd_tracer.pop_traces() - assert len(traces) == 1 - assert len(traces[0]) == 2 - assert traces[0][0].name == "coroutine_1" - assert traces[0][1].name == "coroutine_2" - # the parenting is correct - assert traces[0][0] == traces[0][1]._parent - assert traces[0][0].trace_id == traces[0][1].trace_id - - -@pytest.mark.asyncio -async def test_trace_multiple_coroutines_dd_ot(ot_tracer): - """ - Ensure we can trace from ddtracer to opentracer across asyncio - context switches. - """ - - # if multiple coroutines have nested tracing, they must belong - # to the same trace - async def coro(): - # another traced coroutine - with ot_tracer.start_span("coroutine_2"): - return 42 - - with ot_tracer._dd_tracer.trace("coroutine_1"): - value = await coro() - - # the coroutine has been called correctly - assert value == 42 - # a single trace has been properly reported - traces = ot_tracer._dd_tracer.pop_traces() - assert len(traces) == 1 - assert len(traces[0]) == 2 - assert traces[0][0].name == "coroutine_1" - assert traces[0][1].name == "coroutine_2" - # the parenting is correct - assert traces[0][0] == traces[0][1]._parent - assert traces[0][0].trace_id == traces[0][1].trace_id diff --git a/tests/opentracer/test_tracer_gevent.py b/tests/opentracer/test_tracer_gevent.py deleted file mode 100644 index 320b39ee997..00000000000 --- a/tests/opentracer/test_tracer_gevent.py +++ /dev/null @@ -1,193 +0,0 @@ -import gevent -from opentracing.scope_managers.gevent import GeventScopeManager -import pytest - -from ddtrace.contrib.internal.gevent.patch import patch -from ddtrace.contrib.internal.gevent.patch import unpatch - - -@pytest.fixture() -def ot_tracer(ot_tracer_factory): - """Fixture providing an opentracer configured for gevent usage.""" - # patch gevent - patch() - yield ot_tracer_factory("gevent_svc", {}, GeventScopeManager()) - # unpatch gevent - unpatch() - - -class TestTracerGevent(object): - """Converted Gevent tests for the regular tracer. - - Ensures that greenlets are properly traced when using - the opentracer. - """ - - def test_no_threading(self, ot_tracer): - with ot_tracer.start_span("span") as span: - span.set_tag("tag", "value") - - assert span.finished - - def test_greenlets(self, ot_tracer, test_spans): - def f(): - with ot_tracer.start_span("f") as span: - gevent.sleep(0.04) - span.set_tag("f", "yes") - - def g(): - with ot_tracer.start_span("g") as span: - gevent.sleep(0.03) - span.set_tag("g", "yes") - - with ot_tracer.start_active_span("root"): - gevent.joinall([gevent.spawn(f), gevent.spawn(g)]) - - traces = test_spans.pop_traces() - assert len(traces) == 1 - assert len(traces[0]) == 3 - - def test_trace_greenlet(self, ot_tracer, test_spans): - # a greenlet can be traced using the trace API - def greenlet(): - with ot_tracer.start_span("greenlet"): - pass - - gevent.spawn(greenlet).join() - traces = test_spans.pop_traces() - assert len(traces) == 1 - assert len(traces[0]) == 1 - assert traces[0][0].name == "greenlet" - - def test_trace_later_greenlet(self, ot_tracer, test_spans): - # a greenlet can be traced using the trace API - def greenlet(): - with ot_tracer.start_span("greenlet"): - pass - - gevent.spawn_later(0.01, greenlet).join() - traces = test_spans.pop_traces() - - assert len(traces) == 1 - assert len(traces[0]) == 1 - assert traces[0][0].name == "greenlet" - - def test_trace_concurrent_calls(self, ot_tracer, test_spans): - # create multiple futures so that we expect multiple - # traces instead of a single one - def greenlet(): - with ot_tracer.start_span("greenlet"): - gevent.sleep(0.01) - - jobs = [gevent.spawn(greenlet) for x in range(100)] - gevent.joinall(jobs) - - traces = test_spans.pop_traces() - - assert len(traces) == 100 - assert len(traces[0]) == 1 - assert traces[0][0].name == "greenlet" - - def test_trace_concurrent_spawn_later_calls(self, ot_tracer, test_spans): - # create multiple futures so that we expect multiple - # traces instead of a single one, even if greenlets - # are delayed - def greenlet(): - with ot_tracer.start_span("greenlet"): - gevent.sleep(0.01) - - jobs = [gevent.spawn_later(0.01, greenlet) for x in range(100)] - gevent.joinall(jobs) - - traces = test_spans.pop_traces() - assert len(traces) == 100 - assert len(traces[0]) == 1 - assert traces[0][0].name == "greenlet" - - -class TestTracerGeventCompatibility(object): - """Ensure the opentracer works in tandem with the ddtracer and gevent.""" - - def test_trace_spawn_multiple_greenlets_multiple_traces_ot_parent(self, ot_tracer, dd_tracer, test_spans): - """ - Copy of gevent test with the same name but testing with mixed usage of - the opentracer and datadog tracers. - - Uses an opentracer span as the parent span. - """ - - # multiple greenlets must be part of the same trace - def entrypoint(): - with ot_tracer.start_active_span("greenlet.main"): - jobs = [gevent.spawn(green_1), gevent.spawn(green_2)] - gevent.joinall(jobs) - - def green_1(): - with dd_tracer.trace("greenlet.worker") as span: - span.set_tag("worker_id", "1") - gevent.sleep(0.01) - - def green_2(): - with ot_tracer.start_span("greenlet.worker") as span: - span.set_tag("worker_id", "2") - gevent.sleep(0.01) - - gevent.spawn(entrypoint).join() - traces = test_spans.pop_traces() - assert len(traces) == 1 - assert len(traces[0]) == 3 - parent_span = traces[0][0] - worker_1 = traces[0][1] - worker_2 = traces[0][2] - # check spans data and hierarchy - assert parent_span.name == "greenlet.main" - assert worker_1.get_tag("worker_id") == "1" - assert worker_1.name == "greenlet.worker" - assert worker_1.resource == "greenlet.worker" - assert worker_1.parent_id == parent_span.span_id - assert worker_2.get_tag("worker_id") == "2" - assert worker_2.name == "greenlet.worker" - assert worker_2.resource == "greenlet.worker" - assert worker_2.parent_id == parent_span.span_id - - def test_trace_spawn_multiple_greenlets_multiple_traces_dd_parent(self, ot_tracer, dd_tracer, test_spans): - """ - Copy of gevent test with the same name but testing with mixed usage of - the opentracer and datadog tracers. - - Uses an opentracer span as the parent span. - """ - - # multiple greenlets must be part of the same trace - def entrypoint(): - with dd_tracer.trace("greenlet.main"): - jobs = [gevent.spawn(green_1), gevent.spawn(green_2)] - gevent.joinall(jobs) - - def green_1(): - with ot_tracer.start_span("greenlet.worker") as span: - span.set_tag("worker_id", "1") - gevent.sleep(0.01) - - def green_2(): - with dd_tracer.trace("greenlet.worker") as span: - span.set_tag("worker_id", "2") - gevent.sleep(0.01) - - gevent.spawn(entrypoint).join() - traces = test_spans.pop_traces() - assert len(traces) == 1 - assert len(traces[0]) == 3 - parent_span = traces[0][0] - worker_1 = traces[0][1] - worker_2 = traces[0][2] - # check spans data and hierarchy - assert parent_span.name == "greenlet.main" - assert worker_1.get_tag("worker_id") == "1" - assert worker_1.name == "greenlet.worker" - assert worker_1.resource == "greenlet.worker" - assert worker_1.parent_id == parent_span.span_id - assert worker_2.get_tag("worker_id") == "2" - assert worker_2.name == "greenlet.worker" - assert worker_2.resource == "greenlet.worker" - assert worker_2.parent_id == parent_span.span_id diff --git a/tests/opentracer/test_tracer_tornado.py b/tests/opentracer/test_tracer_tornado.py deleted file mode 100644 index d81541e0a52..00000000000 --- a/tests/opentracer/test_tracer_tornado.py +++ /dev/null @@ -1,30 +0,0 @@ -from opentracing.scope_managers.tornado import TornadoScopeManager -import pytest - - -@pytest.fixture() -def ot_tracer(ot_tracer_factory): - """Fixture providing an opentracer configured for tornado usage.""" - yield ot_tracer_factory("tornado_svc", {}, TornadoScopeManager()) - - -class TestTracerTornado(object): - """ - Since the ScopeManager is provided by OpenTracing we should simply test - whether it exists and works for a very simple use-case. - """ - - def test_sanity(self, ot_tracer, test_spans): - with ot_tracer.start_active_span("one"): - with ot_tracer.start_active_span("two"): - pass - - traces = test_spans.pop_traces() - assert len(traces) == 1 - assert len(traces[0]) == 2 - assert traces[0][0].name == "one" - assert traces[0][1].name == "two" - - # the parenting is correct - assert traces[0][0] == traces[0][1]._parent - assert traces[0][0].trace_id == traces[0][1].trace_id diff --git a/tests/opentracer/utils.py b/tests/opentracer/utils.py deleted file mode 100644 index 85b84865ad8..00000000000 --- a/tests/opentracer/utils.py +++ /dev/null @@ -1,11 +0,0 @@ -from ddtrace.opentracer import Tracer - - -def init_tracer(service_name, dd_tracer, scope_manager=None): - """A method that emulates what a user of OpenTracing would call to - initialize a Datadog opentracer. - - It accepts a Datadog tracer that should be the same one used for testing. - """ - ot_tracer = Tracer(service_name, scope_manager=scope_manager, _dd_tracer=dd_tracer) - return ot_tracer diff --git a/tests/suitespec.yml b/tests/suitespec.yml index 977f6685e79..8e24ecaf5d6 100644 --- a/tests/suitespec.yml +++ b/tests/suitespec.yml @@ -90,8 +90,6 @@ components: opentelemetry: - ddtrace/opentelemetry/* - ddtrace/internal/opentelemetry/* - opentracer: - - ddtrace/opentracer/* profiling: - ddtrace/profiling/* - ddtrace/internal/datadog/profiling/* diff --git a/tests/telemetry/test_telemetry_metrics_e2e.py b/tests/telemetry/test_telemetry_metrics_e2e.py index 8eed0b55426..03bf27b9682 100644 --- a/tests/telemetry/test_telemetry_metrics_e2e.py +++ b/tests/telemetry/test_telemetry_metrics_e2e.py @@ -141,69 +141,3 @@ def test_span_creation_and_finished_metrics_otel(test_agent_session, ddtrace_run assert metrics_sf[0]["metric"] == "spans_finished" assert metrics_sf[0]["tags"] == ["integration_name:otel"] assert metrics_sf[0]["points"][0][1] == 9 - - -def test_span_creation_and_finished_metrics_opentracing(test_agent_session, ddtrace_run_python_code_in_subprocess): - code = """ -from ddtrace.opentracer import Tracer - -ot = Tracer() -for _ in range(2): - with ot.start_span('span'): - pass -""" - env = os.environ.copy() - env["DD_TRACE_OTEL_ENABLED"] = "true" - env["_DD_INSTRUMENTATION_TELEMETRY_TESTS_FORCE_APP_STARTED"] = "true" - _, stderr, status, _ = ddtrace_run_python_code_in_subprocess(code, env=env) - assert status == 0, stderr - - metrics_sc = test_agent_session.get_metrics("spans_created") - assert len(metrics_sc) == 1 - assert metrics_sc[0]["metric"] == "spans_created" - assert metrics_sc[0]["tags"] == ["integration_name:opentracing"] - assert metrics_sc[0]["points"][0][1] == 2 - - metrics_sf = test_agent_session.get_metrics("spans_finished") - assert len(metrics_sf) == 1 - assert metrics_sf[0]["metric"] == "spans_finished" - assert metrics_sf[0]["tags"] == ["integration_name:opentracing"] - assert metrics_sf[0]["points"][0][1] == 2 - - -def test_span_creation_no_finish(test_agent_session, ddtrace_run_python_code_in_subprocess): - code = """ -import ddtrace -import opentelemetry.trace -from ddtrace import opentracer - -ddtracer = ddtrace.tracer -otel = opentelemetry.trace.get_tracer(__name__) -ot = opentracer.Tracer() - -# we must finish at least one span to enable sending telemetry to the agent -ddtracer.trace("first_span").finish() - -for _ in range(4): - ot.start_span('ot_span') - otel.start_span('otel_span') - ddtracer.trace("ddspan") -""" - env = os.environ.copy() - env["DD_TRACE_OTEL_ENABLED"] = "true" - env["_DD_INSTRUMENTATION_TELEMETRY_TESTS_FORCE_APP_STARTED"] = "true" - _, stderr, status, _ = ddtrace_run_python_code_in_subprocess(code, env=env) - assert status == 0, stderr - - metrics = test_agent_session.get_metrics("spans_created") - assert len(metrics) == 3 - - assert metrics[0]["metric"] == "spans_created" - assert metrics[0]["tags"] == ["integration_name:datadog"] - assert metrics[0]["points"][0][1] == 5 - assert metrics[1]["metric"] == "spans_created" - assert metrics[1]["tags"] == ["integration_name:opentracing"] - assert metrics[1]["points"][0][1] == 4 - assert metrics[2]["metric"] == "spans_created" - assert metrics[2]["tags"] == ["integration_name:otel"] - assert metrics[2]["points"][0][1] == 4 diff --git a/tests/tracer/test_correlation_log_context.py b/tests/tracer/test_correlation_log_context.py index abd82ad91a7..fa5f8b045f6 100644 --- a/tests/tracer/test_correlation_log_context.py +++ b/tests/tracer/test_correlation_log_context.py @@ -58,27 +58,6 @@ def test_get_log_correlation_trace_context(): }, dd_log_record -@pytest.mark.subprocess( - ddtrace_run=True, env={"DD_VERSION": "test-version", "DD_ENV": "test-env", "DD_SERVICE": "test-service"} -) -def test_get_log_correlation_context_opentracer(): - """Ensure expected DDLogRecord generated via get_correlation_log_record with an opentracing Tracer.""" - from ddtrace.internal.utils.formats import format_trace_id - from ddtrace.opentracer.tracer import Tracer as OT_Tracer - - ot_tracer = OT_Tracer(service_name="test-service") - with ot_tracer.start_active_span("operation") as scope: - dd_span = scope._span._dd_span - dd_log_record = ot_tracer.get_log_correlation_context() - assert dd_log_record == { - "dd.span_id": str(dd_span.span_id), - "dd.trace_id": format_trace_id(dd_span.trace_id), - "dd.service": "test-service", - "dd.env": "test-env", - "dd.version": "test-version", - }, dd_log_record - - @pytest.mark.subprocess() def test_get_log_correlation_context_no_active_span(): """Ensure empty DDLogRecord generated if no active span.""" diff --git a/tests/tracer/test_propagation.py b/tests/tracer/test_propagation.py index 9232d4c2f20..eee54604355 100644 --- a/tests/tracer/test_propagation.py +++ b/tests/tracer/test_propagation.py @@ -3515,22 +3515,6 @@ def test_http_propagator_baggage_extract(headers): assert context._baggage == {"key1": "val1", "key2": "val2", "foo": "bar", "x": "y"} -@pytest.mark.subprocess( - env=dict(DD_TRACE_PROPAGATION_HTTP_BAGGAGE_ENABLED="True"), - parametrize=dict(DD_TRACE_PROPAGATION_EXTRACT_FIRST=["True", "False"]), -) -def test_opentracer_propagator_baggage_extract(): - from ddtrace.propagation.http import HTTPPropagator - - headers = { - "x-datadog-trace-id": "1234", - "x-datadog-parent-id": "5678", - "http_ot_baggage_key1": "value1", - } - context = HTTPPropagator.extract(headers) - assert context._baggage == {"key1": "value1"} - - def test_baggage_span_tags_default(): headers = {"baggage": "user.id=123,correlation_id=abc,region=us-east"} context = HTTPPropagator.extract(headers) From c47f4d5e00ea866449bfcf1c0366ebf9d7446dc3 Mon Sep 17 00:00:00 2001 From: Emmett Butler <723615+emmettbutler@users.noreply.github.com> Date: Fri, 24 Oct 2025 10:58:09 -0700 Subject: [PATCH 5/5] chore: remove deprecated Span function parameters (#14894) This change removes deprecated methods and method parameters from the `Span` class. Note the base branch, a staging area for breaking changes slated for 4.0. --------- Co-authored-by: brettlangdon --- ddtrace/_trace/span.py | 33 ------------- .../span-args-remove-5feecae6cf00537f.yaml | 4 ++ tests/contrib/yaaredis/test_yaaredis.py | 1 - tests/opentelemetry/test_span.py | 1 - tests/tracer/test_span.py | 47 ------------------- 5 files changed, 4 insertions(+), 82 deletions(-) create mode 100644 releasenotes/notes/span-args-remove-5feecae6cf00537f.yaml diff --git a/ddtrace/_trace/span.py b/ddtrace/_trace/span.py index 9e306f621bc..df5c36df611 100644 --- a/ddtrace/_trace/span.py +++ b/ddtrace/_trace/span.py @@ -52,10 +52,8 @@ from ddtrace.internal.constants import SPAN_API_DATADOG from ddtrace.internal.constants import SamplingMechanism from ddtrace.internal.logger import get_logger -from ddtrace.internal.utils.deprecations import DDTraceDeprecationWarning from ddtrace.internal.utils.time import Time from ddtrace.settings._config import config -from ddtrace.vendor.debtcollector import deprecate from ddtrace.vendor.debtcollector import removals @@ -630,8 +628,6 @@ def record_exception( self, exception: BaseException, attributes: Optional[Dict[str, _AttributeValueType]] = None, - timestamp: Optional[int] = None, - escaped: bool = False, ) -> None: """ Records an exception as a span event. Multiple exceptions can be recorded on a span. @@ -643,23 +639,6 @@ def record_exception( :param timestamp: Deprecated. :param escaped: Deprecated. """ - if escaped: - deprecate( - prefix="The escaped argument is deprecated for record_exception", - message="""If an exception exits the scope of the span, it will automatically be - reported in the span tags.""", - category=DDTraceDeprecationWarning, - removal_version="4.0.0", - ) - if timestamp is not None: - deprecate( - prefix="The timestamp argument is deprecated for record_exception", - message="""The timestamp of the span event should correspond to the time when the - error is recorded which is set automatically.""", - category=DDTraceDeprecationWarning, - removal_version="4.0.0", - ) - tb = self._get_traceback(type(exception), exception, exception.__traceback__) attrs: Dict[str, _AttributeValueType] = { @@ -847,18 +826,6 @@ def __exit__( except Exception: log.exception("error closing trace") - def _pprint(self) -> str: - # Although Span._pprint has been internal to ddtrace since v1.0.0, it is still - # used to debug spans in the wild. Introducing a deprecation warning here to - # give users a chance to migrate to __repr__ before we remove it. - deprecate( - prefix="The _pprint method is deprecated for __repr__", - message="""Use __repr__ instead.""", - category=DDTraceDeprecationWarning, - removal_version="4.0.0", - ) - return self.__repr__() - def __repr__(self) -> str: """Return a detailed string representation of a span.""" return ( diff --git a/releasenotes/notes/span-args-remove-5feecae6cf00537f.yaml b/releasenotes/notes/span-args-remove-5feecae6cf00537f.yaml new file mode 100644 index 00000000000..03d65342e97 --- /dev/null +++ b/releasenotes/notes/span-args-remove-5feecae6cf00537f.yaml @@ -0,0 +1,4 @@ +--- +other: + - | + This change removes deprecated methods and method parameters from the `Span` class. diff --git a/tests/contrib/yaaredis/test_yaaredis.py b/tests/contrib/yaaredis/test_yaaredis.py index 84185652ba0..d3fa5743b70 100644 --- a/tests/contrib/yaaredis/test_yaaredis.py +++ b/tests/contrib/yaaredis/test_yaaredis.py @@ -9,7 +9,6 @@ from ddtrace.contrib.internal.yaaredis.patch import patch from ddtrace.contrib.internal.yaaredis.patch import unpatch from ddtrace.internal.compat import is_wrapted -from tests.opentracer.utils import init_tracer from tests.utils import override_config from ..config import REDIS_CONFIG diff --git a/tests/opentelemetry/test_span.py b/tests/opentelemetry/test_span.py index 3af064de795..61f9c6e0359 100644 --- a/tests/opentelemetry/test_span.py +++ b/tests/opentelemetry/test_span.py @@ -272,4 +272,3 @@ def test_otel_span_interoperability(oteltracer): otel_span_clone = Span(otel_span_og._ddspan) # Ensure all properties are consistent assert otel_span_clone.__dict__ == otel_span_og.__dict__ - assert otel_span_clone._ddspan._pprint() == otel_span_og._ddspan._pprint() diff --git a/tests/tracer/test_span.py b/tests/tracer/test_span.py index a47391ef3da..fcfd753255f 100644 --- a/tests/tracer/test_span.py +++ b/tests/tracer/test_span.py @@ -10,7 +10,6 @@ from ddtrace._trace._span_link import SpanLink from ddtrace._trace._span_pointer import _SpanPointerDirection -from ddtrace._trace.context import Context from ddtrace.constants import _SPAN_MEASURED_KEY from ddtrace.constants import ENV_KEY from ddtrace.constants import ERROR_MSG @@ -866,52 +865,6 @@ def test_span_preconditions(arg): Span("test", **{arg: "foo"}) -def test_span_pprint(): - root = Span("test.span", service="s", resource="r", span_type=SpanTypes.WEB, context=Context(trace_id=1, span_id=2)) - root.set_tag("t", "v") - root.set_metric("m", 1.0) - root._add_event("message", {"importance": 10}, 16789898242) - root.set_link(trace_id=99, span_id=10, attributes={"link.name": "s1_to_s2", "link.kind": "scheduled_by"}) - root._add_span_pointer("test_kind", _SpanPointerDirection.DOWNSTREAM, "test_hash_123", {"extra": "attr"}) - - root.finish() - actual = root._pprint() - assert "name='test.span'" in actual - assert "service='s'" in actual - assert "resource='r'" in actual - assert "type='web'" in actual - assert "error=0" in actual - assert "tags={'t': 'v'}" in actual - assert "metrics={'m': 1.0}" in actual - assert "events=[SpanEvent(name='message', time=16789898242, attributes={'importance': 10})]" in actual - assert ( - "SpanLink(trace_id=99, span_id=10, attributes={'link.name': 's1_to_s2', 'link.kind': 'scheduled_by'}, " - "tracestate=None, flags=None, dropped_attributes=0)" - ) in actual - assert "SpanPointer(trace_id=0, span_id=0, kind=span-pointer" in actual - assert "direction=d, hash=test_hash_123" in actual - assert ( - f"context=Context(trace_id={root.trace_id}, span_id={root.span_id}, _meta={{}}, " - "_metrics={}, _span_links=[], _baggage={}, _is_remote=False)" - ) in actual - assert f"span_id={root.span_id}" in actual - assert f"trace_id={root.trace_id}" in actual - assert f"parent_id={root.parent_id}" in actual - assert f"start={root.start_ns}" in actual - assert f"duration={root.duration_ns}" in actual - assert f"end={root.start_ns + root.duration_ns}" in actual - - root = Span("test.span", service="s", resource="r", span_type=SpanTypes.WEB) - root.error = 1 - kv = {f"😌{i}": "😌" for i in range(100)} - root.set_tags(kv) - actual = root._pprint() - assert "duration=None" in actual - assert "end=None" in actual - assert "error=1" in actual - assert f"tags={kv}" in actual - - def test_manual_context_usage(): span1 = Span("span1") span2 = Span("span2", context=span1.context)