From 735187c86cadeb3c195ebf48fbdaa86d10e882a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E5=9B=BD=E6=A0=8B0668001083?= Date: Mon, 20 Apr 2026 17:22:04 +0800 Subject: [PATCH 1/2] fix(gateway): include tail logs on abnormal exit When the managed gateway process exits with an error, append the last buffered stdout/stderr lines to the exit log to make root causes visible. Closes #2513 --- web/backend/api/gateway.go | 7 ++++++- web/backend/api/log.go | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/web/backend/api/gateway.go b/web/backend/api/gateway.go index 201000ff3..90a31b2ff 100644 --- a/web/backend/api/gateway.go +++ b/web/backend/api/gateway.go @@ -762,7 +762,12 @@ func (h *Handler) startGatewayLocked(initialStatus string, existingPid int) (int // Wait for exit in background and clean up go func() { if err := cmd.Wait(); err != nil { - logger.ErrorC("gateway", fmt.Sprintf("Gateway process exited: %v", err)) + tail := gateway.logs.Tail(50) + if len(tail) > 0 { + logger.ErrorC("gateway", fmt.Sprintf("Gateway process exited: %v\nLast gateway logs:\n%s", err, strings.Join(tail, "\n"))) + } else { + logger.ErrorC("gateway", fmt.Sprintf("Gateway process exited: %v", err)) + } } else { logger.InfoC("gateway", "Gateway process exited normally") } diff --git a/web/backend/api/log.go b/web/backend/api/log.go index f83f6f34c..8ebb60384 100644 --- a/web/backend/api/log.go +++ b/web/backend/api/log.go @@ -95,3 +95,35 @@ func (b *LogBuffer) RunID() int { return b.runID } + +// Tail returns up to the last n buffered lines (newest last). +// If n <= 0, it returns nil. +func (b *LogBuffer) Tail(n int) []string { + if n <= 0 { + return nil + } + + b.mu.RLock() + defer b.mu.RUnlock() + + if b.total == 0 || len(b.lines) == 0 { + return nil + } + + if n > len(b.lines) { + n = len(b.lines) + } + + result := make([]string, n) + + if b.total <= b.cap { + copy(result, b.lines[len(b.lines)-n:]) + return result + } + + start := (b.total - n) % b.cap + for i := 0; i < n; i++ { + result[i] = b.lines[(start+i)%b.cap] + } + return result +} From 1c953db972b183298de7429157e08613ee22af72 Mon Sep 17 00:00:00 2001 From: Yum-King Date: Mon, 20 Apr 2026 20:44:41 +0800 Subject: [PATCH 2/2] chore(lint): wrap gateway exit log line --- web/backend/api/gateway.go | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/web/backend/api/gateway.go b/web/backend/api/gateway.go index 90a31b2ff..c7d695824 100644 --- a/web/backend/api/gateway.go +++ b/web/backend/api/gateway.go @@ -764,7 +764,14 @@ func (h *Handler) startGatewayLocked(initialStatus string, existingPid int) (int if err := cmd.Wait(); err != nil { tail := gateway.logs.Tail(50) if len(tail) > 0 { - logger.ErrorC("gateway", fmt.Sprintf("Gateway process exited: %v\nLast gateway logs:\n%s", err, strings.Join(tail, "\n"))) + logger.ErrorC( + "gateway", + fmt.Sprintf( + "Gateway process exited: %v\nLast gateway logs:\n%s", + err, + strings.Join(tail, "\n"), + ), + ) } else { logger.ErrorC("gateway", fmt.Sprintf("Gateway process exited: %v", err)) }