feat: add tracking for auth request success and failure counts

- Introduced `Success` and `Failed` fields in auth records to track request outcomes.
- Updated `/v0/management/auth-files` and `/v0/management/api-key-usage` responses to include success and failure counts.
- Enhanced tests to validate tracking logic and API responses.
This commit is contained in:
Luis Pater
2026-05-02 03:40:00 +08:00
parent 8c2f1a80d3
commit b8bba053fc
7 changed files with 103 additions and 13 deletions
+8
View File
@@ -1126,6 +1126,9 @@ func (m *Manager) Update(ctx context.Context, auth *Auth) (*Auth, error) {
auth.Index = existing.Index
auth.indexAssigned = existing.indexAssigned
}
auth.Success = existing.Success
auth.Failed = existing.Failed
auth.recentRequests = existing.recentRequests
if !existing.Disabled && existing.Status != StatusDisabled && !auth.Disabled && auth.Status != StatusDisabled {
if len(auth.ModelStates) == 0 && len(existing.ModelStates) > 0 {
auth.ModelStates = existing.ModelStates
@@ -2022,6 +2025,11 @@ func (m *Manager) MarkResult(ctx context.Context, result Result) {
if auth, ok := m.auths[result.AuthID]; ok && auth != nil {
now := time.Now()
auth.recordRecentRequest(now, result.Success)
if result.Success {
auth.Success++
} else {
auth.Failed++
}
if result.Success {
if result.Model != "" {
@@ -31,6 +31,10 @@ func TestManagerMarkResultRecordsRecentRequests(t *testing.T) {
t.Fatalf("GetByID returned ok=%v auth=%v", ok, gotAuth)
}
if gotAuth.Success != 1 || gotAuth.Failed != 1 {
t.Fatalf("auth totals = success=%d failed=%d, want 1/1", gotAuth.Success, gotAuth.Failed)
}
snapshot := gotAuth.RecentRequestsSnapshot(time.Now())
var successTotal int64
var failedTotal int64
@@ -42,3 +46,50 @@ func TestManagerMarkResultRecordsRecentRequests(t *testing.T) {
t.Fatalf("totals = success=%d failed=%d, want 1/1", successTotal, failedTotal)
}
}
func TestManagerUpdatePreservesRecentRequestsAndTotals(t *testing.T) {
mgr := NewManager(nil, nil, nil)
auth := &Auth{
ID: "auth-1",
Provider: "antigravity",
Metadata: map[string]any{
"type": "antigravity",
},
}
if _, err := mgr.Register(WithSkipPersist(context.Background()), auth); err != nil {
t.Fatalf("Register returned error: %v", err)
}
mgr.MarkResult(context.Background(), Result{AuthID: "auth-1", Provider: "antigravity", Model: "gpt-5", Success: true})
updated := &Auth{
ID: "auth-1",
Provider: "antigravity",
Metadata: map[string]any{
"type": "antigravity",
"note": "updated",
},
}
if _, err := mgr.Update(WithSkipPersist(context.Background()), updated); err != nil {
t.Fatalf("Update returned error: %v", err)
}
gotAuth, ok := mgr.GetByID("auth-1")
if !ok || gotAuth == nil {
t.Fatalf("GetByID returned ok=%v auth=%v", ok, gotAuth)
}
if gotAuth.Success != 1 || gotAuth.Failed != 0 {
t.Fatalf("auth totals = success=%d failed=%d, want 1/0", gotAuth.Success, gotAuth.Failed)
}
snapshot := gotAuth.RecentRequestsSnapshot(time.Now())
var successTotal int64
var failedTotal int64
for _, bucket := range snapshot {
successTotal += bucket.Success
failedTotal += bucket.Failed
}
if successTotal != 1 || failedTotal != 0 {
t.Fatalf("bucket totals = success=%d failed=%d, want 1/0", successTotal, failedTotal)
}
}
+3
View File
@@ -92,6 +92,9 @@ type Auth struct {
// Runtime carries non-serialisable data used during execution (in-memory only).
Runtime any `json:"-"`
Success int64 `json:"-"`
Failed int64 `json:"-"`
recentRequests recentRequestRing `json:"-"`
indexAssigned bool `json:"-"`
}