Skip to content

Commit 7fda25b

Browse files
committed
feat: add flush support for partial lines in invocation log
1 parent eb28493 commit 7fda25b

File tree

2 files changed

+77
-5
lines changed

2 files changed

+77
-5
lines changed

enterprise/server/cmd/ci_runner/main.go

Lines changed: 64 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -486,6 +486,9 @@ func (r *buildEventReporter) Stop() error {
486486
r.cancelBackgroundFlush()
487487
r.cancelBackgroundFlush = nil
488488
}
489+
if err := r.log.Flush(); err != nil {
490+
return err
491+
}
489492
r.FlushProgress()
490493

491494
elapsedTimeSeconds := float64(time.Since(r.startTime)) / float64(time.Second)
@@ -938,6 +941,9 @@ type invocationLog struct {
938941
lockingbuffer.LockingBuffer
939942
writer io.Writer
940943
writeListener func(s string)
944+
945+
mu sync.Mutex
946+
partialLine bytes.Buffer
941947
}
942948

943949
func newInvocationLog() *invocationLog {
@@ -947,16 +953,69 @@ func newInvocationLog() *invocationLog {
947953
}
948954

949955
func (invLog *invocationLog) Write(b []byte) (int, error) {
950-
output := string(b)
956+
invLog.mu.Lock()
957+
defer invLog.mu.Unlock()
958+
959+
if _, err := invLog.partialLine.Write(b); err != nil {
960+
return len(b), err
961+
}
951962

952-
redacted := redact.RedactText(output)
963+
var writeErr error
953964

954-
invLog.writeListener(redacted)
955-
_, err := invLog.writer.Write([]byte(redacted))
965+
for {
966+
data := invLog.partialLine.Bytes()
967+
if len(data) == 0 {
968+
break
969+
}
970+
971+
idx := bytes.IndexAny(data, "\n\r")
972+
if idx < 0 {
973+
break
974+
}
975+
976+
newlineLen := 1
977+
newlineSuffix := data[idx : idx+newlineLen]
978+
979+
if data[idx] == '\r' && idx+1 < len(data) && data[idx+1] == '\n' {
980+
newlineLen = 2
981+
newlineSuffix = data[idx : idx+newlineLen]
982+
}
983+
984+
lineContent := string(data[:idx])
985+
newlineStr := string(newlineSuffix)
986+
987+
invLog.partialLine.Next(idx + newlineLen)
988+
989+
redacted := redact.RedactText(lineContent)
990+
output := redacted + newlineStr
991+
992+
invLog.writeListener(output)
993+
if _, err := invLog.writer.Write([]byte(output)); err != nil && writeErr == nil {
994+
writeErr = err
995+
}
996+
}
956997

957998
// Return the size of the original buffer even if a redacted size was written,
958999
// or clients will return a short write error
959-
return len(b), err
1000+
return len(b), writeErr
1001+
}
1002+
1003+
func (invLog *invocationLog) Flush() error {
1004+
invLog.mu.Lock()
1005+
defer invLog.mu.Unlock()
1006+
1007+
if invLog.partialLine.Len() == 0 {
1008+
return nil
1009+
}
1010+
1011+
line := invLog.partialLine.String()
1012+
invLog.partialLine.Reset()
1013+
1014+
redacted := redact.RedactText(line)
1015+
1016+
invLog.writeListener(redacted)
1017+
_, err := invLog.writer.Write([]byte(redacted))
1018+
return err
9601019
}
9611020

9621021
func (invLog *invocationLog) Println(vals ...interface{}) {

enterprise/server/cmd/ci_runner/main_test.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,3 +43,16 @@ func TestInvocationLogRedactsMultipleLines(t *testing.T) {
4343
"line1 --remote_exec_header=<REDACTED>\nline2 --remote_exec_header=<REDACTED>\n",
4444
buf.String())
4545
}
46+
47+
func TestInvocationLogFlushesPartialLine(t *testing.T) {
48+
invLog, buf := newTestInvocationLog()
49+
50+
chunk := "common --remote_exec_header=secret-token"
51+
n, err := invLog.Write([]byte(chunk))
52+
require.NoError(t, err)
53+
require.Equal(t, len(chunk), n)
54+
require.Equal(t, "", buf.String(), "should not flush before newline")
55+
56+
require.NoError(t, invLog.Flush())
57+
require.Equal(t, "common --remote_exec_header=<REDACTED>", buf.String())
58+
}

0 commit comments

Comments
 (0)