Skip to content

Commit 44baf7a

Browse files
committed
refactor: split worker logs from other stdout logs
1 parent 2f1984f commit 44baf7a

5 files changed

Lines changed: 108 additions & 6 deletions

File tree

internal/model/worker_log.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ type WorkerLog struct {
1212
Stdin string `json:"stdin" gorm:"column:stdin;type:text"`
1313
Stdout string `json:"stdout" gorm:"column:stdout;type:text"`
1414
Stderr string `json:"stderr" gorm:"column:stderr;type:text"`
15+
ExecLog string `json:"exec_log" gorm:"column:exec_log;type:text"`
1516
Result string `json:"result" gorm:"column:result;type:text"`
1617
Error string `json:"error" gorm:"column:error;type:text"`
1718
DurationMS int64 `json:"duration_ms" gorm:"column:duration_ms"`

internal/worker/executor/executor.go

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import (
2525
var workerEntrypointsFS embed.FS
2626

2727
const logAndOutputSeparator = "\n**=====^=====**\n"
28+
const workerLogSeparatorLine = "==============="
2829
const (
2930
defaultPythonCgroupMemMaxBytes = 64 * 1024 * 1024
3031
defaultNodeCgroupMemMaxBytes = 64 * 1024 * 1024
@@ -45,6 +46,7 @@ type ExecuteResult struct {
4546
Body any
4647
Stdout string
4748
Stderr string
49+
ExecLog string
4850
Result string
4951
DurationMS int64
5052
TimedOut bool
@@ -87,6 +89,7 @@ func Run(parent context.Context, workerSpec worker.WorkerSpec, cfg config.Config
8789
ServerPort: cfg.MagicServerPort,
8890
Payload: payload,
8991
})
92+
result.ExecLog = bridgeStdout
9093
result.Stderr = bridgeStderr
9194

9295
if errors.Is(parent.Err(), context.DeadlineExceeded) {
@@ -97,18 +100,19 @@ func Run(parent context.Context, workerSpec worker.WorkerSpec, cfg config.Config
97100
}
98101
if runErr != nil {
99102
// slog.Error("脚本执行失败", "worker_id", worker.ID, "request_id", input.Event.RequestID, "stderr", bridgeStderr, "err", runErr)
100-
result.Stdout = bridgeStdout
103+
result.Stdout = extractWorkerStdout(result.ExecLog)
101104
result.Err = buildScriptExecuteError(bridgeStderr, runErr)
102105
return
103106
}
104107

105108
logOutput, resultOutput, err := splitBridgeOutput(bridgeStdout)
106109
if err != nil {
107-
result.Stdout = bridgeStdout
110+
result.Stdout = extractWorkerStdout(result.ExecLog)
108111
result.Err = fmt.Errorf("脚本 stdout 格式错误: %w", err)
109112
return
110113
}
111-
result.Stdout = logOutput
114+
_ = logOutput
115+
result.Stdout = extractWorkerStdout(result.ExecLog)
112116
result.Result = resultOutput
113117

114118
scriptOut, err := parseScriptOutput([]byte(resultOutput))
@@ -654,6 +658,37 @@ func splitBridgeOutput(stdout string) (logOutput string, resultOutput string, er
654658
return logOutput, resultOutput, nil
655659
}
656660

661+
func extractWorkerStdout(execLog string) string {
662+
if strings.TrimSpace(execLog) == "" {
663+
return ""
664+
}
665+
666+
logSource := execLog
667+
if logOutput, _, err := splitBridgeOutput(execLog); err == nil {
668+
logSource = logOutput
669+
}
670+
671+
lines := strings.Split(logSource, "\n")
672+
startIdx := -1
673+
endIdx := -1
674+
for index, line := range lines {
675+
if strings.TrimSpace(line) != workerLogSeparatorLine {
676+
continue
677+
}
678+
if startIdx < 0 {
679+
startIdx = index
680+
continue
681+
}
682+
endIdx = index
683+
}
684+
685+
if startIdx >= 0 && endIdx > startIdx {
686+
return strings.Trim(strings.Join(lines[startIdx+1:endIdx], "\n"), "\n")
687+
}
688+
689+
return strings.TrimSpace(logSource)
690+
}
691+
657692
// 用于在 Python 虚拟环境目录下定位真实的 site-packages 路径,供构建 PYTHONPATH 使用。
658693
func detectPythonSitePackages(pythonEnvDir string) string {
659694
libDir := filepath.Join(pythonEnvDir, "lib")

internal/worker/executor/invoke.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,7 @@ func (s *Service) buildWorkerLog(workerID string, requestID string, input model.
134134
Stdin: stdinText,
135135
Stdout: execResult.Stdout,
136136
Stderr: execResult.Stderr,
137+
ExecLog: execResult.ExecLog,
137138
Result: execResult.Result,
138139
Error: errMsg,
139140
DurationMS: execResult.DurationMS,
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
package executor
2+
3+
import (
4+
"strings"
5+
"testing"
6+
)
7+
8+
func TestExtractWorkerStdoutReturnsWorkerLogBlock(t *testing.T) {
9+
raw := strings.Join([]string{
10+
"[I] nsjail start",
11+
"===============",
12+
"worker line 1",
13+
"worker line 2",
14+
"**=====^=====**",
15+
`{"status":200,"body":"ok"}`,
16+
"**=====^=====**",
17+
"===============",
18+
"[I] nsjail end",
19+
}, "\n")
20+
21+
logOutput := extractWorkerStdout(raw)
22+
want := "worker line 1\nworker line 2"
23+
if logOutput != want {
24+
t.Fatalf("worker stdout 提取不正确,got=%q want=%q", logOutput, want)
25+
}
26+
}
27+
28+
func TestExtractWorkerStdoutReturnsEmptyWhenWorkerLogBlockIsEmpty(t *testing.T) {
29+
raw := strings.Join([]string{
30+
"[I] nsjail start",
31+
"===============",
32+
"**=====^=====**",
33+
`{"status":200,"body":"ok"}`,
34+
"**=====^=====**",
35+
"===============",
36+
"[I] nsjail end",
37+
}, "\n")
38+
39+
logOutput := extractWorkerStdout(raw)
40+
if logOutput != "" {
41+
t.Fatalf("worker stdout 应为空,got=%q", logOutput)
42+
}
43+
}
44+
45+
func TestExtractWorkerStdoutFallsBackToTrimmedRawWhenLogBlockMissing(t *testing.T) {
46+
raw := "[I] nsjail only"
47+
48+
logOutput := extractWorkerStdout(raw)
49+
if logOutput != raw {
50+
t.Fatalf("缺少分隔块时应回退原始内容,got=%q want=%q", logOutput, raw)
51+
}
52+
}

pages/src/components/worker-log-list.tsx

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,14 @@ export type WorkerLogItem = {
1212
stdin: string;
1313
stdout: string;
1414
stderr: string;
15+
exec_log: string;
1516
result: string;
1617
error: string;
1718
duration_ms: number;
1819
created_at: string;
1920
};
2021

21-
type LogTabKey = "result" | "error" | "stdin" | "stdout" | "stderr";
22+
type LogTabKey = "result" | "error" | "stdin" | "stdout" | "stderr" | "exec_log";
2223

2324
type WorkerLogListProps = {
2425
loading: boolean;
@@ -32,12 +33,13 @@ type WorkerLogListProps = {
3233
type LogTabConfig = {
3334
key: LogTabKey;
3435
label: string;
36+
fixed?: boolean;
3537
content: string;
3638
toneClassName: string;
3739
labelClassName: string;
3840
};
3941

40-
const logTabOrder: LogTabKey[] = ["result", "error", "stdin", "stdout", "stderr"];
42+
const logTabOrder: LogTabKey[] = ["result", "error", "stdin", "stdout", "stderr", "exec_log"];
4143

4244
function formatLogTime(raw: string): string {
4345
const dt = new Date(raw);
@@ -75,6 +77,7 @@ function buildLogTabs(item: WorkerLogItem): LogTabConfig[] {
7577
result: {
7678
key: "result",
7779
label: "result",
80+
fixed: true,
7881
content: formattedResult,
7982
toneClassName: "bg-accent/20 text-accent-600",
8083
labelClassName: "text-accent",
@@ -89,13 +92,15 @@ function buildLogTabs(item: WorkerLogItem): LogTabConfig[] {
8992
stdin: {
9093
key: "stdin",
9194
label: "stdin",
95+
fixed: true,
9296
content: formattedStdin,
9397
toneClassName: "bg-success/20 text-success-700",
9498
labelClassName: "text-success",
9599
},
96100
stdout: {
97101
key: "stdout",
98102
label: "stdout",
103+
fixed: true,
99104
content: item.stdout,
100105
toneClassName: "bg-default/40 text-default-700",
101106
labelClassName: "text-default-800",
@@ -107,11 +112,19 @@ function buildLogTabs(item: WorkerLogItem): LogTabConfig[] {
107112
toneClassName: "bg-warning/20 text-warning-700",
108113
labelClassName: "text-warning",
109114
},
115+
exec_log: {
116+
key: "exec_log",
117+
label: "exec_log",
118+
fixed: true,
119+
content: item.exec_log,
120+
toneClassName: "bg-default/40 text-default-700",
121+
labelClassName: "text-default-800",
122+
},
110123
};
111124

112125
return logTabOrder
113126
.map((key) => tabMap[key])
114-
.filter((tab) => tab.content);
127+
.filter((tab) => tab.fixed === true || tab.content);
115128
}
116129

117130
function getDefaultTabKey(tabs: LogTabConfig[]): LogTabKey | null {

0 commit comments

Comments
 (0)