Skip to content

Commit f52d07f

Browse files
authored
fix: stop logging large content [IDE-1351] (#397)
1 parent 96f4ad9 commit f52d07f

File tree

2 files changed

+114
-1
lines changed

2 files changed

+114
-1
lines changed

pkg/networking/logging.go

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"fmt"
77
"io"
88
"net/http"
9+
"strings"
910

1011
"github.com/pkg/errors"
1112
"github.com/rs/zerolog"
@@ -14,7 +15,21 @@ import (
1415
const defaultNetworkLogLevel = zerolog.DebugLevel
1516
const extendedNetworkLogLevel = zerolog.TraceLevel
1617
const maxNumberOfRequestBodyCharacters = 60
17-
const maxNumberOfResponseBodyCharacters = -1 // log complete response body
18+
const maxNumberOfResponseBodyCharacters = 10 * 1024 // 10KiB, to ensure we don't log an entire CLI download response that is interrupted.
19+
20+
// Binary content types that should not have their response bodies logged to avoid memory issues
21+
var binaryMIMETypes = []string{
22+
"application/octet-stream", // Standard binary MIME type
23+
"binary/octet-stream", // Non-standard but sometimes used
24+
"application/zip", // ZIP archives
25+
"application/gzip", // GZIP archives
26+
"application/x-gzip", // Alternative GZIP MIME type
27+
"application/x-tar", // TAR archives
28+
"application/x-executable", // Executable files
29+
"application/x-msdownload", // Windows executables
30+
"application/x-mach-binary", // macOS binaries
31+
"application/x-elf", // Linux ELF binaries
32+
}
1833

1934
func shouldNotLog(currentLevel zerolog.Level, levelToLogAt zerolog.Level) bool {
2035
// Don't log if logger level is above the threshold
@@ -109,6 +124,17 @@ func shortenStringFromCenter(str string, maxCharacters int64) string {
109124
return str
110125
}
111126

127+
// isBinaryContent checks if the content type indicates binary data that shouldn't be logged
128+
func isBinaryContent(contentType string) bool {
129+
mimeType := strings.ToLower(strings.TrimSpace(strings.Split(contentType, ";")[0]))
130+
for _, binaryMIMEType := range binaryMIMETypes {
131+
if mimeType == binaryMIMEType {
132+
return true
133+
}
134+
}
135+
return false
136+
}
137+
112138
func LogRequest(r *http.Request, logger *zerolog.Logger) {
113139
if shouldNotLog(logger.GetLevel(), defaultNetworkLogLevel) { // Don't log if logger level is above the threshold
114140
return
@@ -141,6 +167,12 @@ func LogResponse(response *http.Response, logger *zerolog.Logger) {
141167
return
142168
}
143169

170+
// Skip response body logging for binary content to avoid memory issues with large binary downloads.
171+
if isBinaryContent(response.Header.Get("Content-Type")) {
172+
logger.WithLevel(defaultNetworkLogLevel).Msgf("%s body: [BINARY CONTENT - NOT LOGGED]", logPrefixResponse)
173+
return
174+
}
175+
144176
logBody(logger, defaultNetworkLogLevel, logPrefixResponse, getResponseBody(response), response.Header, maxNumberOfResponseBodyCharacters)
145177
}
146178
}

pkg/networking/logging_test.go

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"io"
77
"net/http"
88
"net/http/httptest"
9+
"strings"
910
"testing"
1011

1112
"github.com/rs/zerolog"
@@ -216,6 +217,86 @@ func Test_LogResponse_nolog(t *testing.T) {
216217
})
217218
}
218219

220+
func Test_LogResponse_skipsBinaryContent(t *testing.T) {
221+
tests := []struct {
222+
name string
223+
contentType string
224+
isBinary bool
225+
}{
226+
{
227+
name: "binary/octet-stream",
228+
contentType: "binary/octet-stream",
229+
isBinary: true,
230+
},
231+
{
232+
name: "text/plain",
233+
contentType: "text/plain",
234+
isBinary: false,
235+
},
236+
{
237+
name: "application/json",
238+
contentType: "application/json",
239+
isBinary: false,
240+
},
241+
{
242+
name: "empty content type",
243+
contentType: "",
244+
isBinary: false,
245+
},
246+
{
247+
name: "case insensitive",
248+
contentType: "APPLICATION/OCTET-STREAM",
249+
isBinary: true,
250+
},
251+
{
252+
name: "with charset",
253+
contentType: "application/octet-stream; charset=utf-8",
254+
isBinary: true,
255+
},
256+
}
257+
258+
for _, tt := range tests {
259+
t.Run(tt.name, func(t *testing.T) {
260+
content := bytes.NewBufferString("")
261+
logger := zerolog.New(content).Level(zerolog.TraceLevel)
262+
263+
var testData string
264+
if tt.isBinary {
265+
testData = "binary data that should not be logged"
266+
} else {
267+
testData = "text data that should be logged"
268+
}
269+
response := &http.Response{
270+
Status: "200 OK",
271+
StatusCode: http.StatusOK,
272+
Header: http.Header{},
273+
Body: io.NopCloser(strings.NewReader(testData)),
274+
}
275+
if tt.contentType != "" {
276+
response.Header.Set("Content-Type", tt.contentType)
277+
}
278+
279+
// Act
280+
LogResponse(response, &logger)
281+
282+
logOutput := content.String()
283+
assert.Contains(t, logOutput, "< response [0x0]: 200 OK")
284+
285+
if tt.contentType != "" {
286+
assert.Contains(t, logOutput, "Content-Type:["+tt.contentType+"]")
287+
}
288+
289+
if tt.isBinary {
290+
assert.Contains(t, logOutput, "[BINARY CONTENT - NOT LOGGED]")
291+
assert.NotContains(t, logOutput, testData)
292+
} else {
293+
assert.NotContains(t, logOutput, "[BINARY CONTENT - NOT LOGGED]")
294+
assert.Contains(t, logOutput, testData)
295+
}
296+
})
297+
}
298+
}
299+
219300
func Test_logRoundTrip(t *testing.T) {
220301
config := configuration.NewWithOpts()
221302
expectedResponseBody := "hello client"

0 commit comments

Comments
 (0)