Avoid calling extract_stack in system_log since it does blocking I/O (#100455)

This commit is contained in:
J. Nick Koston
2023-09-21 09:48:41 +02:00
committed by GitHub
parent f2fc62138a
commit 59daceafd2
3 changed files with 103 additions and 46 deletions
+42 -14
View File
@@ -4,6 +4,7 @@ from __future__ import annotations
import asyncio
from collections.abc import Awaitable
import logging
import re
import traceback
from typing import Any
from unittest.mock import MagicMock, patch
@@ -87,11 +88,6 @@ class WatchLogErrorHandler(system_log.LogErrorHandler):
self.watch_event.set()
def get_frame(name):
"""Get log stack frame."""
return (name, 5, None, None)
async def async_setup_system_log(hass, config) -> WatchLogErrorHandler:
"""Set up the system_log component."""
WatchLogErrorHandler.instances = []
@@ -362,21 +358,28 @@ async def test_unknown_path(
assert log["source"] == ["unknown_path", 0]
def get_frame(path: str, previous_frame: MagicMock | None) -> MagicMock:
"""Get log stack frame."""
return MagicMock(
f_back=previous_frame,
f_code=MagicMock(co_filename=path),
f_lineno=5,
)
async def async_log_error_from_test_path(hass, path, watcher):
"""Log error while mocking the path."""
call_path = "internal_path.py"
main_frame = get_frame("main_path/main.py", None)
path_frame = get_frame(path, main_frame)
call_path_frame = get_frame(call_path, path_frame)
logger_frame = get_frame("venv_path/logging/log.py", call_path_frame)
with patch.object(
_LOGGER, "findCaller", MagicMock(return_value=(call_path, 0, None, None))
), patch(
"traceback.extract_stack",
MagicMock(
return_value=[
get_frame("main_path/main.py"),
get_frame(path),
get_frame(call_path),
get_frame("venv_path/logging/log.py"),
]
),
"homeassistant.components.system_log.sys._getframe",
return_value=logger_frame,
):
wait_empty = watcher.add_watcher("error message")
_LOGGER.error("error message")
@@ -441,3 +444,28 @@ async def test_raise_during_log_capture(
log = find_log(await get_error_log(hass_ws_client), "ERROR")
assert log is not None
assert_log(log, "", "Bad logger message: repr error", "ERROR")
async def test__figure_out_source(hass: HomeAssistant) -> None:
"""Test that source is figured out correctly.
We have to test this directly for exception tracebacks since
we cannot generate a trackback from a Home Assistant component
in a test because the test is not a component.
"""
try:
raise ValueError("test")
except ValueError as ex:
exc_info = (type(ex), ex, ex.__traceback__)
mock_record = MagicMock(
pathname="should not hit",
lineno=5,
exc_info=exc_info,
)
regex_str = f"({__file__})"
file, line_no = system_log._figure_out_source(
mock_record,
re.compile(regex_str),
)
assert file == __file__
assert line_no != 5