diff --git a/internal/api/middleware/response_writer.go b/internal/api/middleware/response_writer.go index 52ef09b2..216fd514 100644 --- a/internal/api/middleware/response_writer.go +++ b/internal/api/middleware/response_writer.go @@ -11,12 +11,19 @@ import ( "bytes" "net/http" "strings" + "sync" "github.com/gin-gonic/gin" "github.com/traylinx/switchAILocal/internal/interfaces" "github.com/traylinx/switchAILocal/internal/logging" ) +var responseBodyPool = sync.Pool{ + New: func() interface{} { + return new(bytes.Buffer) + }, +} + // RequestInfo holds essential details of an incoming HTTP request for logging purposes. type RequestInfo struct { URL string // URL is the request URL. @@ -53,9 +60,11 @@ type ResponseWriterWrapper struct { // Returns: // - A pointer to a new ResponseWriterWrapper. func NewResponseWriterWrapper(w gin.ResponseWriter, logger logging.RequestLogger, requestInfo *RequestInfo) *ResponseWriterWrapper { + buf := responseBodyPool.Get().(*bytes.Buffer) + buf.Reset() return &ResponseWriterWrapper{ ResponseWriter: w, - body: &bytes.Buffer{}, + body: buf, logger: logger, requestInfo: requestInfo, headers: make(map[string][]string), @@ -301,7 +310,15 @@ func (w *ResponseWriterWrapper) Finalize(c *gin.Context) error { return nil } - return w.logRequest(finalStatusCode, w.cloneHeaders(), w.body.Bytes(), w.extractAPIRequest(c), w.extractAPIResponse(c), slicesAPIResponseError, forceLog) + bodyBytes := w.body.Bytes() + err := w.logRequest(finalStatusCode, w.cloneHeaders(), bodyBytes, w.extractAPIRequest(c), w.extractAPIResponse(c), slicesAPIResponseError, forceLog) + + // Return buffer to pool, avoiding memory bloat from occasional massive payloads + if w.body.Cap() <= 128*1024 { + responseBodyPool.Put(w.body) + } + + return err } func (w *ResponseWriterWrapper) cloneHeaders() map[string][]string {