fix: truncate oversized upstream error logs (#5083)

This commit is contained in:
Seefs
2026-05-25 23:10:30 +08:00
committed by GitHub
parent 2a528d46cb
commit 1288028181
6 changed files with 142 additions and 25 deletions
+104
View File
@@ -1,9 +1,17 @@
package service
import (
"bytes"
"context"
"fmt"
"io"
"net/http"
"strings"
"testing"
"github.com/QuantumNous/new-api/common"
"github.com/QuantumNous/new-api/types"
"github.com/gin-gonic/gin"
"github.com/stretchr/testify/require"
)
@@ -55,3 +63,99 @@ func TestResetStatusCode(t *testing.T) {
})
}
}
func TestRelayErrorHandlerTruncatesInvalidJSONBodyInLog(t *testing.T) {
withDebugEnabled(t, false)
body := strings.Repeat("b", common.LocalLogContentLimit+256)
var logBuffer bytes.Buffer
common.LogWriterMu.Lock()
oldWriter := gin.DefaultErrorWriter
gin.DefaultErrorWriter = &logBuffer
common.LogWriterMu.Unlock()
t.Cleanup(func() {
common.LogWriterMu.Lock()
gin.DefaultErrorWriter = oldWriter
common.LogWriterMu.Unlock()
})
resp := &http.Response{
StatusCode: http.StatusInternalServerError,
Body: io.NopCloser(strings.NewReader(body)),
}
newAPIError := RelayErrorHandler(context.Background(), resp, false)
require.NotNil(t, newAPIError)
require.Equal(t, "bad response status code 500", newAPIError.Error())
require.Contains(t, logBuffer.String(), "[truncated")
require.Contains(t, logBuffer.String(), fmt.Sprintf("original_length=%d", len(body)))
require.NotContains(t, logBuffer.String(), strings.Repeat("b", common.LocalLogContentLimit+1))
}
func TestRelayErrorHandlerKeepsStructuredErrorMessage(t *testing.T) {
message := strings.Repeat("c", common.LocalLogContentLimit+256)
body := `{"message":"` + message + `"}`
resp := &http.Response{
StatusCode: http.StatusInternalServerError,
Body: io.NopCloser(strings.NewReader(body)),
}
newAPIError := RelayErrorHandler(context.Background(), resp, false)
require.NotNil(t, newAPIError)
require.Equal(t, message, newAPIError.Error())
}
func TestRelayErrorHandlerKeepsOpenAIErrorMessage(t *testing.T) {
message := strings.Repeat("d", common.LocalLogContentLimit+256)
body := `{"error":{"message":"` + message + `","type":"server_error","code":"server_error"}}`
resp := &http.Response{
StatusCode: http.StatusInternalServerError,
Body: io.NopCloser(strings.NewReader(body)),
}
newAPIError := RelayErrorHandler(context.Background(), resp, false)
require.NotNil(t, newAPIError)
require.Equal(t, message, newAPIError.Error())
}
func TestRelayErrorHandlerKeepsInvalidJSONBodyInDebugLog(t *testing.T) {
withDebugEnabled(t, true)
body := strings.Repeat("e", common.LocalLogContentLimit+256)
var logBuffer bytes.Buffer
common.LogWriterMu.Lock()
oldWriter := gin.DefaultErrorWriter
gin.DefaultErrorWriter = &logBuffer
common.LogWriterMu.Unlock()
t.Cleanup(func() {
common.LogWriterMu.Lock()
gin.DefaultErrorWriter = oldWriter
common.LogWriterMu.Unlock()
})
resp := &http.Response{
StatusCode: http.StatusInternalServerError,
Body: io.NopCloser(strings.NewReader(body)),
}
newAPIError := RelayErrorHandler(context.Background(), resp, false)
require.NotNil(t, newAPIError)
require.NotContains(t, logBuffer.String(), "[truncated")
require.Contains(t, logBuffer.String(), body)
}
func withDebugEnabled(t *testing.T, enabled bool) {
t.Helper()
oldDebug := common.DebugEnabled
common.DebugEnabled = enabled
t.Cleanup(func() {
common.DebugEnabled = oldDebug
})
}