Clean and optimize systemmonitor (#48699)
- Remove unneeded excinfo to _LOGGER.exception - Use f-strings - Switch last_boot to utc - Cache psutil/os calls used by multiple attributes in the same update cyclepull/48708/head
parent
d0b3f76a6f
commit
c28d4e8e01
|
@ -4,6 +4,7 @@ from __future__ import annotations
|
|||
import asyncio
|
||||
from dataclasses import dataclass
|
||||
import datetime
|
||||
from functools import lru_cache
|
||||
import logging
|
||||
import os
|
||||
import socket
|
||||
|
@ -246,7 +247,7 @@ async def async_setup_sensor_registry_updates(
|
|||
try:
|
||||
state, value, update_time = _update(type_, data)
|
||||
except Exception as ex: # pylint: disable=broad-except
|
||||
_LOGGER.exception("Error updating sensor: %s", type_, exc_info=ex)
|
||||
_LOGGER.exception("Error updating sensor: %s", type_)
|
||||
data.last_exception = ex
|
||||
else:
|
||||
data.state = state
|
||||
|
@ -254,6 +255,14 @@ async def async_setup_sensor_registry_updates(
|
|||
data.update_time = update_time
|
||||
data.last_exception = None
|
||||
|
||||
# Only fetch these once per iteration as we use the same
|
||||
# data source multiple times in _update
|
||||
_disk_usage.cache_clear()
|
||||
_swap_memory.cache_clear()
|
||||
_virtual_memory.cache_clear()
|
||||
_net_io_counters.cache_clear()
|
||||
_getloadavg.cache_clear()
|
||||
|
||||
async def _async_update_data(*_: Any) -> None:
|
||||
"""Update all sensors in one executor jump."""
|
||||
if _update_lock.locked():
|
||||
|
@ -289,14 +298,14 @@ class SystemMonitorSensor(SensorEntity):
|
|||
) -> None:
|
||||
"""Initialize the sensor."""
|
||||
self._type: str = sensor_type
|
||||
self._name: str = "{} {}".format(self.sensor_type[SENSOR_TYPE_NAME], argument)
|
||||
self._name: str = f"{self.sensor_type[SENSOR_TYPE_NAME]} {argument}".rstrip()
|
||||
self._unique_id: str = slugify(f"{sensor_type}_{argument}")
|
||||
self._sensor_registry = sensor_registry
|
||||
|
||||
@property
|
||||
def name(self) -> str:
|
||||
"""Return the name of the sensor."""
|
||||
return self._name.rstrip()
|
||||
return self._name
|
||||
|
||||
@property
|
||||
def unique_id(self) -> str:
|
||||
|
@ -362,24 +371,24 @@ def _update(
|
|||
update_time = None
|
||||
|
||||
if type_ == "disk_use_percent":
|
||||
state = psutil.disk_usage(data.argument).percent
|
||||
state = _disk_usage(data.argument).percent
|
||||
elif type_ == "disk_use":
|
||||
state = round(psutil.disk_usage(data.argument).used / 1024 ** 3, 1)
|
||||
state = round(_disk_usage(data.argument).used / 1024 ** 3, 1)
|
||||
elif type_ == "disk_free":
|
||||
state = round(psutil.disk_usage(data.argument).free / 1024 ** 3, 1)
|
||||
state = round(_disk_usage(data.argument).free / 1024 ** 3, 1)
|
||||
elif type_ == "memory_use_percent":
|
||||
state = psutil.virtual_memory().percent
|
||||
state = _virtual_memory().percent
|
||||
elif type_ == "memory_use":
|
||||
virtual_memory = psutil.virtual_memory()
|
||||
virtual_memory = _virtual_memory()
|
||||
state = round((virtual_memory.total - virtual_memory.available) / 1024 ** 2, 1)
|
||||
elif type_ == "memory_free":
|
||||
state = round(psutil.virtual_memory().available / 1024 ** 2, 1)
|
||||
state = round(_virtual_memory().available / 1024 ** 2, 1)
|
||||
elif type_ == "swap_use_percent":
|
||||
state = psutil.swap_memory().percent
|
||||
state = _swap_memory().percent
|
||||
elif type_ == "swap_use":
|
||||
state = round(psutil.swap_memory().used / 1024 ** 2, 1)
|
||||
state = round(_swap_memory().used / 1024 ** 2, 1)
|
||||
elif type_ == "swap_free":
|
||||
state = round(psutil.swap_memory().free / 1024 ** 2, 1)
|
||||
state = round(_swap_memory().free / 1024 ** 2, 1)
|
||||
elif type_ == "processor_use":
|
||||
state = round(psutil.cpu_percent(interval=None))
|
||||
elif type_ == "processor_temperature":
|
||||
|
@ -398,20 +407,20 @@ def _update(
|
|||
err.name,
|
||||
)
|
||||
elif type_ in ["network_out", "network_in"]:
|
||||
counters = psutil.net_io_counters(pernic=True)
|
||||
counters = _net_io_counters()
|
||||
if data.argument in counters:
|
||||
counter = counters[data.argument][IO_COUNTER[type_]]
|
||||
state = round(counter / 1024 ** 2, 1)
|
||||
else:
|
||||
state = None
|
||||
elif type_ in ["packets_out", "packets_in"]:
|
||||
counters = psutil.net_io_counters(pernic=True)
|
||||
counters = _net_io_counters()
|
||||
if data.argument in counters:
|
||||
state = counters[data.argument][IO_COUNTER[type_]]
|
||||
else:
|
||||
state = None
|
||||
elif type_ in ["throughput_network_out", "throughput_network_in"]:
|
||||
counters = psutil.net_io_counters(pernic=True)
|
||||
counters = _net_io_counters()
|
||||
if data.argument in counters:
|
||||
counter = counters[data.argument][IO_COUNTER[type_]]
|
||||
now = dt_util.utcnow()
|
||||
|
@ -429,7 +438,7 @@ def _update(
|
|||
else:
|
||||
state = None
|
||||
elif type_ in ["ipv4_address", "ipv6_address"]:
|
||||
addresses = psutil.net_if_addrs()
|
||||
addresses = _net_io_counters()
|
||||
if data.argument in addresses:
|
||||
for addr in addresses[data.argument]:
|
||||
if addr.family == IF_ADDRS_FAMILY[type_]:
|
||||
|
@ -439,21 +448,46 @@ def _update(
|
|||
elif type_ == "last_boot":
|
||||
# Only update on initial setup
|
||||
if data.state is None:
|
||||
state = dt_util.as_local(
|
||||
dt_util.utc_from_timestamp(psutil.boot_time())
|
||||
).isoformat()
|
||||
state = dt_util.utc_from_timestamp(psutil.boot_time()).isoformat()
|
||||
else:
|
||||
state = data.state
|
||||
elif type_ == "load_1m":
|
||||
state = round(os.getloadavg()[0], 2)
|
||||
state = round(_getloadavg()[0], 2)
|
||||
elif type_ == "load_5m":
|
||||
state = round(os.getloadavg()[1], 2)
|
||||
state = round(_getloadavg()[1], 2)
|
||||
elif type_ == "load_15m":
|
||||
state = round(os.getloadavg()[2], 2)
|
||||
state = round(_getloadavg()[2], 2)
|
||||
|
||||
return state, value, update_time
|
||||
|
||||
|
||||
# When we drop python 3.8 support these can be switched to
|
||||
# @cache https://docs.python.org/3.9/library/functools.html#functools.cache
|
||||
@lru_cache(maxsize=None)
|
||||
def _disk_usage(path: str) -> Any:
|
||||
return psutil.disk_usage(path)
|
||||
|
||||
|
||||
@lru_cache(maxsize=None)
|
||||
def _swap_memory() -> Any:
|
||||
return psutil.swap_memory()
|
||||
|
||||
|
||||
@lru_cache(maxsize=None)
|
||||
def _virtual_memory() -> Any:
|
||||
return psutil.virtual_memory()
|
||||
|
||||
|
||||
@lru_cache(maxsize=None)
|
||||
def _net_io_counters() -> Any:
|
||||
return psutil.net_io_counters(pernic=True)
|
||||
|
||||
|
||||
@lru_cache(maxsize=None)
|
||||
def _getloadavg() -> tuple[float, float, float]:
|
||||
return os.getloadavg()
|
||||
|
||||
|
||||
def _read_cpu_temperature() -> float | None:
|
||||
"""Attempt to read CPU / processor temperature."""
|
||||
temps = psutil.sensors_temperatures()
|
||||
|
|
Loading…
Reference in New Issue