fix: large memory usage on detail logging post requests (#5039)

This commit is contained in:
Kevin Wan
2025-07-31 19:09:32 +08:00
committed by GitHub
parent bf75027889
commit 63ec989376
2 changed files with 27 additions and 3 deletions

View File

@@ -24,8 +24,9 @@ import (
)
const (
limitBodyBytes = 1024
defaultSlowThreshold = time.Millisecond * 500
limitBodyBytes = 1024
limitDetailedBodyBytes = 4096
defaultSlowThreshold = time.Millisecond * 500
)
var slowThreshold = syncx.ForAtomicDuration(defaultSlowThreshold)
@@ -94,7 +95,8 @@ func DetailedLogHandler(next http.Handler) http.Handler {
lrw := newDetailLoggedResponseWriter(rw, &buf)
var dup io.ReadCloser
r.Body, dup = iox.DupReadCloser(r.Body)
// https://github.com/zeromicro/go-zero/issues/3564
r.Body, dup = iox.LimitDupReadCloser(r.Body, limitDetailedBodyBytes)
logs := new(internal.LogCollector)
next.ServeHTTP(lrw, r.WithContext(internal.WithLogCollector(r.Context(), logs)))
r.Body = dup

View File

@@ -10,6 +10,7 @@ import (
"time"
"github.com/stretchr/testify/assert"
"github.com/zeromicro/go-zero/core/logx/logtest"
"github.com/zeromicro/go-zero/rest/internal"
"github.com/zeromicro/go-zero/rest/internal/response"
)
@@ -86,6 +87,26 @@ func TestLogHandlerSlow(t *testing.T) {
assert.Equal(t, http.StatusOK, resp.Code)
}
}
func TestDetailedLogHandler_LargeBody(t *testing.T) {
lbuf := logtest.NewCollector(t)
var buf bytes.Buffer
for i := 0; i < limitDetailedBodyBytes<<2; i++ {
buf.WriteByte('a')
}
req := httptest.NewRequest(http.MethodPost, "http://localhost", &buf)
h := DetailedLogHandler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
io.Copy(io.Discard, r.Body)
}))
resp := httptest.NewRecorder()
h.ServeHTTP(resp, req)
// extra 200 for the length of POST request headers
assert.True(t, len(lbuf.Content()) < limitDetailedBodyBytes+200)
}
func TestDetailedLogHandler_Hijack(t *testing.T) {
resp := httptest.NewRecorder()
writer := &detailLoggedResponseWriter{
@@ -111,6 +132,7 @@ func TestDetailedLogHandler_Hijack(t *testing.T) {
_, _, _ = writer.Hijack()
})
}
func TestSetSlowThreshold(t *testing.T) {
assert.Equal(t, defaultSlowThreshold, slowThreshold.Load())
SetSlowThreshold(time.Second)