Improve tracing of sqlalchemy
Use before_cursor_execute and after_cursor_execute instead of before_execute and after_execute. 1) Migration with custom types will work now (even if tracing is enabled) 2) We don't need to render 2 times SQL expressesion => less overhead Change-Id: I7c6b6909ce0f15a69ce5caad544e1351a647b472
This commit is contained in:
parent
a51b110576
commit
a6ad8da299
@ -20,11 +20,7 @@ _DISABLED = False
|
|||||||
|
|
||||||
|
|
||||||
def disable():
|
def disable():
|
||||||
"""add_tracing does not add event listeners for sqlalchemy.
|
"""Disable tracing of all DB queries. Reduce a lot size of profiles."""
|
||||||
|
|
||||||
This is quite important in case of sql migrations. Because it's not allowed
|
|
||||||
to add these events.
|
|
||||||
"""
|
|
||||||
global _DISABLED
|
global _DISABLED
|
||||||
_DISABLED = True
|
_DISABLED = True
|
||||||
|
|
||||||
@ -40,27 +36,26 @@ def add_tracing(sqlalchemy, engine, name):
|
|||||||
"""Add tracing to all sqlalchemy calls."""
|
"""Add tracing to all sqlalchemy calls."""
|
||||||
|
|
||||||
if not _DISABLED:
|
if not _DISABLED:
|
||||||
sqlalchemy.event.listen(engine, 'before_execute',
|
sqlalchemy.event.listen(engine, 'before_cursor_execute',
|
||||||
_before_execute(name))
|
_before_cursor_execute(name))
|
||||||
sqlalchemy.event.listen(engine, 'after_execute', _after_execute())
|
sqlalchemy.event.listen(engine, 'after_cursor_execute',
|
||||||
|
_after_cursor_execute())
|
||||||
|
|
||||||
|
|
||||||
def _before_execute(name):
|
def _before_cursor_execute(name):
|
||||||
"""Add listener that will send trace info before query is executed."""
|
"""Add listener that will send trace info before query is executed."""
|
||||||
|
|
||||||
def handler(conn, clauseelement, multiparams, params):
|
def handler(conn, cursor, statement, params, context, executemany):
|
||||||
info = {"db.statement": str(clauseelement),
|
info = {"db.statement": statement, "db.params": params}
|
||||||
"db.multiparams": str(multiparams),
|
|
||||||
"db.params": str(params)}
|
|
||||||
profiler.start(name, info=info)
|
profiler.start(name, info=info)
|
||||||
|
|
||||||
return handler
|
return handler
|
||||||
|
|
||||||
|
|
||||||
def _after_execute():
|
def _after_cursor_execute():
|
||||||
"""Add listener that will send trace info after query is executed."""
|
"""Add listener that will send trace info after query is executed."""
|
||||||
|
|
||||||
def handler(conn, clauseelement, multiparams, params, result):
|
def handler(conn, cursor, statement, params, context, executemany):
|
||||||
profiler.stop(info=None)
|
profiler.stop()
|
||||||
|
|
||||||
return handler
|
return handler
|
||||||
|
@ -24,24 +24,23 @@ class SqlalchemyTracingTestCase(test.TestCase):
|
|||||||
|
|
||||||
@mock.patch("osprofiler.sqlalchemy.profiler")
|
@mock.patch("osprofiler.sqlalchemy.profiler")
|
||||||
def test_before_execute(self, mock_profiler):
|
def test_before_execute(self, mock_profiler):
|
||||||
handler = sqlalchemy._before_execute("sql")
|
handler = sqlalchemy._before_cursor_execute("sql")
|
||||||
|
|
||||||
handler(mock.MagicMock(), 1, 2, 3)
|
handler(mock.MagicMock(), 1, 2, 3, 4, 5)
|
||||||
expected_info = {
|
expected_info = {
|
||||||
"db.statement": "1",
|
"db.statement": 2,
|
||||||
"db.multiparams": "2",
|
"db.params": 3
|
||||||
"db.params": "3"
|
|
||||||
}
|
}
|
||||||
mock_profiler.start.assert_called_once_with("sql", info=expected_info)
|
mock_profiler.start.assert_called_once_with("sql", info=expected_info)
|
||||||
|
|
||||||
@mock.patch("osprofiler.sqlalchemy.profiler")
|
@mock.patch("osprofiler.sqlalchemy.profiler")
|
||||||
def test_after_execute(self, mock_profiler):
|
def test_after_execute(self, mock_profiler):
|
||||||
handler = sqlalchemy._after_execute()
|
handler = sqlalchemy._after_cursor_execute()
|
||||||
handler(mock.MagicMock(), 1, 2, 3, mock.MagicMock())
|
handler(mock.MagicMock(), 1, 2, 3, 4, 5)
|
||||||
mock_profiler.stop.assert_called_once_with(info=None)
|
mock_profiler.stop.assert_called_once_with()
|
||||||
|
|
||||||
@mock.patch("osprofiler.sqlalchemy._before_execute")
|
@mock.patch("osprofiler.sqlalchemy._before_cursor_execute")
|
||||||
@mock.patch("osprofiler.sqlalchemy._after_execute")
|
@mock.patch("osprofiler.sqlalchemy._after_cursor_execute")
|
||||||
def test_add_tracing(self, mock_after_exc, mock_before_exc):
|
def test_add_tracing(self, mock_after_exc, mock_before_exc):
|
||||||
sa = mock.MagicMock()
|
sa = mock.MagicMock()
|
||||||
engine = mock.MagicMock()
|
engine = mock.MagicMock()
|
||||||
@ -54,13 +53,13 @@ class SqlalchemyTracingTestCase(test.TestCase):
|
|||||||
mock_before_exc.assert_called_once_with("sql")
|
mock_before_exc.assert_called_once_with("sql")
|
||||||
mock_after_exc.assert_called_once_with()
|
mock_after_exc.assert_called_once_with()
|
||||||
expected_calls = [
|
expected_calls = [
|
||||||
mock.call(engine, "before_execute", "before"),
|
mock.call(engine, "before_cursor_execute", "before"),
|
||||||
mock.call(engine, "after_execute", "after")
|
mock.call(engine, "after_cursor_execute", "after")
|
||||||
]
|
]
|
||||||
self.assertEqual(sa.event.listen.call_args_list, expected_calls)
|
self.assertEqual(sa.event.listen.call_args_list, expected_calls)
|
||||||
|
|
||||||
@mock.patch("osprofiler.sqlalchemy._before_execute")
|
@mock.patch("osprofiler.sqlalchemy._before_cursor_execute")
|
||||||
@mock.patch("osprofiler.sqlalchemy._after_execute")
|
@mock.patch("osprofiler.sqlalchemy._after_cursor_execute")
|
||||||
def test_disable_and_enable(self, mock_after_exc, mock_before_exc):
|
def test_disable_and_enable(self, mock_after_exc, mock_before_exc):
|
||||||
sqlalchemy.disable()
|
sqlalchemy.disable()
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user