Files
CLIProxyAPI/internal/api/handlers/management/api_key_usage.go
T
Luis Pater b8bba053fc 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.
2026-05-02 03:40:00 +08:00

108 lines
2.6 KiB
Go

package management
import (
"net/http"
"strings"
"time"
"github.com/gin-gonic/gin"
coreauth "github.com/router-for-me/CLIProxyAPI/v6/sdk/cliproxy/auth"
)
type apiKeyUsageEntry struct {
Success int64 `json:"success"`
Failed int64 `json:"failed"`
RecentRequests []coreauth.RecentRequestBucket `json:"recent_requests"`
}
func mergeRecentRequestBuckets(dst, src []coreauth.RecentRequestBucket) []coreauth.RecentRequestBucket {
if len(dst) == 0 {
return src
}
if len(src) == 0 {
return dst
}
if len(dst) != len(src) {
n := len(dst)
if len(src) < n {
n = len(src)
}
for i := 0; i < n; i++ {
dst[i].Success += src[i].Success
dst[i].Failed += src[i].Failed
}
return dst
}
for i := range dst {
dst[i].Success += src[i].Success
dst[i].Failed += src[i].Failed
}
return dst
}
// GetAPIKeyUsage returns recent request buckets for all in-memory api_key auths,
// grouped by provider and keyed by "base_url|api_key".
func (h *Handler) GetAPIKeyUsage(c *gin.Context) {
if h == nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "handler not initialized"})
return
}
h.mu.Lock()
manager := h.authManager
h.mu.Unlock()
if manager == nil {
c.JSON(http.StatusServiceUnavailable, gin.H{"error": "core auth manager unavailable"})
return
}
now := time.Now()
out := make(map[string]map[string]apiKeyUsageEntry)
for _, auth := range manager.List() {
if auth == nil {
continue
}
kind, apiKey := auth.AccountInfo()
if !strings.EqualFold(strings.TrimSpace(kind), "api_key") {
continue
}
apiKey = strings.TrimSpace(apiKey)
if apiKey == "" {
continue
}
baseURL := ""
if auth.Attributes != nil {
baseURL = strings.TrimSpace(auth.Attributes["base_url"])
if baseURL == "" {
baseURL = strings.TrimSpace(auth.Attributes["base-url"])
}
}
compositeKey := baseURL + "|" + apiKey
provider := strings.ToLower(strings.TrimSpace(auth.Provider))
if provider == "" {
provider = "unknown"
}
recent := auth.RecentRequestsSnapshot(now)
providerBucket, ok := out[provider]
if !ok {
providerBucket = make(map[string]apiKeyUsageEntry)
out[provider] = providerBucket
}
if existing, exists := providerBucket[compositeKey]; exists {
existing.Success += auth.Success
existing.Failed += auth.Failed
existing.RecentRequests = mergeRecentRequestBuckets(existing.RecentRequests, recent)
providerBucket[compositeKey] = existing
continue
}
providerBucket[compositeKey] = apiKeyUsageEntry{
Success: auth.Success,
Failed: auth.Failed,
RecentRequests: recent,
}
}
c.JSON(http.StatusOK, out)
}