Skip to content

Commit cdd02bd

Browse files
authored
fix(logging): limit size of request bodies in trace level logging (#380)
1 parent e64056b commit cdd02bd

File tree

2 files changed

+39
-4
lines changed

2 files changed

+39
-4
lines changed

pkg/networking/logging.go

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ import (
1313

1414
const defaultNetworkLogLevel = zerolog.DebugLevel
1515
const extendedNetworkLogLevel = zerolog.TraceLevel
16+
const maxNumberOfRequestBodyCharacters = 60
17+
const maxNumberOfResponseBodyCharacters = -1 // log complete response body
1618

1719
func shouldNotLog(currentLevel zerolog.Level, levelToLogAt zerolog.Level) bool {
1820
// Don't log if logger level is above the threshold
@@ -71,16 +73,16 @@ func decodeBody(bodyBytes []byte, contentEncoding string) (string, error) {
7173
}
7274
}
7375

74-
func logBody(logger *zerolog.Logger, logLevel zerolog.Level, logPrefix string, body io.ReadCloser, header http.Header) {
76+
func logBody(logger *zerolog.Logger, logLevel zerolog.Level, logPrefix string, body io.ReadCloser, header http.Header, maxBodyCharacters int64) {
7577
if body != nil {
76-
bodyBytes, bodyErr := io.ReadAll(body)
7778
defer func() {
7879
closeErr := body.Close()
7980
if closeErr != nil {
8081
logger.WithLevel(logLevel).Err(closeErr).Msg("failed to close body")
8182
}
8283
}()
8384

85+
bodyBytes, bodyErr := io.ReadAll(body)
8486
if bodyErr != nil {
8587
return
8688
}
@@ -89,11 +91,24 @@ func logBody(logger *zerolog.Logger, logLevel zerolog.Level, logPrefix string, b
8991
if err != nil {
9092
logger.WithLevel(logLevel).Err(err).Msgf("%s Failed to decode request body", logPrefix)
9193
} else if len(bodyString) > 0 {
94+
bodyString = shortenStringFromCenter(bodyString, maxBodyCharacters)
9295
logger.WithLevel(logLevel).Msgf("%s body: %v", logPrefix, bodyString)
9396
}
9497
}
9598
}
9699

100+
// shortenStringFromCenter shortens the given string and keeps only maxCharacters of it. It removes content from the center
101+
// of the string and adds a placeholder making this obvious.
102+
func shortenStringFromCenter(str string, maxCharacters int64) string {
103+
// shorten body if maxBodyCharacters is set
104+
bodyLength := int64(len(str))
105+
if maxCharacters > 0 && bodyLength > maxCharacters {
106+
subLength := maxCharacters / 2
107+
str = fmt.Sprintf("%s [...shortened...] %s", str[0:subLength], str[bodyLength-subLength:bodyLength])
108+
}
109+
return str
110+
}
111+
97112
func LogRequest(r *http.Request, logger *zerolog.Logger) {
98113
if shouldNotLog(logger.GetLevel(), defaultNetworkLogLevel) { // Don't log if logger level is above the threshold
99114
return
@@ -108,7 +123,7 @@ func LogRequest(r *http.Request, logger *zerolog.Logger) {
108123
return
109124
}
110125

111-
logBody(logger, defaultNetworkLogLevel, logPrefixRequest, getRequestBody(r), r.Header)
126+
logBody(logger, defaultNetworkLogLevel, logPrefixRequest, getRequestBody(r), r.Header, maxNumberOfRequestBodyCharacters)
112127
}
113128

114129
func LogResponse(response *http.Response, logger *zerolog.Logger) {
@@ -126,6 +141,6 @@ func LogResponse(response *http.Response, logger *zerolog.Logger) {
126141
return
127142
}
128143

129-
logBody(logger, defaultNetworkLogLevel, logPrefixResponse, getResponseBody(response), response.Header)
144+
logBody(logger, defaultNetworkLogLevel, logPrefixResponse, getResponseBody(response), response.Header, maxNumberOfResponseBodyCharacters)
130145
}
131146
}

pkg/networking/logging_test.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,26 @@ func Test_LogRequest_happyPath_server_request(t *testing.T) {
109109
assert.Equal(t, expectedBody, string(actualBody))
110110
}
111111

112+
func Test_LogRequest_happyPath_server_request_limited(t *testing.T) {
113+
inputBody := "this is a longer text, that will not be logged fully. It'll just stop at some point and show the end of the text as well, since start and end of a message might be the most interesting part"
114+
expectedBody := "this is a longer text, that wi [...shortened...] t be the most interesting part"
115+
body := io.NopCloser(bytes.NewBufferString(inputBody))
116+
117+
logBuffer := bytes.Buffer{}
118+
logger := zerolog.New(&logBuffer).Level(zerolog.TraceLevel)
119+
request, err := http.NewRequest(http.MethodGet, "http://localhost/", body)
120+
assert.NoError(t, err)
121+
122+
// method under test
123+
LogRequest(request, &logger)
124+
assert.Contains(t, logBuffer.String(), expectedBody)
125+
126+
// ensure that the request body can still be read
127+
actualBody, err := io.ReadAll(request.Body)
128+
assert.NoError(t, err)
129+
assert.Equal(t, inputBody, string(actualBody))
130+
}
131+
112132
func Test_LogRequest_happyPath_client_request(t *testing.T) {
113133
expectedBody := "hello world"
114134
body := io.NopCloser(bytes.NewBufferString(expectedBody))

0 commit comments

Comments
 (0)