Skip to content

Commit 819a630

Browse files
authored
Merge pull request #114 from kormax/slow_callback_duration_logging
Add slow_callback_duration logging
2 parents 05a34ca + 4a85fb7 commit 819a630

2 files changed

Lines changed: 40 additions & 2 deletions

File tree

qasync/__init__.py

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,13 @@ def __exit__(self, *args):
226226
self.shutdown()
227227

228228

229+
def _format_handle(handle: asyncio.Handle):
230+
cb = getattr(handle, "_callback", None)
231+
if isinstance(getattr(cb, '__self__', None), asyncio.tasks.Task):
232+
return repr(cb.__self__)
233+
return str(handle)
234+
235+
229236
def _make_signaller(qtimpl_qtcore, *args):
230237
class Signaller(qtimpl_qtcore.QObject):
231238
try:
@@ -268,8 +275,22 @@ def timerEvent(self, event): # noqa: N802
268275
if handle._cancelled:
269276
self.__log_debug("Handle %s cancelled", handle)
270277
else:
271-
self.__log_debug("Calling handle %s", handle)
272-
handle._run()
278+
if self.__debug_enabled:
279+
# This may not be the most efficient thing to do, but it removes the need to sync
280+
# "slow_callback_duration" and "_current_handle" variables
281+
loop = asyncio.get_event_loop()
282+
try:
283+
loop._current_handle = handle
284+
self._logger.debug("Calling handle %s", handle)
285+
t0 = time.time()
286+
handle._run()
287+
dt = time.time() - t0
288+
if dt >= loop.slow_callback_duration:
289+
self._logger.warning('Executing %s took %.3f seconds', _format_handle(handle), dt)
290+
finally:
291+
loop._current_handle = None
292+
else:
293+
handle._run()
273294
finally:
274295
del self.__callbacks[timerid]
275296
handle = None

tests/test_qeventloop.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import socket
1212
import subprocess
1313
import sys
14+
import time
1415
from concurrent.futures import ProcessPoolExecutor, ThreadPoolExecutor
1516

1617
import pytest
@@ -791,6 +792,22 @@ async def mycoro():
791792
assert not loop.is_running()
792793

793794

795+
def test_slow_callback_duration_logging(loop, caplog):
796+
async def mycoro():
797+
time.sleep(1)
798+
799+
caplog.clear()
800+
loop.set_debug(True)
801+
loop.slow_callback_duration = 0.1
802+
with caplog.at_level(logging.WARNING):
803+
loop.run_until_complete(mycoro())
804+
assert len(caplog.records) == 1
805+
msg = caplog.records[0].message
806+
assert "Executing" in msg
807+
assert "took" in msg
808+
assert "seconds" in msg
809+
810+
794811
def teardown_module(module):
795812
"""
796813
Remove handlers from all loggers

0 commit comments

Comments
 (0)