Skip to content

SQLAlchemy instrumentation does not respect suppress_instrumentation functionality #3454

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
marcm-ml opened this issue Apr 29, 2025 · 0 comments · May be fixed by #3477
Open

SQLAlchemy instrumentation does not respect suppress_instrumentation functionality #3454

marcm-ml opened this issue Apr 29, 2025 · 0 comments · May be fixed by #3477
Labels
bug Something isn't working

Comments

@marcm-ml
Copy link

marcm-ml commented Apr 29, 2025

Describe your environment

MacOS
python 3.12
opentelemetry-instrumentation-sqlalchemy v0.53b1
opentelemetry-api v1.32.1
opentelemetry-instrumentation v0.53b1
opentelemetry-semantic-conventions v0.53b1

What happened?

We have some healthcheck functions that produce spans from sqlalchemy instrumentation we would like to suppress.
In order to do that, I guess it is best practice to use the suppress_instrumentation method from opentelemetry.instrumentations.util module. However, the SQLAlchemy instrumentation does not respect this and still produces spans and metrics.

Steps to Reproduce

using uv you can simply run this as is with uv run reproduce.py

reproduce.py:

# /// script
# requires-python = ">=3.12"
# dependencies = [
#     "opentelemetry-api",
#     "opentelemetry-instrumentation-sqlalchemy",
#     "opentelemetry-sdk",
#     "sqlalchemy",
# ]
# ///
from opentelemetry import trace
from opentelemetry.instrumentation.sqlalchemy import SQLAlchemyInstrumentor
from opentelemetry.instrumentation.utils import suppress_instrumentation
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor, ConsoleSpanExporter
from sqlalchemy import create_engine

exporter = ConsoleSpanExporter()
provider = TracerProvider()
provider.add_span_processor(BatchSpanProcessor(exporter))
trace.set_tracer_provider(provider)

engine = create_engine("sqlite:///:memory:")
SQLAlchemyInstrumentor().instrument(engine=engine)

with engine.connect():  # produces spans
    pass

with suppress_instrumentation(), engine.connect():  # should not produce spans but does
    pass

Expected Result

OTEL signals should not be produced when suppress_instrumentation is used.

Actual Result

OTEL signals are produced when suppress_instrumentation is used

Additional context

A fix can be implemented by using the is_instrumentation_enabled from opentelemetry.instrumentation.utils module everywhere in the engine.py module, i.e.:

engine.py

def _wrap_connect(tracer):
    # pylint: disable=unused-argument
    def _wrap_connect_internal(func, module, args, kwargs):
        if not is_instrumentation_enabled(): # this is new
            return func(*args, **kwargs)

        with tracer.start_as_current_span(
            "connect", kind=trace.SpanKind.CLIENT
        ) as span:
            if span.is_recording():
                attrs, _ = _get_attributes_from_url(module.url)
                span.set_attributes(attrs)
                span.set_attribute(
                    SpanAttributes.DB_SYSTEM, _normalize_vendor(module.name)
                )
            return func(*args, **kwargs)

    return _wrap_connect_internal

If i use the code above and the reproduction script, I get the expected result where only 1 span is produced.

Would you like to implement a fix?

Yes

@marcm-ml marcm-ml added the bug Something isn't working label Apr 29, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
1 participant