From 3d435a9cb73cd8f49f030d58568cae7890f2c5d2 Mon Sep 17 00:00:00 2001 From: Anbraten Date: Sat, 1 Jul 2023 18:55:00 +0200 Subject: [PATCH] Fix log view (#1874) closes #1857 closes #1520 closes #1879 - fixes unicode log lines as reported in matrix --------- Co-authored-by: 6543 <6543@obermui.de> --- server/api/stream.go | 4 +- server/logging/log.go | 4 +- .../components/repo/pipeline/PipelineLog.vue | 63 +++++++++++++++---- 3 files changed, 56 insertions(+), 15 deletions(-) diff --git a/server/api/stream.go b/server/api/stream.go index eedc9285e..a4914860c 100644 --- a/server/api/stream.go +++ b/server/api/stream.go @@ -186,8 +186,8 @@ func LogStreamSSE(c *gin.Context) { } if step.State != model.StatusRunning { - log.Debug().Msg("stream not found.") - logWriteStringErr(io.WriteString(rw, "event: error\ndata: stream not found\n\n")) + log.Debug().Msg("step not running (anymore).") + logWriteStringErr(io.WriteString(rw, "event: error\ndata: step not running (anymore)\n\n")) return } diff --git a/server/logging/log.go b/server/logging/log.go index e29e498ce..6ea2e21ff 100644 --- a/server/logging/log.go +++ b/server/logging/log.go @@ -61,12 +61,12 @@ func (l *log) Open(_ context.Context, stepID int64) error { return nil } -func (l *log) Write(_ context.Context, stepID int64, logEntry *model.LogEntry) error { +func (l *log) Write(ctx context.Context, stepID int64, logEntry *model.LogEntry) error { l.Lock() s, ok := l.streams[stepID] l.Unlock() if !ok { - return ErrNotFound + return l.Open(ctx, stepID) } s.Lock() s.list = append(s.list, logEntry) diff --git a/web/src/components/repo/pipeline/PipelineLog.vue b/web/src/components/repo/pipeline/PipelineLog.vue index 1deea6e8a..ad47f3f93 100644 --- a/web/src/components/repo/pipeline/PipelineLog.vue +++ b/web/src/components/repo/pipeline/PipelineLog.vue @@ -34,13 +34,41 @@
-
- {{ line.index + 1 }} - - - {{ formatTime(line.time) }} +
+ {{ line.index + 1 }} + + + + {{ formatTime(line.time) }}
@@ -84,6 +112,7 @@ type LogLine = { index: number; text: string; time?: number; + type: 'error' | 'warning' | null; }; const props = defineProps<{ @@ -128,14 +157,26 @@ function formatTime(time?: number): string { return time === undefined ? '' : `${time}s`; } -function writeLog(line: LogLine) { +function writeLog(line: Partial) { logBuffer.value.push({ index: line.index ?? 0, - text: ansiUp.value.ansi_to_html(line.text), + text: ansiUp.value.ansi_to_html(line.text ?? ''), time: line.time ?? 0, + type: null, // TODO: implement way to detect errors and warnings }); } +// SOURCE: https://stackoverflow.com/questions/30106476/using-javascripts-atob-to-decode-base64-doesnt-properly-decode-utf-8-strings +function b64DecodeUnicode(str: string) { + return decodeURIComponent( + window + .atob(str) + .split('') + .map((c) => `%${`00${c.charCodeAt(0).toString(16)}`.slice(-2)}`) + .join(''), + ); +} + function scrollDown() { nextTick(() => { if (!consoleElement.value) { @@ -198,7 +239,7 @@ async function download() { downloadInProgress.value = false; } const fileURL = window.URL.createObjectURL( - new Blob([logs.map((line) => atob(line.data)).join('')], { + new Blob([logs.map((line) => b64DecodeUnicode(line.data)).join('')], { type: 'text/plain', }), ); @@ -240,13 +281,13 @@ async function loadLogs() { if (isStepFinished(step.value)) { const logs = await apiClient.getLogs(repo.value.id, pipeline.value.number, step.value.id); - logs?.forEach((line) => writeLog({ index: line.line, text: atob(line.data), time: line.time })); + logs?.forEach((line) => writeLog({ index: line.line, text: b64DecodeUnicode(line.data), time: line.time })); flushLogs(false); } if (isStepRunning(step.value)) { stream.value = apiClient.streamLogs(repo.value.id, pipeline.value.number, step.value.id, (line) => { - writeLog({ index: line.line, text: atob(line.data), time: line.time }); + writeLog({ index: line.line, text: b64DecodeUnicode(line.data), time: line.time }); flushLogs(true); }); }