Log unhandled loop exception traces when asyncio debug is on (#57602)

This commit is contained in:
J. Nick Koston 2021-10-18 17:07:51 -10:00 committed by GitHub
parent f92fe38bbd
commit 6576225c48
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 36 additions and 3 deletions

View File

@ -5,6 +5,7 @@ import asyncio
import dataclasses import dataclasses
import logging import logging
import threading import threading
import traceback
from typing import Any from typing import Any
from homeassistant import bootstrap from homeassistant import bootstrap
@ -86,9 +87,15 @@ def _async_loop_exception_handler(_: Any, context: dict[str, Any]) -> None:
if exception := context.get("exception"): if exception := context.get("exception"):
kwargs["exc_info"] = (type(exception), exception, exception.__traceback__) kwargs["exc_info"] = (type(exception), exception, exception.__traceback__)
logging.getLogger(__package__).error( logger = logging.getLogger(__package__)
"Error doing job: %s", context["message"], **kwargs # type: ignore if source_traceback := context.get("source_traceback"):
) stack_summary = "".join(traceback.format_list(source_traceback))
logger.error(
"Error doing job: %s: %s", context["message"], stack_summary, **kwargs # type: ignore
)
return
logger.error("Error doing job: %s", context["message"], **kwargs) # type: ignore
async def setup_and_run_hass(runtime_config: RuntimeConfig) -> int: async def setup_and_run_hass(runtime_config: RuntimeConfig) -> int:

View File

@ -1,5 +1,11 @@
"""List of tests that have uncaught exceptions today. Will be shrunk over time.""" """List of tests that have uncaught exceptions today. Will be shrunk over time."""
IGNORE_UNCAUGHT_EXCEPTIONS = [ IGNORE_UNCAUGHT_EXCEPTIONS = [
(
# This test explicitly throws an uncaught exception
# and should not be removed.
"tests.test_runner",
"test_unhandled_exception_traceback",
),
( (
"test_homeassistant_bridge", "test_homeassistant_bridge",
"test_homeassistant_bridge_fan_setup", "test_homeassistant_bridge_fan_setup",

View File

@ -117,3 +117,23 @@ def test_run_does_not_block_forever_with_shielded_task(hass, tmpdir, caplog):
assert ( assert (
"Task could not be canceled and was still running after shutdown" in caplog.text "Task could not be canceled and was still running after shutdown" in caplog.text
) )
async def test_unhandled_exception_traceback(hass, caplog):
"""Test an unhandled exception gets a traceback in debug mode."""
async def _unhandled_exception():
raise Exception("This is unhandled")
try:
hass.loop.set_debug(True)
asyncio.create_task(_unhandled_exception())
finally:
hass.loop.set_debug(False)
await asyncio.sleep(0)
await asyncio.sleep(0)
assert "Task exception was never retrieved" in caplog.text
assert "This is unhandled" in caplog.text
assert "_unhandled_exception" in caplog.text