mirror of
https://github.com/router-for-me/CLIProxyAPI.git
synced 2026-06-01 12:22:31 +08:00
feat(logging): add RequestID support in home request logging
- Included `RequestID` field in `homeRequestLogPayload` for better log categorization. - Updated `forwardRequestLogToHome` and related components to handle `RequestID`. - Added new test cases to validate `RequestID` propagation in streaming requests.
This commit is contained in:
@@ -166,6 +166,7 @@ type FileRequestLogger struct {
|
||||
|
||||
type homeRequestLogPayload struct {
|
||||
Headers map[string][]string `json:"headers,omitempty"`
|
||||
RequestID string `json:"request_id,omitempty"`
|
||||
RequestLog string `json:"request_log,omitempty"`
|
||||
}
|
||||
|
||||
@@ -192,7 +193,7 @@ func cloneHeaders(headers map[string][]string) map[string][]string {
|
||||
return out
|
||||
}
|
||||
|
||||
func (l *FileRequestLogger) forwardRequestLogToHome(ctx context.Context, headers map[string][]string, logText string) error {
|
||||
func (l *FileRequestLogger) forwardRequestLogToHome(ctx context.Context, headers map[string][]string, requestID string, logText string) error {
|
||||
if l == nil || !l.homeEnabled {
|
||||
return nil
|
||||
}
|
||||
@@ -202,6 +203,7 @@ func (l *FileRequestLogger) forwardRequestLogToHome(ctx context.Context, headers
|
||||
}
|
||||
payload := homeRequestLogPayload{
|
||||
Headers: cloneHeaders(headers),
|
||||
RequestID: strings.TrimSpace(requestID),
|
||||
RequestLog: logText,
|
||||
}
|
||||
raw, errMarshal := json.Marshal(&payload)
|
||||
@@ -334,7 +336,7 @@ func (l *FileRequestLogger) logRequest(url, method string, requestHeaders map[st
|
||||
if writeErr != nil {
|
||||
return fmt.Errorf("failed to build request log content: %w", writeErr)
|
||||
}
|
||||
return l.forwardRequestLogToHome(context.Background(), requestHeaders, buf.String())
|
||||
return l.forwardRequestLogToHome(context.Background(), requestHeaders, requestID, buf.String())
|
||||
}
|
||||
|
||||
// Ensure logs directory exists
|
||||
@@ -1631,11 +1633,12 @@ type homeStreamingLogWriter struct {
|
||||
apiRequest []byte
|
||||
apiResponse []byte
|
||||
apiWebsocketTime []byte
|
||||
requestID string
|
||||
apiResponseTS time.Time
|
||||
firstChunkTS time.Time
|
||||
}
|
||||
|
||||
func newHomeStreamingLogWriter(url, method string, headers map[string][]string, body []byte, _ string) *homeStreamingLogWriter {
|
||||
func newHomeStreamingLogWriter(url, method string, headers map[string][]string, body []byte, requestID string) *homeStreamingLogWriter {
|
||||
requestHeaders := make(map[string][]string, len(headers))
|
||||
for key, values := range headers {
|
||||
headerValues := make([]string, len(values))
|
||||
@@ -1649,6 +1652,7 @@ func newHomeStreamingLogWriter(url, method string, headers map[string][]string,
|
||||
timestamp: time.Now(),
|
||||
requestHeaders: requestHeaders,
|
||||
requestBody: append([]byte(nil), body...),
|
||||
requestID: strings.TrimSpace(requestID),
|
||||
chunkChan: make(chan []byte, 100),
|
||||
doneChan: make(chan struct{}),
|
||||
}
|
||||
@@ -1766,6 +1770,7 @@ func (w *homeStreamingLogWriter) Close() error {
|
||||
|
||||
payload := homeRequestLogPayload{
|
||||
Headers: cloneHeaders(w.requestHeaders),
|
||||
RequestID: w.requestID,
|
||||
RequestLog: buf.String(),
|
||||
}
|
||||
raw, errMarshal := json.Marshal(&payload)
|
||||
|
||||
@@ -77,6 +77,7 @@ func TestFileRequestLogger_HomeEnabled_ForwardsWhenRequestLogEnabled(t *testing.
|
||||
|
||||
var got struct {
|
||||
Headers map[string][]string `json:"headers"`
|
||||
RequestID string `json:"request_id"`
|
||||
RequestLog string `json:"request_log"`
|
||||
}
|
||||
if errUnmarshal := json.Unmarshal(stub.pushed[0], &got); errUnmarshal != nil {
|
||||
@@ -88,6 +89,62 @@ func TestFileRequestLogger_HomeEnabled_ForwardsWhenRequestLogEnabled(t *testing.
|
||||
if got.Headers == nil || got.Headers["Authorization"][0] != "Bearer secret" {
|
||||
t.Fatalf("headers.authorization = %+v, want Bearer secret", got.Headers["Authorization"])
|
||||
}
|
||||
if got.RequestID != "req-1" {
|
||||
t.Fatalf("request_id = %q, want req-1", got.RequestID)
|
||||
}
|
||||
if got.RequestLog == "" {
|
||||
t.Fatalf("request_log empty, want non-empty")
|
||||
}
|
||||
}
|
||||
|
||||
func TestFileRequestLogger_HomeEnabled_ForwardsStreamingRequestID(t *testing.T) {
|
||||
original := currentHomeRequestLogClient
|
||||
defer func() {
|
||||
currentHomeRequestLogClient = original
|
||||
}()
|
||||
|
||||
stub := &stubHomeRequestLogClient{heartbeatOK: true}
|
||||
currentHomeRequestLogClient = func() homeRequestLogClient {
|
||||
return stub
|
||||
}
|
||||
|
||||
logsDir := t.TempDir()
|
||||
logger := NewFileRequestLogger(true, logsDir, "", 0)
|
||||
logger.SetHomeEnabled(true)
|
||||
|
||||
writer, errLog := logger.LogStreamingRequest(
|
||||
"/v1/responses",
|
||||
http.MethodPost,
|
||||
map[string][]string{"Content-Type": {"application/json"}},
|
||||
[]byte(`{"input":"hello"}`),
|
||||
"stream-req-1",
|
||||
)
|
||||
if errLog != nil {
|
||||
t.Fatalf("LogStreamingRequest error: %v", errLog)
|
||||
}
|
||||
|
||||
if errStatus := writer.WriteStatus(http.StatusOK, map[string][]string{"Content-Type": {"text/event-stream"}}); errStatus != nil {
|
||||
t.Fatalf("WriteStatus error: %v", errStatus)
|
||||
}
|
||||
writer.WriteChunkAsync([]byte("data: ok\n\n"))
|
||||
if errClose := writer.Close(); errClose != nil {
|
||||
t.Fatalf("Close error: %v", errClose)
|
||||
}
|
||||
|
||||
if len(stub.pushed) != 1 {
|
||||
t.Fatalf("home pushed records = %d, want 1", len(stub.pushed))
|
||||
}
|
||||
|
||||
var got struct {
|
||||
RequestID string `json:"request_id"`
|
||||
RequestLog string `json:"request_log"`
|
||||
}
|
||||
if errUnmarshal := json.Unmarshal(stub.pushed[0], &got); errUnmarshal != nil {
|
||||
t.Fatalf("unmarshal payload: %v payload=%s", errUnmarshal, string(stub.pushed[0]))
|
||||
}
|
||||
if got.RequestID != "stream-req-1" {
|
||||
t.Fatalf("request_id = %q, want stream-req-1", got.RequestID)
|
||||
}
|
||||
if got.RequestLog == "" {
|
||||
t.Fatalf("request_log empty, want non-empty")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user