-
Notifications
You must be signed in to change notification settings - Fork 682
Fix sqlalchemy uninstrument #1581
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
Changes from 4 commits
8cd9168
3536964
0975434
0bac6a0
8edb72a
df24e6b
7fca774
c85c256
c883c48
e12a2b2
2a0e744
ec12619
1f8b2a2
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -14,7 +14,10 @@ | |
import os | ||
import re | ||
|
||
from sqlalchemy.event import listen # pylint: disable=no-name-in-module | ||
from sqlalchemy.event import ( # pylint: disable=no-name-in-module | ||
listen, | ||
remove, | ||
) | ||
|
||
from opentelemetry import trace | ||
from opentelemetry.instrumentation.sqlalchemy.package import ( | ||
|
@@ -111,6 +114,11 @@ def __init__( | |
listen(engine, "after_cursor_execute", _after_cur_exec) | ||
listen(engine, "handle_error", _handle_error) | ||
|
||
def remove_event_listeners(self): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. its a private method should start with There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's not a private method, I need to use this function from sqlalchemy |
||
remove(self.engine, "before_cursor_execute", self._before_cur_exec) | ||
remove(self.engine, "after_cursor_execute", _after_cur_exec) | ||
remove(self.engine, "handle_error", _handle_error) | ||
|
||
def _operation_name(self, db_name, statement): | ||
parts = [] | ||
if isinstance(statement, str): | ||
|
Original file line number | Diff line number | Diff line change | ||
---|---|---|---|---|
|
@@ -248,6 +248,7 @@ def test_uninstrument(self): | |||
|
||||
self.memory_exporter.clear() | ||||
SQLAlchemyInstrumentor().uninstrument() | ||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please dont call def test_uninstrument(self):
engine = create_engine("sqlite:///:memory:")
instrumentor = SQLAlchemyInstrumentor()
instrumentor.instrument(
engine=engine,
tracer_provider=self.tracer_provider,
)
cnx = engine.connect()
cnx.execute("SELECT 1 + 1;").fetchall()
spans = self.memory_exporter.get_finished_spans()
self.assertEqual(len(spans), 2)
# first span - the connection to the db
self.assertEqual(spans[0].name, "connect")
self.assertEqual(spans[0].kind, trace.SpanKind.CLIENT)
# second span - the query itself
self.assertEqual(spans[1].name, "SELECT :memory:")
self.assertEqual(spans[1].kind, trace.SpanKind.CLIENT)
self.memory_exporter.clear()
instrumentor.uninstrument()
cnx.execute("SELECT 2 + 2;").fetchall()
spans = self.memory_exporter.get_finished_spans()
self.assertEqual(len(spans), 0) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure, can you explain what's the difference? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We dont want to create additional instrumentor class with new connection and new engine, There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It will not create another sqlalchemy instrumentor, if I understand this correctly it's like Singelton: Line 50 in c92ba14
What do you think? |
||||
cnx.execute("SELECT 1 + 1;").fetchall() | ||||
engine2 = create_engine("sqlite:///:memory:") | ||||
cnx2 = engine2.connect() | ||||
cnx2.execute("SELECT 2 + 2;").fetchall() | ||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there any reason to keep list of engines, why is it necessary to keep all the engines in array?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can create one engine or engines, so if I keep them in array it will be easier to clean up
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No problem, We should consider to remove the engine from that list when python finalize the engine by the garbage collector or when the user deleting the engine, otherwise potentially a memory leak could happen
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i wonder if we should implement call uninstrument logic when the garbage collector trying to collect the engine
https://docs.python.org/3.6/library/weakref.html#finalizer-objects
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought about this but the problem is after the instrumentation the EngineTracer returns to the user and we can't be sure the user delete it and when the garbage collector works
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for the comments