Skip to content

Commit 7bde4c5

Browse files
ldmonsterPavel Okhlopkov
and
Pavel Okhlopkov
authored
Fix/double logging std (#677)
Signed-off-by: Pavel Okhlopkov <[email protected]> Co-authored-by: Pavel Okhlopkov <[email protected]>
1 parent e4f317f commit 7bde4c5

File tree

2 files changed

+75
-7
lines changed

2 files changed

+75
-7
lines changed

pkg/executor/executor.go

+60-6
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package executor
22

33
import (
4+
"bufio"
45
"bytes"
56
"encoding/json"
67
"fmt"
@@ -77,17 +78,18 @@ type proxyJSONLogger struct {
7778
logProxyHookJSON bool
7879
}
7980

80-
func (pj *proxyJSONLogger) Write(p []byte) (n int, err error) {
81-
pj.buf = append(pj.buf, p...)
82-
81+
func (pj *proxyJSONLogger) Write(p []byte) (int, error) {
8382
if !pj.logProxyHookJSON {
84-
pj.Entry.Log(log.InfoLevel, strings.TrimSpace(string(pj.buf)))
83+
pj.writerScanner(p)
8584

8685
return len(p), nil
8786
}
8887

88+
// join all parts of json
89+
pj.buf = append(pj.buf, p...)
90+
8991
var line interface{}
90-
err = json.Unmarshal(pj.buf, &line)
92+
err := json.Unmarshal(pj.buf, &line)
9193
if err != nil {
9294
if err.Error() == "unexpected end of JSON input" {
9395
return len(p), nil
@@ -107,15 +109,67 @@ func (pj *proxyJSONLogger) Write(p []byte) (n int, err error) {
107109
logMap[k] = v
108110
}
109111

110-
logLine, _ := json.Marshal(logMap)
112+
logLineRaw, _ := json.Marshal(logMap)
113+
114+
logLine := string(logLineRaw)
111115

112116
logEntry := pj.WithField(app.ProxyJsonLogKey, true)
113117

118+
if len(logLine) > 10000 {
119+
logLine = fmt.Sprintf("%s:truncated", string(logLine[:10000]))
120+
121+
truncatedLog, _ := json.Marshal(map[string]string{
122+
"truncated": logLine,
123+
})
124+
125+
logEntry.Log(log.FatalLevel, string(truncatedLog))
126+
}
127+
114128
logEntry.Log(log.FatalLevel, string(logLine))
115129

116130
return len(p), nil
117131
}
118132

133+
func (pj *proxyJSONLogger) writerScanner(p []byte) {
134+
scanner := bufio.NewScanner(bytes.NewReader(p))
135+
136+
// Set the buffer size to the maximum token size to avoid buffer overflows
137+
scanner.Buffer(make([]byte, bufio.MaxScanTokenSize), bufio.MaxScanTokenSize)
138+
139+
// Define a split function to split the input into chunks of up to 64KB
140+
chunkSize := bufio.MaxScanTokenSize // 64KB
141+
splitFunc := func(data []byte, atEOF bool) (int, []byte, error) {
142+
if len(data) >= chunkSize {
143+
return chunkSize, data[:chunkSize], nil
144+
}
145+
146+
return bufio.ScanLines(data, atEOF)
147+
}
148+
149+
// Use the custom split function to split the input
150+
scanner.Split(splitFunc)
151+
152+
// Scan the input and write it to the logger using the specified print function
153+
for scanner.Scan() {
154+
// prevent empty logging
155+
str := strings.TrimSpace(scanner.Text())
156+
if str == "" {
157+
continue
158+
}
159+
160+
if len(str) > 10000 {
161+
str = fmt.Sprintf("%s:truncated", str[:10000])
162+
}
163+
164+
pj.Entry.Info(str)
165+
}
166+
167+
// If there was an error while scanning the input, log an error
168+
if err := scanner.Err(); err != nil {
169+
pj.Entry.Errorf("Error while reading from Writer: %s", err)
170+
}
171+
}
172+
119173
func Output(cmd *exec.Cmd) (output []byte, err error) {
120174
// TODO context: hook name, hook phase, hook binding
121175
// TODO observability

pkg/executor/executor_test.go

+15-1
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ func TestRunAndLogLines(t *testing.T) {
5555
cmd := exec.Command("cat", f.Name())
5656
_, err = RunAndLogLines(cmd, map[string]string{"a": "b"})
5757
assert.NoError(t, err)
58-
assert.Contains(t, buf.String(), `\",\"output\":\"stdout\"}" a=b output=stdout proxyJsonLog=true`)
58+
assert.Contains(t, buf.String(), `:truncated\"}" a=b output=stdout proxyJsonLog=true`)
5959

6060
buf.Reset()
6161
})
@@ -82,6 +82,20 @@ func TestRunAndLogLines(t *testing.T) {
8282

8383
buf.Reset()
8484
})
85+
86+
t.Run("multiline non json", func(t *testing.T) {
87+
app.LogProxyHookJSON = false
88+
cmd := exec.Command("echo", `
89+
a b
90+
c d
91+
`)
92+
_, err := RunAndLogLines(cmd, map[string]string{"foor": "baar"})
93+
assert.NoError(t, err)
94+
assert.Contains(t, buf.String(), `level=info msg="a b" foor=baar output=stdout`)
95+
assert.Contains(t, buf.String(), `level=info msg="c d" foor=baar output=stdout`)
96+
97+
buf.Reset()
98+
})
8599
}
86100

87101
var letterRunes = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")

0 commit comments

Comments
 (0)