Skip to content

Commit 77325aa

Browse files
marcm-mlemdnetoxrmx
authored
fix: respect supress_instrumentation functionality in sqlalchemy instrumentation (#3477)
* respect supress_instrumentation * update changelog * Update CHANGELOG.md Fix changelog after release --------- Co-authored-by: Emídio Neto <[email protected]> Co-authored-by: Riccardo Magliocchetti <[email protected]>
1 parent 6d8becf commit 77325aa

File tree

3 files changed

+89
-2
lines changed

3 files changed

+89
-2
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
3737
([#3520](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3520))
3838
- `opentelemetry-instrumentation-botocore` Ensure spans end on early stream closure for Bedrock Streaming APIs
3939
([#3481](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3481))
40+
- `opentelemetry-instrumentation-sqlalchemy` Respect suppress_instrumentation functionality
41+
([#3477](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3477))
4042
- `opentelemetry-instrumentation-botocore`: fix handling of tool input in Bedrock ConverseStream
4143
([#3544](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3544))
4244
- `opentelemetry-instrumentation-botocore` Add type check when extracting tool use from Bedrock request message content

instrumentation/opentelemetry-instrumentation-sqlalchemy/src/opentelemetry/instrumentation/sqlalchemy/engine.py

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,10 @@
2323

2424
from opentelemetry import trace
2525
from opentelemetry.instrumentation.sqlcommenter_utils import _add_sql_comment
26-
from opentelemetry.instrumentation.utils import _get_opentelemetry_values
26+
from opentelemetry.instrumentation.utils import (
27+
_get_opentelemetry_values,
28+
is_instrumentation_enabled,
29+
)
2730
from opentelemetry.semconv.trace import NetTransportValues, SpanAttributes
2831
from opentelemetry.trace.status import Status, StatusCode
2932

@@ -54,6 +57,9 @@ def _wrap_create_async_engine_internal(func, module, args, kwargs):
5457
"""Trace the SQLAlchemy engine, creating an `EngineTracer`
5558
object that will listen to SQLAlchemy events.
5659
"""
60+
if not is_instrumentation_enabled():
61+
return func(*args, **kwargs)
62+
5763
engine = func(*args, **kwargs)
5864
EngineTracer(
5965
tracer,
@@ -79,6 +85,9 @@ def _wrap_create_engine_internal(func, _module, args, kwargs):
7985
"""Trace the SQLAlchemy engine, creating an `EngineTracer`
8086
object that will listen to SQLAlchemy events.
8187
"""
88+
if not is_instrumentation_enabled():
89+
return func(*args, **kwargs)
90+
8291
engine = func(*args, **kwargs)
8392
EngineTracer(
8493
tracer,
@@ -96,6 +105,9 @@ def _wrap_create_engine_internal(func, _module, args, kwargs):
96105
def _wrap_connect(tracer):
97106
# pylint: disable=unused-argument
98107
def _wrap_connect_internal(func, module, args, kwargs):
108+
if not is_instrumentation_enabled():
109+
return func(*args, **kwargs)
110+
99111
with tracer.start_as_current_span(
100112
"connect", kind=trace.SpanKind.CLIENT
101113
) as span:
@@ -144,6 +156,9 @@ def __init__(
144156
self._register_event_listener(engine, "checkout", self._pool_checkout)
145157

146158
def _add_idle_to_connection_usage(self, value):
159+
if not is_instrumentation_enabled():
160+
return
161+
147162
self.connections_usage.add(
148163
value,
149164
attributes={
@@ -153,6 +168,9 @@ def _add_idle_to_connection_usage(self, value):
153168
)
154169

155170
def _add_used_to_connection_usage(self, value):
171+
if not is_instrumentation_enabled():
172+
return
173+
156174
self.connections_usage.add(
157175
value,
158176
attributes={
@@ -259,6 +277,9 @@ def _set_db_client_span_attributes(self, span, statement, attrs) -> None:
259277
def _before_cur_exec(
260278
self, conn, cursor, statement, params, context, _executemany
261279
):
280+
if not is_instrumentation_enabled():
281+
return statement, params
282+
262283
attrs, found = _get_attributes_from_url(conn.engine.url)
263284
if not found:
264285
attrs = _get_attributes_from_cursor(self.vendor, cursor, attrs)

instrumentation/opentelemetry-instrumentation-sqlalchemy/tests/test_sqlalchemy.py

Lines changed: 65 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,11 @@
2323
)
2424

2525
from opentelemetry import trace
26-
from opentelemetry.instrumentation.sqlalchemy import SQLAlchemyInstrumentor
26+
from opentelemetry.instrumentation.sqlalchemy import (
27+
EngineTracer,
28+
SQLAlchemyInstrumentor,
29+
)
30+
from opentelemetry.instrumentation.utils import suppress_instrumentation
2731
from opentelemetry.sdk.resources import Resource
2832
from opentelemetry.sdk.trace import TracerProvider, export
2933
from opentelemetry.semconv.trace import SpanAttributes
@@ -630,3 +634,63 @@ def make_shortlived_engine():
630634
gc.collect()
631635
assert callback.call_count == 5
632636
assert len(EngineTracer._remove_event_listener_params) == 0
637+
638+
def test_suppress_instrumentation_create_engine(self):
639+
SQLAlchemyInstrumentor().instrument()
640+
641+
from sqlalchemy import create_engine
642+
643+
with suppress_instrumentation():
644+
engine = create_engine("sqlite:///:memory:")
645+
646+
self.assertTrue(not isinstance(engine, EngineTracer))
647+
648+
@pytest.mark.skipif(
649+
not sqlalchemy.__version__.startswith("1.4"),
650+
reason="only run async tests for 1.4",
651+
)
652+
def test_suppress_instrumentation_create_async_engine(self):
653+
async def run():
654+
SQLAlchemyInstrumentor().instrument()
655+
from sqlalchemy.ext.asyncio import ( # pylint: disable-all
656+
create_async_engine,
657+
)
658+
659+
with suppress_instrumentation():
660+
engine = create_async_engine("sqlite+aiosqlite:///:memory:")
661+
662+
self.assertTrue(not isinstance(engine, EngineTracer))
663+
664+
asyncio.get_event_loop().run_until_complete(run())
665+
666+
def test_suppress_instrumentation_connect(self):
667+
engine = create_engine("sqlite:///:memory:")
668+
SQLAlchemyInstrumentor().instrument(
669+
engine=engine,
670+
tracer_provider=self.tracer_provider,
671+
)
672+
673+
with suppress_instrumentation():
674+
with engine.connect():
675+
pass
676+
677+
spans_list = self.memory_exporter.get_finished_spans()
678+
self.assertEqual(len(spans_list), 0)
679+
680+
def test_suppress_instrumentation_cursor_and_metric(self):
681+
engine = create_engine("sqlite:///:memory:")
682+
SQLAlchemyInstrumentor().instrument(
683+
engine=engine,
684+
tracer_provider=self.tracer_provider,
685+
enable_commenter=True,
686+
)
687+
688+
with suppress_instrumentation():
689+
with engine.connect() as conn:
690+
conn.execute(text("SELECT 1 + 1;")).fetchall()
691+
692+
spans_list = self.memory_exporter.get_finished_spans()
693+
self.assertEqual(len(spans_list), 0)
694+
695+
metric_list = self.get_sorted_metrics()
696+
self.assertEqual(len(metric_list), 0)

0 commit comments

Comments
 (0)