diff --git a/.github/workflows/test-integrations-misc.yml b/.github/workflows/test-integrations-misc.yml index b9c347933c..1f670f1ddd 100644 --- a/.github/workflows/test-integrations-misc.yml +++ b/.github/workflows/test-integrations-misc.yml @@ -29,7 +29,7 @@ jobs: strategy: fail-fast: false matrix: - python-version: ["3.7","3.8","3.9","3.10","3.11","3.12","3.13"] + python-version: ["3.7","3.8","3.10","3.11","3.12","3.13"] os: [ubuntu-22.04] steps: - uses: actions/checkout@v4.2.2 diff --git a/scripts/populate_tox/tox.jinja b/scripts/populate_tox/tox.jinja index 8088eb1998..b76dfd12fa 100644 --- a/scripts/populate_tox/tox.jinja +++ b/scripts/populate_tox/tox.jinja @@ -107,12 +107,6 @@ envlist = {py3.9,py3.11,py3.12}-openai-latest {py3.9,py3.11,py3.12}-openai-notiktoken - # OpenTelemetry (OTel) - {py3.7,py3.9,py3.12,py3.13}-opentelemetry - - # OpenTelemetry Experimental (POTel) - {py3.8,py3.9,py3.10,py3.11,py3.12,py3.13}-potel - # pure_eval {py3.7,py3.12,py3.13}-pure_eval @@ -310,12 +304,6 @@ deps = openai-latest: tiktoken~=0.6.0 openai-notiktoken: openai - # OpenTelemetry (OTel) - opentelemetry: opentelemetry-distro - - # OpenTelemetry Experimental (POTel) - potel: -e .[opentelemetry-experimental] - # pure_eval pure_eval: pure_eval @@ -441,8 +429,6 @@ setenv = loguru: TESTPATH=tests/integrations/loguru openai: TESTPATH=tests/integrations/openai openfeature: TESTPATH=tests/integrations/openfeature - opentelemetry: TESTPATH=tests/integrations/opentelemetry - potel: TESTPATH=tests/integrations/opentelemetry pure_eval: TESTPATH=tests/integrations/pure_eval pymongo: TESTPATH=tests/integrations/pymongo pyramid: TESTPATH=tests/integrations/pyramid diff --git a/sentry_sdk/client.py b/sentry_sdk/client.py index c4599cd840..2f4349253b 100644 --- a/sentry_sdk/client.py +++ b/sentry_sdk/client.py @@ -35,6 +35,7 @@ from sentry_sdk.integrations.dedupe import DedupeIntegration from sentry_sdk.sessions import SessionFlusher from sentry_sdk.envelope import Envelope + from sentry_sdk.profiler.continuous_profiler import setup_continuous_profiler from sentry_sdk.profiler.transaction_profiler import ( has_profiling_enabled, @@ -392,6 +393,13 @@ def _capture_envelope(envelope): except Exception as e: logger.debug("Can not set up continuous profiler. (%s)", e) + from sentry_sdk.opentelemetry.tracing import ( + patch_readable_span, + setup_sentry_tracing, + ) + + patch_readable_span() + setup_sentry_tracing() finally: _client_init_debug.set(old_debug) diff --git a/sentry_sdk/integrations/__init__.py b/sentry_sdk/integrations/__init__.py index fcfcccebd0..c7967852a7 100644 --- a/sentry_sdk/integrations/__init__.py +++ b/sentry_sdk/integrations/__init__.py @@ -69,7 +69,6 @@ def iter_default_integrations(with_auto_enabling_integrations): "sentry_sdk.integrations.excepthook.ExcepthookIntegration", "sentry_sdk.integrations.logging.LoggingIntegration", "sentry_sdk.integrations.modules.ModulesIntegration", - "sentry_sdk.integrations.opentelemetry.integration.OpenTelemetryIntegration", "sentry_sdk.integrations.stdlib.StdlibIntegration", "sentry_sdk.integrations.threading.ThreadingIntegration", ] diff --git a/sentry_sdk/integrations/opentelemetry/__init__.py b/sentry_sdk/integrations/opentelemetry/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/sentry_sdk/integrations/opentelemetry/integration.py b/sentry_sdk/integrations/opentelemetry/integration.py deleted file mode 100644 index ef5bd34f96..0000000000 --- a/sentry_sdk/integrations/opentelemetry/integration.py +++ /dev/null @@ -1,80 +0,0 @@ -""" -IMPORTANT: The contents of this file are part of a proof of concept and as such -are experimental and not suitable for production use. They may be changed or -removed at any time without prior notice. -""" - -from sentry_sdk.integrations import DidNotEnable, Integration -from sentry_sdk.opentelemetry import ( - SentryPropagator, - SentrySampler, - SentrySpanProcessor, -) -from sentry_sdk.utils import logger - -try: - from opentelemetry import trace - from opentelemetry.propagate import set_global_textmap - from opentelemetry.sdk.trace import TracerProvider, Span, ReadableSpan -except ImportError: - raise DidNotEnable("opentelemetry not installed") - -try: - from opentelemetry.instrumentation.django import DjangoInstrumentor # type: ignore[import-not-found] -except ImportError: - DjangoInstrumentor = None - - -CONFIGURABLE_INSTRUMENTATIONS = { - DjangoInstrumentor: {"is_sql_commentor_enabled": True}, -} - - -class OpenTelemetryIntegration(Integration): - identifier = "opentelemetry" - - @staticmethod - def setup_once(): - # type: () -> None - logger.warning( - "[OTel] Initializing highly experimental OpenTelemetry support. " - "Use at your own risk." - ) - - _setup_sentry_tracing() - _patch_readable_span() - # _setup_instrumentors() - - logger.debug("[OTel] Finished setting up OpenTelemetry integration") - - -def _patch_readable_span(): - # type: () -> None - """ - We need to pass through sentry specific metadata/objects from Span to ReadableSpan - to work with them consistently in the SpanProcessor. - """ - old_readable_span = Span._readable_span - - def sentry_patched_readable_span(self): - # type: (Span) -> ReadableSpan - readable_span = old_readable_span(self) - readable_span._sentry_meta = getattr(self, "_sentry_meta", {}) # type: ignore[attr-defined] - return readable_span - - Span._readable_span = sentry_patched_readable_span # type: ignore[method-assign] - - -def _setup_sentry_tracing(): - # type: () -> None - provider = TracerProvider(sampler=SentrySampler()) - provider.add_span_processor(SentrySpanProcessor()) - trace.set_tracer_provider(provider) - - set_global_textmap(SentryPropagator()) - - -def _setup_instrumentors(): - # type: () -> None - for instrumentor, kwargs in CONFIGURABLE_INSTRUMENTATIONS.items(): - instrumentor().instrument(**kwargs) diff --git a/sentry_sdk/opentelemetry/tracing.py b/sentry_sdk/opentelemetry/tracing.py new file mode 100644 index 0000000000..8392c1515a --- /dev/null +++ b/sentry_sdk/opentelemetry/tracing.py @@ -0,0 +1,35 @@ +from opentelemetry import trace +from opentelemetry.propagate import set_global_textmap +from opentelemetry.sdk.trace import TracerProvider, Span, ReadableSpan + +from sentry_sdk.opentelemetry import ( + SentryPropagator, + SentrySampler, + SentrySpanProcessor, +) + + +def patch_readable_span(): + # type: () -> None + """ + We need to pass through sentry specific metadata/objects from Span to ReadableSpan + to work with them consistently in the SpanProcessor. + """ + old_readable_span = Span._readable_span + + def sentry_patched_readable_span(self): + # type: (Span) -> ReadableSpan + readable_span = old_readable_span(self) + readable_span._sentry_meta = getattr(self, "_sentry_meta", {}) # type: ignore[attr-defined] + return readable_span + + Span._readable_span = sentry_patched_readable_span # type: ignore[method-assign] + + +def setup_sentry_tracing(): + # type: () -> None + provider = TracerProvider(sampler=SentrySampler()) + provider.add_span_processor(SentrySpanProcessor()) + trace.set_tracer_provider(provider) + + set_global_textmap(SentryPropagator()) diff --git a/tests/integrations/opentelemetry/__init__.py b/tests/opentelemetry/__init__.py similarity index 100% rename from tests/integrations/opentelemetry/__init__.py rename to tests/opentelemetry/__init__.py diff --git a/tests/integrations/opentelemetry/test_compat.py b/tests/opentelemetry/test_compat.py similarity index 100% rename from tests/integrations/opentelemetry/test_compat.py rename to tests/opentelemetry/test_compat.py diff --git a/tests/integrations/opentelemetry/test_entry_points.py b/tests/opentelemetry/test_entry_points.py similarity index 100% rename from tests/integrations/opentelemetry/test_entry_points.py rename to tests/opentelemetry/test_entry_points.py diff --git a/tests/integrations/opentelemetry/test_potel.py b/tests/opentelemetry/test_potel.py similarity index 100% rename from tests/integrations/opentelemetry/test_potel.py rename to tests/opentelemetry/test_potel.py diff --git a/tests/integrations/opentelemetry/test_propagator.py b/tests/opentelemetry/test_propagator.py similarity index 100% rename from tests/integrations/opentelemetry/test_propagator.py rename to tests/opentelemetry/test_propagator.py diff --git a/tests/integrations/opentelemetry/test_sampler.py b/tests/opentelemetry/test_sampler.py similarity index 100% rename from tests/integrations/opentelemetry/test_sampler.py rename to tests/opentelemetry/test_sampler.py diff --git a/tests/integrations/opentelemetry/test_utils.py b/tests/opentelemetry/test_utils.py similarity index 100% rename from tests/integrations/opentelemetry/test_utils.py rename to tests/opentelemetry/test_utils.py diff --git a/tox.ini b/tox.ini index 3777f8f0ca..744b7c62a0 100644 --- a/tox.ini +++ b/tox.ini @@ -10,7 +10,7 @@ # The file (and all resulting CI YAMLs) then need to be regenerated via # "scripts/generate-test-files.sh". # -# Last generated: 2025-04-10T12:24:07.555804+00:00 +# Last generated: 2025-04-10T13:32:09.968256+00:00 [tox] requires = @@ -107,12 +107,6 @@ envlist = {py3.9,py3.11,py3.12}-openai-latest {py3.9,py3.11,py3.12}-openai-notiktoken - # OpenTelemetry (OTel) - {py3.7,py3.9,py3.12,py3.13}-opentelemetry - - # OpenTelemetry Experimental (POTel) - {py3.8,py3.9,py3.10,py3.11,py3.12,py3.13}-potel - # pure_eval {py3.7,py3.12,py3.13}-pure_eval @@ -435,12 +429,6 @@ deps = openai-latest: tiktoken~=0.6.0 openai-notiktoken: openai - # OpenTelemetry (OTel) - opentelemetry: opentelemetry-distro - - # OpenTelemetry Experimental (POTel) - potel: -e .[opentelemetry-experimental] - # pure_eval pure_eval: pure_eval @@ -757,8 +745,6 @@ setenv = loguru: TESTPATH=tests/integrations/loguru openai: TESTPATH=tests/integrations/openai openfeature: TESTPATH=tests/integrations/openfeature - opentelemetry: TESTPATH=tests/integrations/opentelemetry - potel: TESTPATH=tests/integrations/opentelemetry pure_eval: TESTPATH=tests/integrations/pure_eval pymongo: TESTPATH=tests/integrations/pymongo pyramid: TESTPATH=tests/integrations/pyramid