Skip to content

Commit c3942d2

Browse files
authored
Add automatic retry to stream logs (#23098)
1 parent f4ef4c6 commit c3942d2

File tree

2 files changed

+80
-29
lines changed

2 files changed

+80
-29
lines changed

src/data/hassio/supervisor.ts

+19
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,25 @@ export const fetchHassioLogsFollow = async (
226226
signal
227227
);
228228

229+
export const fetchHassioLogsFollowSkip = async (
230+
hass: HomeAssistant,
231+
provider: string,
232+
signal: AbortSignal,
233+
cursor: string,
234+
skipLines: number,
235+
lines = 100,
236+
boot = 0
237+
) =>
238+
hass.callApiRaw(
239+
"GET",
240+
`hassio/${provider.includes("_") ? `addons/${provider}` : provider}/logs${boot !== 0 ? `/boots/${boot}` : ""}/follow`,
241+
undefined,
242+
{
243+
Range: `entries=${cursor}:${skipLines}:${lines}`,
244+
},
245+
signal
246+
);
247+
229248
export const getHassioLogDownloadUrl = (provider: string) =>
230249
`/api/hassio/${
231250
provider.includes("_") ? `addons/${provider}` : provider

src/panels/config/logs/error-log-card.ts

+61-29
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ import {
5050
fetchHassioBoots,
5151
fetchHassioLogs,
5252
fetchHassioLogsFollow,
53+
fetchHassioLogsFollowSkip,
5354
fetchHassioLogsLegacy,
5455
getHassioLogDownloadLinesUrl,
5556
getHassioLogDownloadUrl,
@@ -428,46 +429,66 @@ class ErrorLogCard extends LitElement {
428429
}
429430
}
430431

431-
private async _loadLogs(): Promise<void> {
432+
private async _loadLogs(retry = false): Promise<void> {
432433
this._error = undefined;
433434
this._loadingState = "loading";
434-
this._loadingPrevState = undefined;
435-
this._firstCursor = undefined;
436-
this._numberOfLines = 0;
437-
this._ansiToHtmlElement?.clear();
435+
this._numberOfLines = retry ? (this._numberOfLines ?? 0) : 0;
436+
437+
if (!retry) {
438+
this._loadingPrevState = undefined;
439+
this._firstCursor = undefined;
440+
this._ansiToHtmlElement?.clear();
441+
}
442+
443+
const streamLogs =
444+
this._streamSupported &&
445+
isComponentLoaded(this.hass, "hassio") &&
446+
this.provider;
438447

439448
try {
440449
if (this._logStreamAborter) {
441450
this._logStreamAborter.abort();
442451
this._logStreamAborter = undefined;
443452
}
444453

445-
if (
446-
this._streamSupported &&
447-
isComponentLoaded(this.hass, "hassio") &&
448-
this.provider
449-
) {
454+
if (streamLogs) {
450455
this._logStreamAborter = new AbortController();
451456

452-
// check if there are any logs at all
453-
const testResponse = await fetchHassioLogs(
454-
this.hass,
455-
this.provider,
456-
`entries=:-1:`,
457-
this._boot
458-
);
459-
const testLogs = await testResponse.text();
460-
if (!testLogs.trim()) {
461-
this._loadingState = "empty";
457+
if (!retry) {
458+
// check if there are any logs at all
459+
const testResponse = await fetchHassioLogs(
460+
this.hass,
461+
this.provider!,
462+
`entries=:-1:`,
463+
this._boot
464+
);
465+
const testLogs = await testResponse.text();
466+
if (!testLogs.trim()) {
467+
this._loadingState = "empty";
468+
}
462469
}
463470

464-
const response = await fetchHassioLogsFollow(
465-
this.hass,
466-
this.provider,
467-
this._logStreamAborter.signal,
468-
NUMBER_OF_LINES,
469-
this._boot
470-
);
471+
let response: Response;
472+
473+
if (retry && this._firstCursor) {
474+
response = await fetchHassioLogsFollowSkip(
475+
this.hass,
476+
this.provider!,
477+
this._logStreamAborter.signal,
478+
this._firstCursor,
479+
this._numberOfLines,
480+
NUMBER_OF_LINES,
481+
this._boot
482+
);
483+
} else {
484+
response = await fetchHassioLogsFollow(
485+
this.hass,
486+
this.provider!,
487+
this._logStreamAborter.signal,
488+
NUMBER_OF_LINES,
489+
this._boot
490+
);
491+
}
471492

472493
if (response.headers.has("X-First-Cursor")) {
473494
this._firstCursor = response.headers.get("X-First-Cursor")!;
@@ -524,14 +545,17 @@ class ErrorLogCard extends LitElement {
524545

525546
if (!this._downloadSupported) {
526547
const downloadUrl = getHassioLogDownloadLinesUrl(
527-
this.provider,
548+
this.provider!,
528549
this._numberOfLines,
529550
this._boot
530551
);
531552
getSignedPath(this.hass, downloadUrl).then((signedUrl) => {
532553
this._logsFileLink = signedUrl.path;
533554
});
534555
}
556+
557+
// first chunk loads successfully, reset retry param
558+
retry = false;
535559
}
536560
}
537561
} else {
@@ -554,6 +578,13 @@ class ErrorLogCard extends LitElement {
554578
if (err.name === "AbortError") {
555579
return;
556580
}
581+
582+
// The stream can fail if the connection is lost or firefox service worker intercept the connection
583+
if (!retry && streamLogs) {
584+
this._loadLogs(true);
585+
return;
586+
}
587+
557588
this._error = (this.localizeFunc || this.hass.localize)(
558589
"ui.panel.config.logs.failed_get_logs",
559590
{
@@ -590,9 +621,10 @@ class ErrorLogCard extends LitElement {
590621
private _handleConnectionStatus = (ev: HASSDomEvent<ConnectionStatus>) => {
591622
if (ev.detail === "disconnected" && this._logStreamAborter) {
592623
this._logStreamAborter.abort();
624+
this._loadingState = "loading";
593625
}
594626
if (ev.detail === "connected") {
595-
this._loadLogs();
627+
this._loadLogs(true);
596628
}
597629
};
598630

0 commit comments

Comments
 (0)