fix: truncate oversized upstream error logs (#5083)
This commit is contained in:
@@ -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
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user