Here is the new POC emitting sys.audit hooks.
Here is some sample usage:
import asyncio
import sys
def audit_hook(event, args):
if not event.startswith("asyncio."):
return
print(event, args)
sys.addaudithook(audit_hook)
async def work():
await asyncio.sleep(0.1)
await asyncio.sleep(0.1)
async def main():
await asyncio.gather(work(), work(), work())
if __name__ == "__main__":
asyncio.run(main())
and output log:
❯ python sample.py
asyncio.task.register (<Task pending name='Task-1' coro=<main() running at /Users/brett.langdon/src/cpython/sample.py:20>>,)
asyncio.task.enter (<Task pending name='Task-1' coro=<main() running at /Users/brett.langdon/src/cpython/sample.py:20> cb=[_run_until_complete_cb() at /Users/brett.langdon/src/cpython/Lib/asyncio/base_events.py:182]>,)
asyncio.task.register (<Task pending name='Task-2' coro=<work() running at /Users/brett.langdon/src/cpython/sample.py:15>>,)
asyncio.task.register (<Task pending name='Task-3' coro=<work() running at /Users/brett.langdon/src/cpython/sample.py:15>>,)
asyncio.task.register (<Task pending name='Task-4' coro=<work() running at /Users/brett.langdon/src/cpython/sample.py:15>>,)
asyncio.task.leave (<Task pending name='Task-1' coro=<main() running at /Users/brett.langdon/src/cpython/sample.py:21> wait_for=<_GatheringFuture pending cb=[Task.task_wakeup()]> cb=[_run_until_complete_cb() at /Users/brett.langdon/src/cpython/Lib/asyncio/base_events.py:182]>,)
asyncio.task.enter (<Task pending name='Task-2' coro=<work() running at /Users/brett.langdon/src/cpython/sample.py:15> cb=[gather.<locals>._done_callback() at /Users/brett.langdon/src/cpython/Lib/asyncio/tasks.py:767]>,)
asyncio.task.leave (<Task pending name='Task-2' coro=<work() running at /Users/brett.langdon/src/cpython/sample.py:16> wait_for=<Future pending cb=[Task.task_wakeup()]> cb=[gather.<locals>._done_callback() at /Users/brett.langdon/src/cpython/Lib/asyncio/tasks.py:767]>,)
asyncio.task.enter (<Task pending name='Task-3' coro=<work() running at /Users/brett.langdon/src/cpython/sample.py:15> cb=[gather.<locals>._done_callback() at /Users/brett.langdon/src/cpython/Lib/asyncio/tasks.py:767]>,)
asyncio.task.leave (<Task pending name='Task-3' coro=<work() running at /Users/brett.langdon/src/cpython/sample.py:16> wait_for=<Future pending cb=[Task.task_wakeup()]> cb=[gather.<locals>._done_callback() at /Users/brett.langdon/src/cpython/Lib/asyncio/tasks.py:767]>,)
asyncio.task.enter (<Task pending name='Task-4' coro=<work() running at /Users/brett.langdon/src/cpython/sample.py:15> cb=[gather.<locals>._done_callback() at /Users/brett.langdon/src/cpython/Lib/asyncio/tasks.py:767]>,)
asyncio.task.leave (<Task pending name='Task-4' coro=<work() running at /Users/brett.langdon/src/cpython/sample.py:16> wait_for=<Future pending cb=[Task.task_wakeup()]> cb=[gather.<locals>._done_callback() at /Users/brett.langdon/src/cpython/Lib/asyncio/tasks.py:767]>,)
asyncio.task.enter (<Task pending name='Task-2' coro=<work() running at /Users/brett.langdon/src/cpython/sample.py:16> wait_for=<Future finished result=None> cb=[gather.<locals>._done_callback() at /Users/brett.langdon/src/cpython/Lib/asyncio/tasks.py:767]>,)
asyncio.task.leave (<Task pending name='Task-2' coro=<work() running at /Users/brett.langdon/src/cpython/sample.py:17> wait_for=<Future pending cb=[Task.task_wakeup()]> cb=[gather.<locals>._done_callback() at /Users/brett.langdon/src/cpython/Lib/asyncio/tasks.py:767]>,)
asyncio.task.enter (<Task pending name='Task-3' coro=<work() running at /Users/brett.langdon/src/cpython/sample.py:16> wait_for=<Future finished result=None> cb=[gather.<locals>._done_callback() at /Users/brett.langdon/src/cpython/Lib/asyncio/tasks.py:767]>,)
asyncio.task.leave (<Task pending name='Task-3' coro=<work() running at /Users/brett.langdon/src/cpython/sample.py:17> wait_for=<Future pending cb=[Task.task_wakeup()]> cb=[gather.<locals>._done_callback() at /Users/brett.langdon/src/cpython/Lib/asyncio/tasks.py:767]>,)
asyncio.task.enter (<Task pending name='Task-4' coro=<work() running at /Users/brett.langdon/src/cpython/sample.py:16> wait_for=<Future finished result=None> cb=[gather.<locals>._done_callback() at /Users/brett.langdon/src/cpython/Lib/asyncio/tasks.py:767]>,)
asyncio.task.leave (<Task pending name='Task-4' coro=<work() running at /Users/brett.langdon/src/cpython/sample.py:17> wait_for=<Future pending cb=[Task.task_wakeup()]> cb=[gather.<locals>._done_callback() at /Users/brett.langdon/src/cpython/Lib/asyncio/tasks.py:767]>,)
asyncio.task.enter (<Task pending name='Task-2' coro=<work() running at /Users/brett.langdon/src/cpython/sample.py:17> wait_for=<Future finished result=None> cb=[gather.<locals>._done_callback() at /Users/brett.langdon/src/cpython/Lib/asyncio/tasks.py:767]>,)
asyncio.task.leave (<Task finished name='Task-2' coro=<work() done, defined at /Users/brett.langdon/src/cpython/sample.py:15> result=None>,)
asyncio.task.enter (<Task pending name='Task-3' coro=<work() running at /Users/brett.langdon/src/cpython/sample.py:17> wait_for=<Future finished result=None> cb=[gather.<locals>._done_callback() at /Users/brett.langdon/src/cpython/Lib/asyncio/tasks.py:767]>,)
asyncio.task.leave (<Task finished name='Task-3' coro=<work() done, defined at /Users/brett.langdon/src/cpython/sample.py:15> result=None>,)
asyncio.task.enter (<Task pending name='Task-4' coro=<work() running at /Users/brett.langdon/src/cpython/sample.py:17> wait_for=<Future finished result=None> cb=[gather.<locals>._done_callback() at /Users/brett.langdon/src/cpython/Lib/asyncio/tasks.py:767]>,)
asyncio.task.leave (<Task finished name='Task-4' coro=<work() done, defined at /Users/brett.langdon/src/cpython/sample.py:15> result=None>,)
asyncio.task.enter (<Task pending name='Task-1' coro=<main() running at /Users/brett.langdon/src/cpython/sample.py:21> wait_for=<_GatheringFuture finished result=[None, None, None]> cb=[_run_until_complete_cb() at /Users/brett.langdon/src/cpython/Lib/asyncio/base_events.py:182]>,)
asyncio.task.leave (<Task finished name='Task-1' coro=<main() done, defined at /Users/brett.langdon/src/cpython/sample.py:20> result=None>,)
asyncio.task.register (<Task pending name='Task-5' coro=<BaseEventLoop.shutdown_asyncgens() running at /Users/brett.langdon/src/cpython/Lib/asyncio/base_events.py:561>>,)
asyncio.task.enter (<Task pending name='Task-5' coro=<BaseEventLoop.shutdown_asyncgens() running at /Users/brett.langdon/src/cpython/Lib/asyncio/base_events.py:561> cb=[_run_until_complete_cb() at /Users/brett.langdon/src/cpython/Lib/asyncio/base_events.py:182]>,)
asyncio.task.leave (<Task finished name='Task-5' coro=<BaseEventLoop.shutdown_asyncgens() done, defined at /Users/brett.langdon/src/cpython/Lib/asyncio/base_events.py:561> result=None>,)
asyncio.task.register (<Task pending name='Task-6' coro=<BaseEventLoop.shutdown_default_executor() running at /Users/brett.langdon/src/cpython/Lib/asyncio/base_events.py:586>>,)
asyncio.task.enter (<Task pending name='Task-6' coro=<BaseEventLoop.shutdown_default_executor() running at /Users/brett.langdon/src/cpython/Lib/asyncio/base_events.py:586> cb=[_run_until_complete_cb() at /Users/brett.langdon/src/cpython/Lib/asyncio/base_events.py:182]>,)
asyncio.task.leave (<Task finished name='Task-6' coro=<BaseEventLoop.shutdown_default_executor() done, defined at /Users/brett.langdon/src/cpython/Lib/asyncio/base_events.py:586> result=None>,)
Here is another sample using uvloop:
import asyncio
import sys
def audit_hook(event, args):
if not event.startswith("asyncio."):
return
print(event, args)
sys.addaudithook(audit_hook)
async def work():
await asyncio.sleep(0.1)
await asyncio.sleep(0.1)
async def main():
await asyncio.gather(work(), work(), work())
if __name__ == "__main__":
import uvloop
uvloop.run(main())
# also works with
# with asyncio.Runner(loop_factory=uvloop.new_event_loop) as runner:
# runner.run(main())
# and
# uvloop.install()
# asyncio.run(main())
❯ python sample.py
asyncio.task.register (<Task pending name='Task-1' coro=<run.<locals>.wrapper() running at /Users/brett.langdon/src/cpython/.venv/lib/python3.12/site-packages/uvloop/__init__.py:54>>,)
asyncio.task.enter (<Task pending name='Task-1' coro=<run.<locals>.wrapper() running at /Users/brett.langdon/src/cpython/.venv/lib/python3.12/site-packages/uvloop/__init__.py:54> cb=[run_until_complete.<locals>.done_cb()]>,)
asyncio.task.register (<Task pending name='Task-2' coro=<work() running at /Users/brett.langdon/src/cpython/sample.py:15>>,)
asyncio.task.register (<Task pending name='Task-3' coro=<work() running at /Users/brett.langdon/src/cpython/sample.py:15>>,)
asyncio.task.register (<Task pending name='Task-4' coro=<work() running at /Users/brett.langdon/src/cpython/sample.py:15>>,)
asyncio.task.leave (<Task pending name='Task-1' coro=<run.<locals>.wrapper() running at /Users/brett.langdon/src/cpython/.venv/lib/python3.12/site-packages/uvloop/__init__.py:61> wait_for=<_GatheringFuture pending cb=[Task.task_wakeup()]> cb=[run_until_complete.<locals>.done_cb()]>,)
asyncio.task.enter (<Task pending name='Task-2' coro=<work() running at /Users/brett.langdon/src/cpython/sample.py:15> cb=[gather.<locals>._done_callback() at /Users/brett.langdon/src/cpython/Lib/asyncio/tasks.py:767]>,)
asyncio.task.leave (<Task pending name='Task-2' coro=<work() running at /Users/brett.langdon/src/cpython/sample.py:16> wait_for=<Future pending cb=[Task.task_wakeup()]> cb=[gather.<locals>._done_callback() at /Users/brett.langdon/src/cpython/Lib/asyncio/tasks.py:767]>,)
asyncio.task.enter (<Task pending name='Task-3' coro=<work() running at /Users/brett.langdon/src/cpython/sample.py:15> cb=[gather.<locals>._done_callback() at /Users/brett.langdon/src/cpython/Lib/asyncio/tasks.py:767]>,)
asyncio.task.leave (<Task pending name='Task-3' coro=<work() running at /Users/brett.langdon/src/cpython/sample.py:16> wait_for=<Future pending cb=[Task.task_wakeup()]> cb=[gather.<locals>._done_callback() at /Users/brett.langdon/src/cpython/Lib/asyncio/tasks.py:767]>,)
asyncio.task.enter (<Task pending name='Task-4' coro=<work() running at /Users/brett.langdon/src/cpython/sample.py:15> cb=[gather.<locals>._done_callback() at /Users/brett.langdon/src/cpython/Lib/asyncio/tasks.py:767]>,)
asyncio.task.leave (<Task pending name='Task-4' coro=<work() running at /Users/brett.langdon/src/cpython/sample.py:16> wait_for=<Future pending cb=[Task.task_wakeup()]> cb=[gather.<locals>._done_callback() at /Users/brett.langdon/src/cpython/Lib/asyncio/tasks.py:767]>,)
asyncio.task.enter (<Task pending name='Task-2' coro=<work() running at /Users/brett.langdon/src/cpython/sample.py:16> wait_for=<Future finished result=None> cb=[gather.<locals>._done_callback() at /Users/brett.langdon/src/cpython/Lib/asyncio/tasks.py:767]>,)
asyncio.task.leave (<Task pending name='Task-2' coro=<work() running at /Users/brett.langdon/src/cpython/sample.py:17> wait_for=<Future pending cb=[Task.task_wakeup()]> cb=[gather.<locals>._done_callback() at /Users/brett.langdon/src/cpython/Lib/asyncio/tasks.py:767]>,)
asyncio.task.enter (<Task pending name='Task-3' coro=<work() running at /Users/brett.langdon/src/cpython/sample.py:16> wait_for=<Future finished result=None> cb=[gather.<locals>._done_callback() at /Users/brett.langdon/src/cpython/Lib/asyncio/tasks.py:767]>,)
asyncio.task.leave (<Task pending name='Task-3' coro=<work() running at /Users/brett.langdon/src/cpython/sample.py:17> wait_for=<Future pending cb=[Task.task_wakeup()]> cb=[gather.<locals>._done_callback() at /Users/brett.langdon/src/cpython/Lib/asyncio/tasks.py:767]>,)
asyncio.task.enter (<Task pending name='Task-4' coro=<work() running at /Users/brett.langdon/src/cpython/sample.py:16> wait_for=<Future finished result=None> cb=[gather.<locals>._done_callback() at /Users/brett.langdon/src/cpython/Lib/asyncio/tasks.py:767]>,)
asyncio.task.leave (<Task pending name='Task-4' coro=<work() running at /Users/brett.langdon/src/cpython/sample.py:17> wait_for=<Future pending cb=[Task.task_wakeup()]> cb=[gather.<locals>._done_callback() at /Users/brett.langdon/src/cpython/Lib/asyncio/tasks.py:767]>,)
asyncio.task.enter (<Task pending name='Task-2' coro=<work() running at /Users/brett.langdon/src/cpython/sample.py:17> wait_for=<Future finished result=None> cb=[gather.<locals>._done_callback() at /Users/brett.langdon/src/cpython/Lib/asyncio/tasks.py:767]>,)
asyncio.task.leave (<Task finished name='Task-2' coro=<work() done, defined at /Users/brett.langdon/src/cpython/sample.py:15> result=None>,)
asyncio.task.enter (<Task pending name='Task-3' coro=<work() running at /Users/brett.langdon/src/cpython/sample.py:17> wait_for=<Future finished result=None> cb=[gather.<locals>._done_callback() at /Users/brett.langdon/src/cpython/Lib/asyncio/tasks.py:767]>,)
asyncio.task.leave (<Task finished name='Task-3' coro=<work() done, defined at /Users/brett.langdon/src/cpython/sample.py:15> result=None>,)
asyncio.task.enter (<Task pending name='Task-4' coro=<work() running at /Users/brett.langdon/src/cpython/sample.py:17> wait_for=<Future finished result=None> cb=[gather.<locals>._done_callback() at /Users/brett.langdon/src/cpython/Lib/asyncio/tasks.py:767]>,)
asyncio.task.leave (<Task finished name='Task-4' coro=<work() done, defined at /Users/brett.langdon/src/cpython/sample.py:15> result=None>,)
asyncio.task.enter (<Task pending name='Task-1' coro=<run.<locals>.wrapper() running at /Users/brett.langdon/src/cpython/.venv/lib/python3.12/site-packages/uvloop/__init__.py:61> wait_for=<_GatheringFuture finished result=[None, None, None]> cb=[run_until_complete.<locals>.done_cb()]>,)
asyncio.task.leave (<Task finished name='Task-1' coro=<run.<locals>.wrapper() done, defined at /Users/brett.langdon/src/cpython/.venv/lib/python3.12/site-packages/uvloop/__init__.py:54> result=None>,)
asyncio.task.register (<Task pending name='Task-5' coro=<Loop.shutdown_asyncgens()>>,)
asyncio.task.enter (<Task pending name='Task-5' coro=<Loop.shutdown_asyncgens()> cb=[run_until_complete.<locals>.done_cb()]>,)
asyncio.task.leave (<Task finished name='Task-5' coro=<<iterable_coroutine without __name__>()> result=None>,)
asyncio.task.register (<Task pending name='Task-6' coro=<Loop.shutdown_default_executor()>>,)
asyncio.task.enter (<Task pending name='Task-6' coro=<Loop.shutdown_default_executor()> cb=[run_until_complete.<locals>.done_cb()]>,)
asyncio.task.leave (<Task finished name='Task-6' coro=<<iterable_coroutine without __name__>()> result=None>,)