From 1aabca9489d33e069db1bf2d4c739050ba385b6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20=C4=8Cerm=C3=A1k?= Date: Fri, 31 Jan 2025 11:55:05 +0100 Subject: [PATCH] Make sure the oldest boot ID is included in the boot list (#5591) If the system is running for a long time, or the logging is particularly chatty, the Systemd journal message we use to detect boot will be rotated out of the journal. Currently we only handled it if there was one boot, but we usually always missed the oldest boot if there were more boots. Adjust the method for getting boot IDs to always get the very first log line in the journal instead of the last one, and make sure its boot ID is included in the list. --- supervisor/host/logs.py | 40 ++++++++++++++++++++++------------------ 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/supervisor/host/logs.py b/supervisor/host/logs.py index 68cdc06b4..6c923db64 100644 --- a/supervisor/host/logs.py +++ b/supervisor/host/logs.py @@ -111,25 +111,29 @@ class LogsControl(CoreSysAttributes): _LOGGER.error, ) from err - # If a system has not been rebooted in a long time query can come back with zero results - # Fallback is to get latest log line and its boot ID so we always have at least one. - if not text: - try: - async with self.journald_logs( - range_header="entries=:-1:1", - accept=LogFormat.JSON, - timeout=ClientTimeout(total=20), - ) as resp: - text = await resp.text() - except (ClientError, TimeoutError) as err: - raise HostLogError( - "Could not get a list of boot IDs from systemd-journal-gatewayd", - _LOGGER.error, - ) from err + # Get the oldest log entry. This makes sure that its ID is included + # if the start of the oldest boot was rotated out of the journal. + try: + async with self.journald_logs( + range_header="entries=:0:1", + accept=LogFormat.JSON, + timeout=ClientTimeout(total=20), + ) as resp: + text = await resp.text() + text + except (ClientError, TimeoutError) as err: + raise HostLogError( + "Could not get a list of boot IDs from systemd-journal-gatewayd", + _LOGGER.error, + ) from err + + self._boot_ids = [] + for entry in text.split("\n"): + if ( + entry + and (boot_id := json.loads(entry)[PARAM_BOOT_ID]) not in self._boot_ids + ): + self._boot_ids.append(boot_id) - self._boot_ids = [ - json.loads(entry)[PARAM_BOOT_ID] for entry in text.split("\n") if entry - ] return self._boot_ids async def get_identifiers(self) -> list[str]: