Skip to content

Commit 0a7cbdf

Browse files
committed
Change the code to save all listen params so we will know how to remove them when uninstument
1 parent 0bac6a0 commit 0a7cbdf

File tree

3 files changed

+44
-24
lines changed

3 files changed

+44
-24
lines changed

Diff for: instrumentation/opentelemetry-instrumentation-sqlalchemy/src/opentelemetry/instrumentation/sqlalchemy/__init__.py

+7-16
Original file line numberDiff line numberDiff line change
@@ -119,8 +119,6 @@ class SQLAlchemyInstrumentor(BaseInstrumentor):
119119
See `BaseInstrumentor`
120120
"""
121121

122-
engines = []
123-
124122
def instrumentation_dependencies(self) -> Collection[str]:
125123
return _instruments
126124

@@ -160,22 +158,17 @@ def _instrument(self, **kwargs):
160158
"create_async_engine",
161159
_wrap_create_async_engine(tracer_provider, enable_commenter),
162160
)
163-
164-
self.engines = []
165161
if kwargs.get("engine") is not None:
166-
self.engines.append(
167-
EngineTracer(
168-
_get_tracer(tracer_provider),
169-
kwargs.get("engine"),
170-
kwargs.get("enable_commenter", False),
171-
kwargs.get("commenter_options", {}),
172-
)
162+
return EngineTracer(
163+
_get_tracer(tracer_provider),
164+
kwargs.get("engine"),
165+
kwargs.get("enable_commenter", False),
166+
kwargs.get("commenter_options", {}),
173167
)
174-
return self.engines[0]
175168
if kwargs.get("engines") is not None and isinstance(
176169
kwargs.get("engines"), Sequence
177170
):
178-
self.engines = [
171+
return [
179172
EngineTracer(
180173
_get_tracer(tracer_provider),
181174
engine,
@@ -184,7 +177,6 @@ def _instrument(self, **kwargs):
184177
)
185178
for engine in kwargs.get("engines")
186179
]
187-
return self.engines
188180

189181
return None
190182

@@ -194,5 +186,4 @@ def _uninstrument(self, **kwargs):
194186
unwrap(Engine, "connect")
195187
if parse_version(sqlalchemy.__version__).release >= (1, 4):
196188
unwrap(sqlalchemy.ext.asyncio, "create_async_engine")
197-
for engine in self.engines:
198-
engine.remove_event_listeners()
189+
EngineTracer.remove_all_event_listeners()

Diff for: instrumentation/opentelemetry-instrumentation-sqlalchemy/src/opentelemetry/instrumentation/sqlalchemy/engine.py

+18-8
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,8 @@ def _wrap_connect_internal(func, module, args, kwargs):
9898

9999

100100
class EngineTracer:
101+
_removeEventListenerParams = []
102+
101103
def __init__(
102104
self, tracer, engine, enable_commenter=False, commenter_options=None
103105
):
@@ -108,16 +110,24 @@ def __init__(
108110
self.commenter_options = commenter_options if commenter_options else {}
109111
self._leading_comment_remover = re.compile(r"^/\*.*?\*/")
110112

111-
listen(
113+
self._register_event_listener(
112114
engine, "before_cursor_execute", self._before_cur_exec, retval=True
113115
)
114-
listen(engine, "after_cursor_execute", _after_cur_exec)
115-
listen(engine, "handle_error", _handle_error)
116-
117-
def remove_event_listeners(self):
118-
remove(self.engine, "before_cursor_execute", self._before_cur_exec)
119-
remove(self.engine, "after_cursor_execute", _after_cur_exec)
120-
remove(self.engine, "handle_error", _handle_error)
116+
self._register_event_listener(
117+
engine, "after_cursor_execute", _after_cur_exec
118+
)
119+
self._register_event_listener(engine, "handle_error", _handle_error)
120+
121+
@classmethod
122+
def _register_event_listener(cls, target, identifier, fn, *args, **kw):
123+
listen(target, identifier, fn, *args, **kw)
124+
cls._removeEventListenerParams.append((target, identifier, fn))
125+
126+
@classmethod
127+
def remove_all_event_listeners(cls):
128+
for removeParams in cls._removeEventListenerParams:
129+
remove(*removeParams)
130+
cls._removeEventListenerParams.clear()
121131

122132
def _operation_name(self, db_name, statement):
123133
parts = []

Diff for: instrumentation/opentelemetry-instrumentation-sqlalchemy/tests/test_sqlalchemy.py

+19
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,25 @@ def test_uninstrument(self):
255255
spans = self.memory_exporter.get_finished_spans()
256256
self.assertEqual(len(spans), 0)
257257

258+
def test_uninstrument_without_engine(self):
259+
SQLAlchemyInstrumentor().instrument(
260+
tracer_provider=self.tracer_provider
261+
)
262+
from sqlalchemy import create_engine
263+
264+
engine = create_engine("sqlite:///:memory:")
265+
266+
cnx = engine.connect()
267+
cnx.execute("SELECT 1 + 1;").fetchall()
268+
spans = self.memory_exporter.get_finished_spans()
269+
self.assertEqual(len(spans), 2)
270+
271+
self.memory_exporter.clear()
272+
SQLAlchemyInstrumentor().uninstrument()
273+
cnx.execute("SELECT 1 + 1;").fetchall()
274+
spans = self.memory_exporter.get_finished_spans()
275+
self.assertEqual(len(spans), 0)
276+
258277
def test_no_op_tracer_provider(self):
259278
engine = create_engine("sqlite:///:memory:")
260279
SQLAlchemyInstrumentor().instrument(

0 commit comments

Comments
 (0)