mirror of
https://github.com/home-assistant/core.git
synced 2025-07-23 13:17:32 +00:00
Fix profiler dumping object when repr fails (#67674)
* Fix profiler dumping object when repr fails * cover
This commit is contained in:
parent
ee38203e1d
commit
bfe94f1cc5
@ -8,6 +8,7 @@ import sys
|
|||||||
import threading
|
import threading
|
||||||
import time
|
import time
|
||||||
import traceback
|
import traceback
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
from guppy import hpy
|
from guppy import hpy
|
||||||
import objgraph
|
import objgraph
|
||||||
@ -87,13 +88,24 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
|||||||
persistent_notification.async_dismiss(hass, "profile_object_logging")
|
persistent_notification.async_dismiss(hass, "profile_object_logging")
|
||||||
domain_data.pop(LOG_INTERVAL_SUB)()
|
domain_data.pop(LOG_INTERVAL_SUB)()
|
||||||
|
|
||||||
|
def _safe_repr(obj: Any) -> str:
|
||||||
|
"""Get the repr of an object but keep going if there is an exception.
|
||||||
|
|
||||||
|
We wrap repr to ensure if one object cannot be serialized, we can
|
||||||
|
still get the rest.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
return repr(obj)
|
||||||
|
except Exception: # pylint: disable=broad-except
|
||||||
|
return f"Failed to serialize {type(obj)}"
|
||||||
|
|
||||||
def _dump_log_objects(call: ServiceCall) -> None:
|
def _dump_log_objects(call: ServiceCall) -> None:
|
||||||
obj_type = call.data[CONF_TYPE]
|
obj_type = call.data[CONF_TYPE]
|
||||||
|
|
||||||
_LOGGER.critical(
|
_LOGGER.critical(
|
||||||
"%s objects in memory: %s",
|
"%s objects in memory: %s",
|
||||||
obj_type,
|
obj_type,
|
||||||
objgraph.by_type(obj_type),
|
[_safe_repr(obj) for obj in objgraph.by_type(obj_type)],
|
||||||
)
|
)
|
||||||
|
|
||||||
persistent_notification.create(
|
persistent_notification.create(
|
||||||
|
@ -131,19 +131,31 @@ async def test_dump_log_object(hass, caplog):
|
|||||||
assert await hass.config_entries.async_setup(entry.entry_id)
|
assert await hass.config_entries.async_setup(entry.entry_id)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
class DumpLogDummy:
|
||||||
|
def __init__(self, fail):
|
||||||
|
self.fail = fail
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
if self.fail:
|
||||||
|
raise Exception("failed")
|
||||||
|
return "<DumpLogDummy success>"
|
||||||
|
|
||||||
|
obj1 = DumpLogDummy(False)
|
||||||
|
obj2 = DumpLogDummy(True)
|
||||||
|
|
||||||
assert hass.services.has_service(DOMAIN, SERVICE_DUMP_LOG_OBJECTS)
|
assert hass.services.has_service(DOMAIN, SERVICE_DUMP_LOG_OBJECTS)
|
||||||
|
|
||||||
await hass.services.async_call(
|
await hass.services.async_call(
|
||||||
DOMAIN, SERVICE_DUMP_LOG_OBJECTS, {CONF_TYPE: "MockConfigEntry"}
|
DOMAIN, SERVICE_DUMP_LOG_OBJECTS, {CONF_TYPE: "DumpLogDummy"}
|
||||||
)
|
)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
assert "MockConfigEntry" in caplog.text
|
assert "<DumpLogDummy success>" in caplog.text
|
||||||
|
assert "Failed to serialize" in caplog.text
|
||||||
|
del obj1
|
||||||
|
del obj2
|
||||||
caplog.clear()
|
caplog.clear()
|
||||||
|
|
||||||
assert await hass.config_entries.async_unload(entry.entry_id)
|
|
||||||
await hass.async_block_till_done()
|
|
||||||
|
|
||||||
|
|
||||||
async def test_log_thread_frames(hass, caplog):
|
async def test_log_thread_frames(hass, caplog):
|
||||||
"""Test we can log thread frames."""
|
"""Test we can log thread frames."""
|
||||||
|
Loading…
x
Reference in New Issue
Block a user