Include a traceback for non-strict event loop blocking detection (#118620)

This commit is contained in:
J. Nick Koston 2024-06-02 05:36:25 -05:00 committed by GitHub
parent e976db8443
commit 8f94205014
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 30 additions and 14 deletions

View file

@ -31,17 +31,17 @@ class IntegrationFrame:
integration: str integration: str
module: str | None module: str | None
relative_filename: str relative_filename: str
_frame: FrameType frame: FrameType
@cached_property @cached_property
def line_number(self) -> int: def line_number(self) -> int:
"""Return the line number of the frame.""" """Return the line number of the frame."""
return self._frame.f_lineno return self.frame.f_lineno
@cached_property @cached_property
def filename(self) -> str: def filename(self) -> str:
"""Return the filename of the frame.""" """Return the filename of the frame."""
return self._frame.f_code.co_filename return self.frame.f_code.co_filename
@cached_property @cached_property
def line(self) -> str: def line(self) -> str:
@ -119,7 +119,7 @@ def get_integration_frame(exclude_integrations: set | None = None) -> Integratio
integration=integration, integration=integration,
module=found_module, module=found_module,
relative_filename=found_frame.f_code.co_filename[index:], relative_filename=found_frame.f_code.co_filename[index:],
_frame=found_frame, frame=found_frame,
) )

View file

@ -7,6 +7,7 @@ import functools
import linecache import linecache
import logging import logging
import threading import threading
import traceback
from typing import Any from typing import Any
from homeassistant.core import async_get_hass_or_none from homeassistant.core import async_get_hass_or_none
@ -54,12 +55,14 @@ def raise_for_blocking_call(
if not strict_core: if not strict_core:
_LOGGER.warning( _LOGGER.warning(
"Detected blocking call to %s with args %s in %s, " "Detected blocking call to %s with args %s in %s, "
"line %s: %s inside the event loop", "line %s: %s inside the event loop\n"
"Traceback (most recent call last):\n%s",
func.__name__, func.__name__,
mapped_args.get("args"), mapped_args.get("args"),
offender_filename, offender_filename,
offender_lineno, offender_lineno,
offender_line, offender_line,
"".join(traceback.format_stack(f=offender_frame)),
) )
return return
@ -79,10 +82,9 @@ def raise_for_blocking_call(
) )
_LOGGER.warning( _LOGGER.warning(
(
"Detected blocking call to %s inside the event loop by %sintegration '%s' " "Detected blocking call to %s inside the event loop by %sintegration '%s' "
"at %s, line %s: %s (offender: %s, line %s: %s), please %s" "at %s, line %s: %s (offender: %s, line %s: %s), please %s\n"
), "Traceback (most recent call last):\n%s",
func.__name__, func.__name__,
"custom " if integration_frame.custom_integration else "", "custom " if integration_frame.custom_integration else "",
integration_frame.integration, integration_frame.integration,
@ -93,6 +95,7 @@ def raise_for_blocking_call(
offender_lineno, offender_lineno,
offender_line, offender_line,
report_issue, report_issue,
"".join(traceback.format_stack(f=integration_frame.frame)),
) )
if strict: if strict:

View file

@ -1689,8 +1689,10 @@ def help_test_all(module: ModuleType) -> None:
def extract_stack_to_frame(extract_stack: list[Mock]) -> FrameType: def extract_stack_to_frame(extract_stack: list[Mock]) -> FrameType:
"""Convert an extract stack to a frame list.""" """Convert an extract stack to a frame list."""
stack = list(extract_stack) stack = list(extract_stack)
_globals = globals()
for frame in stack: for frame in stack:
frame.f_back = None frame.f_back = None
frame.f_globals = _globals
frame.f_code.co_filename = frame.filename frame.f_code.co_filename = frame.filename
frame.f_lineno = int(frame.lineno) frame.f_lineno = int(frame.lineno)

View file

@ -17,7 +17,7 @@ async def test_extract_frame_integration(
integration_frame = frame.get_integration_frame() integration_frame = frame.get_integration_frame()
assert integration_frame == frame.IntegrationFrame( assert integration_frame == frame.IntegrationFrame(
custom_integration=False, custom_integration=False,
_frame=mock_integration_frame, frame=mock_integration_frame,
integration="hue", integration="hue",
module=None, module=None,
relative_filename="homeassistant/components/hue/light.py", relative_filename="homeassistant/components/hue/light.py",
@ -42,7 +42,7 @@ async def test_extract_frame_resolve_module(
assert integration_frame == frame.IntegrationFrame( assert integration_frame == frame.IntegrationFrame(
custom_integration=True, custom_integration=True,
_frame=ANY, frame=ANY,
integration="test_integration_frame", integration="test_integration_frame",
module="custom_components.test_integration_frame", module="custom_components.test_integration_frame",
relative_filename="custom_components/test_integration_frame/__init__.py", relative_filename="custom_components/test_integration_frame/__init__.py",
@ -98,7 +98,7 @@ async def test_extract_frame_integration_with_excluded_integration(
assert integration_frame == frame.IntegrationFrame( assert integration_frame == frame.IntegrationFrame(
custom_integration=False, custom_integration=False,
_frame=correct_frame, frame=correct_frame,
integration="mdns", integration="mdns",
module=None, module=None,
relative_filename="homeassistant/components/mdns/light.py", relative_filename="homeassistant/components/mdns/light.py",

View file

@ -1271,7 +1271,7 @@ async def test_hass_components_use_reported(
) )
integration_frame = frame.IntegrationFrame( integration_frame = frame.IntegrationFrame(
custom_integration=True, custom_integration=True,
_frame=mock_integration_frame, frame=mock_integration_frame,
integration="test_integration_frame", integration="test_integration_frame",
module="custom_components.test_integration_frame", module="custom_components.test_integration_frame",
relative_filename="custom_components/test_integration_frame/__init__.py", relative_filename="custom_components/test_integration_frame/__init__.py",
@ -1969,7 +1969,7 @@ async def test_hass_helpers_use_reported(
"""Test that use of hass.components is reported.""" """Test that use of hass.components is reported."""
integration_frame = frame.IntegrationFrame( integration_frame = frame.IntegrationFrame(
custom_integration=True, custom_integration=True,
_frame=mock_integration_frame, frame=mock_integration_frame,
integration="test_integration_frame", integration="test_integration_frame",
module="custom_components.test_integration_frame", module="custom_components.test_integration_frame",
relative_filename="custom_components/test_integration_frame/__init__.py", relative_filename="custom_components/test_integration_frame/__init__.py",

View file

@ -27,6 +27,7 @@ async def test_raise_for_blocking_call_async_non_strict_core(
"""Test non_strict_core raise_for_blocking_call detects from event loop without integration context.""" """Test non_strict_core raise_for_blocking_call detects from event loop without integration context."""
haloop.raise_for_blocking_call(banned_function, strict_core=False) haloop.raise_for_blocking_call(banned_function, strict_core=False)
assert "Detected blocking call to banned_function" in caplog.text assert "Detected blocking call to banned_function" in caplog.text
assert "Traceback (most recent call last)" in caplog.text
async def test_raise_for_blocking_call_async_integration( async def test_raise_for_blocking_call_async_integration(
@ -130,6 +131,11 @@ async def test_raise_for_blocking_call_async_integration_non_strict(
"please create a bug report at https://github.com/home-assistant/core/issues?" "please create a bug report at https://github.com/home-assistant/core/issues?"
"q=is%3Aopen+is%3Aissue+label%3A%22integration%3A+hue%22" in caplog.text "q=is%3Aopen+is%3Aissue+label%3A%22integration%3A+hue%22" in caplog.text
) )
assert "Traceback (most recent call last)" in caplog.text
assert (
'File "/home/paulus/homeassistant/components/hue/light.py", line 23'
in caplog.text
)
async def test_raise_for_blocking_call_async_custom( async def test_raise_for_blocking_call_async_custom(
@ -182,6 +188,11 @@ async def test_raise_for_blocking_call_async_custom(
"please create a bug report at https://github.com/home-assistant/core/issues?" "please create a bug report at https://github.com/home-assistant/core/issues?"
"q=is%3Aopen+is%3Aissue+label%3A%22integration%3A+hue%22" "q=is%3Aopen+is%3Aissue+label%3A%22integration%3A+hue%22"
) in caplog.text ) in caplog.text
assert "Traceback (most recent call last)" in caplog.text
assert (
'File "/home/paulus/config/custom_components/hue/light.py", line 23'
in caplog.text
)
async def test_raise_for_blocking_call_sync( async def test_raise_for_blocking_call_sync(