Coverage for custom_components / remote_logger / handler.py: 100%
20 statements
« prev ^ index » next coverage.py v7.13.5, created at 2026-05-22 21:55 +0000
« prev ^ index » next coverage.py v7.13.5, created at 2026-05-22 21:55 +0000
1from __future__ import annotations
3import datetime as dt
4import logging
5import re
6import typing
8from homeassistant import __path__ as HOMEASSISTANT_PATH # noqa: N812
9from homeassistant.components.system_log import LogEntry
10from homeassistant.util import dt as dt_util
12if typing.TYPE_CHECKING:
13 from collections.abc import Callable
15 from homeassistant.core import HomeAssistant
17type KeyType = tuple[str, tuple[str, int], tuple[str, int, str] | None]
20class ExportingLogHandler(logging.Handler):
21 """Log handler for error messages."""
23 def __init__(
24 self,
25 hass: HomeAssistant,
26 handler: Callable,
27 ) -> None:
28 """Initialize a new LogErrorHandler."""
29 super().__init__()
30 self.handler = handler
31 self.tz = dt_util.get_default_time_zone()
32 self.paths_re = re.compile(rf"(?:{re.escape(HOMEASSISTANT_PATH[0])}|{re.escape(hass.config.config_dir)})/(.*)")
34 def emit(self, record: logging.LogRecord) -> None:
35 """Save error and warning logs.
37 Everything logged with error or warning is saved in local buffer. A
38 default upper limit is set to 50 (older entries are discarded) but can
39 be changed if needed.
40 """
41 if record.name.startswith("custom_components.remote_logger"):
42 # guard against loops, use exposed entities to check for remote_logger errors
43 return
44 entry: LogEntry = LogEntry(record, self.paths_re, formatter=self.formatter, figure_out_source=True)
45 self.handler(entry.to_dict(), time_fired=dt.datetime.fromtimestamp(record.created, tz=self.tz))