diff --git a/assets/components/LogViewer/LogEventSource.spec.ts b/assets/components/LogViewer/LogEventSource.spec.ts index 7e1a0fd7..bcd5aeef 100644 --- a/assets/components/LogViewer/LogEventSource.spec.ts +++ b/assets/components/LogViewer/LogEventSource.spec.ts @@ -88,7 +88,7 @@ describe("", () => { }); } - const sourceUrl = "/api/logs/stream/localhost/abc?lastEventId=&stdout=1&stderr=1"; + const sourceUrl = "/api/logs/stream/localhost/abc?stdout=1&stderr=1"; test("renders correctly", async () => { const wrapper = createLogEventSource(); diff --git a/assets/composables/eventsource.ts b/assets/composables/eventsource.ts index 029dc751..f657d91b 100644 --- a/assets/composables/eventsource.ts +++ b/assets/composables/eventsource.ts @@ -30,6 +30,7 @@ export function useLogStream(container: Ref, streamConfig: LogStreamC let messages: LogEntry[] = $ref([]); let buffer: LogEntry[] = $ref([]); const scrollingPaused = $ref(inject("scrollingPaused") as Ref); + let containerId = container.value.id; function flushNow() { if (messages.length > config.maxLogs) { @@ -57,21 +58,30 @@ export function useLogStream(container: Ref, streamConfig: LogStreamC } const flushBuffer = debounce(flushNow, 250, { maxWait: 1000 }); let es: EventSource | null = null; - let lastEventId = ""; + + function close() { + if (es) { + es.close(); + console.debug(`EventSource closed for ${containerId}`); + es = null; + } + } + + function clearMessages() { + flushBuffer.cancel(); + messages = []; + buffer = []; + console.debug(`Clearing messages for ${containerId}`); + } function connect({ clear } = { clear: true }) { - es?.close(); + close(); if (clear) { - flushBuffer.cancel(); - messages = []; - buffer = []; - lastEventId = ""; + clearMessages(); } - const params = { - lastEventId, - } as { lastEventId: string; stdout?: string; stderr?: string }; + const params = {} as { stdout?: string; stderr?: string }; if (streamConfig.stdout) { params.stdout = "1"; @@ -79,23 +89,25 @@ export function useLogStream(container: Ref, streamConfig: LogStreamC if (streamConfig.stderr) { params.stderr = "1"; } + containerId = container.value.id; + + console.debug(`Connecting to ${containerId} with params`, params); es = new EventSource( - `${config.base}/api/logs/stream/${container.value.host}/${container.value.id}?${new URLSearchParams( - params, - ).toString()}`, + `${config.base}/api/logs/stream/${container.value.host}/${containerId}?${new URLSearchParams(params).toString()}`, ); es.addEventListener("container-stopped", () => { - es?.close(); - es = null; + close(); buffer.push(new DockerEventLogEntry("Container stopped", new Date(), "container-stopped")); flushBuffer(); flushBuffer.flush(); }); - es.addEventListener("error", (e) => console.error("EventSource failed: " + JSON.stringify(e))); + es.onerror = (e) => { + console.error(`Unexpected error for eventsource container-id:${containerId}. Clearing logs and reconnecting.`); + clearMessages(); + }; es.onmessage = (e) => { - lastEventId = e.lastEventId; if (e.data) { buffer.push(parseMessage(e.data)); flushBuffer(); @@ -126,9 +138,7 @@ export function useLogStream(container: Ref, streamConfig: LogStreamC const logs = await ( await fetch( - `${config.base}/api/logs/${container.value.host}/${container.value.id}?${new URLSearchParams( - params, - ).toString()}`, + `${config.base}/api/logs/${container.value.host}/${containerId}?${new URLSearchParams(params).toString()}`, ) ).text(); if (logs) { @@ -152,11 +162,7 @@ export function useLogStream(container: Ref, streamConfig: LogStreamC }, ); - onUnmounted(() => { - if (es) { - es.close(); - } - }); + onUnmounted(() => close()); watch( () => container.value.id,