mirror of
https://github.com/home-assistant/core.git
synced 2026-04-27 05:16:51 +00:00
Add profiler service for dumping sockets used by HA (#152440)
Co-authored-by: Stefan Agner <stefan@agner.ch>
This commit is contained in:
@@ -35,6 +35,7 @@ SERVICE_STOP_LOG_OBJECTS = "stop_log_objects"
|
||||
SERVICE_START_LOG_OBJECT_SOURCES = "start_log_object_sources"
|
||||
SERVICE_STOP_LOG_OBJECT_SOURCES = "stop_log_object_sources"
|
||||
SERVICE_DUMP_LOG_OBJECTS = "dump_log_objects"
|
||||
SERVICE_DUMP_SOCKETS = "dump_sockets"
|
||||
SERVICE_LRU_STATS = "lru_stats"
|
||||
SERVICE_LOG_THREAD_FRAMES = "log_thread_frames"
|
||||
SERVICE_LOG_EVENT_LOOP_SCHEDULED = "log_event_loop_scheduled"
|
||||
@@ -231,6 +232,15 @@ async def async_setup_entry( # noqa: C901
|
||||
notification_id="profile_lru_stats",
|
||||
)
|
||||
|
||||
def _dump_sockets(call: ServiceCall) -> None:
|
||||
"""Dump list of all currently existing sockets to the log."""
|
||||
import objgraph # noqa: PLC0415
|
||||
|
||||
_LOGGER.critical(
|
||||
"Sockets used by Home Assistant:\n%s",
|
||||
"\n".join(repr(sock) for sock in objgraph.by_type("socket")),
|
||||
)
|
||||
|
||||
async def _async_dump_thread_frames(call: ServiceCall) -> None:
|
||||
"""Log all thread frames."""
|
||||
frames = sys._current_frames() # noqa: SLF001
|
||||
@@ -346,6 +356,13 @@ async def async_setup_entry( # noqa: C901
|
||||
schema=vol.Schema({vol.Required(CONF_TYPE): str}),
|
||||
)
|
||||
|
||||
async_register_admin_service(
|
||||
hass,
|
||||
DOMAIN,
|
||||
SERVICE_DUMP_SOCKETS,
|
||||
_dump_sockets,
|
||||
)
|
||||
|
||||
async_register_admin_service(
|
||||
hass,
|
||||
DOMAIN,
|
||||
|
||||
@@ -15,6 +15,9 @@
|
||||
"dump_log_objects": {
|
||||
"service": "mdi:invoice-export-outline"
|
||||
},
|
||||
"dump_sockets": {
|
||||
"service": "mdi:pipe"
|
||||
},
|
||||
"start_log_object_sources": {
|
||||
"service": "mdi:play"
|
||||
},
|
||||
|
||||
@@ -51,6 +51,7 @@ start_log_object_sources:
|
||||
unit_of_measurement: objects
|
||||
stop_log_object_sources:
|
||||
lru_stats:
|
||||
dump_sockets:
|
||||
log_thread_frames:
|
||||
log_event_loop_scheduled:
|
||||
set_asyncio_debug:
|
||||
|
||||
@@ -65,6 +65,10 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"dump_sockets": {
|
||||
"name": "Dump used sockets",
|
||||
"description": "Logs information about all currently used sockets."
|
||||
},
|
||||
"stop_log_object_sources": {
|
||||
"name": "Stop logging object sources",
|
||||
"description": "Stops logging sources of new objects in memory."
|
||||
|
||||
@@ -5,6 +5,7 @@ from functools import lru_cache
|
||||
import logging
|
||||
import os
|
||||
from pathlib import Path
|
||||
import socket
|
||||
from unittest.mock import patch
|
||||
|
||||
from freezegun.api import FrozenDateTimeFactory
|
||||
@@ -18,6 +19,7 @@ from homeassistant.components.profiler import (
|
||||
CONF_ENABLED,
|
||||
CONF_SECONDS,
|
||||
SERVICE_DUMP_LOG_OBJECTS,
|
||||
SERVICE_DUMP_SOCKETS,
|
||||
SERVICE_LOG_CURRENT_TASKS,
|
||||
SERVICE_LOG_EVENT_LOOP_SCHEDULED,
|
||||
SERVICE_LOG_THREAD_FRAMES,
|
||||
@@ -271,6 +273,36 @@ async def test_log_scheduled(
|
||||
await hass.async_block_till_done()
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("socket_enabled")
|
||||
async def test_dump_sockets(
|
||||
hass: HomeAssistant, caplog: pytest.LogCaptureFixture
|
||||
) -> None:
|
||||
"""Test dumping of sockets to the log."""
|
||||
entry = MockConfigEntry(domain=DOMAIN)
|
||||
entry.add_to_hass(hass)
|
||||
|
||||
assert await hass.config_entries.async_setup(entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
caplog.clear()
|
||||
|
||||
sock = None
|
||||
try:
|
||||
# Try to bind ephemeral UDP port on localhost for testing
|
||||
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
sock.bind(("127.0.0.1", 0))
|
||||
port = sock.getsockname()[1]
|
||||
|
||||
assert hass.services.has_service(DOMAIN, SERVICE_DUMP_SOCKETS)
|
||||
await hass.services.async_call(DOMAIN, SERVICE_DUMP_SOCKETS, blocking=True)
|
||||
finally:
|
||||
if sock:
|
||||
sock.close()
|
||||
|
||||
assert "Sockets used by Home Assistant" in caplog.text
|
||||
assert f"laddr=('127.0.0.1', {port})" in caplog.text
|
||||
|
||||
|
||||
async def test_lru_stats(hass: HomeAssistant, caplog: pytest.LogCaptureFixture) -> None:
|
||||
"""Test logging lru stats."""
|
||||
|
||||
|
||||
Reference in New Issue
Block a user