feat: log non-200/non-429 kiro errors to rolling file for debugging
Some checks failed
Build Docker Image / build (push) Has been cancelled
Some checks failed
Build Docker Image / build (push) Has been cancelled
Writes request body + response body of failed upstream calls to kiro_errors.log in the working directory. File is capped at 10MB; when the next write would exceed that, the file is truncated so only the most recent records are kept. Helps diagnose 400 "Improperly formed request" errors where both CW and Q reject the same payload. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
47
proxy/error_log.go
Normal file
47
proxy/error_log.go
Normal file
@@ -0,0 +1,47 @@
|
||||
package proxy
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
kiroErrorLogPath = "kiro_errors.log"
|
||||
kiroErrorLogMaxSize = 10 * 1024 * 1024 // 10MB, truncate and restart when exceeded
|
||||
)
|
||||
|
||||
var kiroErrorLogMu sync.Mutex
|
||||
|
||||
// logKiroError appends a non-200/non-429 failure record to kiro_errors.log in the
|
||||
// current working directory. The file is capped at 10MB; when the next write would
|
||||
// push it over the limit, the file is truncated so only the most recent records
|
||||
// are retained.
|
||||
func logKiroError(reqID, endpoint string, status int, account, model string, reqBody, respBody []byte) {
|
||||
kiroErrorLogMu.Lock()
|
||||
defer kiroErrorLogMu.Unlock()
|
||||
|
||||
entry := fmt.Sprintf(
|
||||
"===== %s req=%s endpoint=%s status=%d account=%s model=%s =====\n"+
|
||||
"-- request body --\n%s\n"+
|
||||
"-- response body --\n%s\n\n",
|
||||
time.Now().Format("2006-01-02 15:04:05"),
|
||||
reqID, endpoint, status, account, model,
|
||||
string(reqBody), string(respBody),
|
||||
)
|
||||
|
||||
// If the next entry would exceed the cap, truncate the file first.
|
||||
if info, err := os.Stat(kiroErrorLogPath); err == nil {
|
||||
if info.Size()+int64(len(entry)) > kiroErrorLogMaxSize {
|
||||
_ = os.Truncate(kiroErrorLogPath, 0)
|
||||
}
|
||||
}
|
||||
|
||||
f, err := os.OpenFile(kiroErrorLogPath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer f.Close()
|
||||
_, _ = f.WriteString(entry)
|
||||
}
|
||||
@@ -285,6 +285,11 @@ func CallKiroAPI(account *config.Account, payload *KiroPayload, callback *KiroSt
|
||||
lastStatus = fmt.Sprintf("%d", resp.StatusCode)
|
||||
bodyStr := string(errBody)
|
||||
|
||||
// 记录非 200 / 非 429 的请求体和响应体以便排查(本地滚动日志,上限 10MB)
|
||||
if resp.StatusCode != 429 {
|
||||
logKiroError(reqID, ep.Name, resp.StatusCode, accountLabel, modelID, reqBody, errBody)
|
||||
}
|
||||
|
||||
if resp.StatusCode == 401 || resp.StatusCode == 403 {
|
||||
log.Printf("[KiroAPI] %d %s %s/a%d auth_error %s %s", resp.StatusCode, reqID, epShort, attempt, fmtMs(time.Since(attemptStart)), truncateForLog(bodyStr, 200))
|
||||
log.Printf("[KiroAPI] FAIL %s all endpoints failed %s last=%s", reqID, fmtMs(time.Since(requestStart)), lastStatus)
|
||||
|
||||
Reference in New Issue
Block a user