feat: add Sora admin page and integrate DB/Redis Prometheus metrics
- Create SoraAdminView with overview, user stats, and generations tabs - Add /admin/sora route for Sora management - Add i18n support (zh/en) for Sora admin page - Extract Prometheus metrics to prommetrics package to avoid import cycles - Integrate SetDBConnections/SetRedisConnections in OpsMetricsCollector
This commit is contained in:
@@ -2,12 +2,11 @@ package routes
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strconv"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/Wei-Shaw/sub2api/internal/prommetrics"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||
)
|
||||
|
||||
@@ -20,125 +19,8 @@ type HealthChecker interface {
|
||||
var (
|
||||
healthChecker HealthChecker
|
||||
healthCheckerOnce sync.Once
|
||||
|
||||
// Prometheus metrics
|
||||
prometheusRegistry = prometheus.NewRegistry()
|
||||
|
||||
// Custom metrics
|
||||
httpRequestsTotal = prometheus.NewCounterVec(
|
||||
prometheus.CounterOpts{
|
||||
Name: "sub2api_http_requests_total",
|
||||
Help: "Total number of HTTP requests",
|
||||
},
|
||||
[]string{"method", "path", "status"},
|
||||
)
|
||||
|
||||
httpRequestDuration = prometheus.NewHistogramVec(
|
||||
prometheus.HistogramOpts{
|
||||
Name: "sub2api_http_request_duration_seconds",
|
||||
Help: "HTTP request duration in seconds",
|
||||
Buckets: prometheus.DefBuckets,
|
||||
},
|
||||
[]string{"method", "path"},
|
||||
)
|
||||
|
||||
dbConnectionsActive = prometheus.NewGauge(
|
||||
prometheus.GaugeOpts{
|
||||
Name: "sub2api_db_connections_active",
|
||||
Help: "Number of active database connections",
|
||||
},
|
||||
)
|
||||
|
||||
dbConnectionsIdle = prometheus.NewGauge(
|
||||
prometheus.GaugeOpts{
|
||||
Name: "sub2api_db_connections_idle",
|
||||
Help: "Number of idle database connections",
|
||||
},
|
||||
)
|
||||
|
||||
redisConnectionsTotal = prometheus.NewGauge(
|
||||
prometheus.GaugeOpts{
|
||||
Name: "sub2api_redis_connections_total",
|
||||
Help: "Total number of Redis connections",
|
||||
},
|
||||
)
|
||||
|
||||
redisConnectionsIdle = prometheus.NewGauge(
|
||||
prometheus.GaugeOpts{
|
||||
Name: "sub2api_redis_connections_idle",
|
||||
Help: "Number of idle Redis connections",
|
||||
},
|
||||
)
|
||||
|
||||
accountActiveTotal = prometheus.NewGauge(
|
||||
prometheus.GaugeOpts{
|
||||
Name: "sub2api_accounts_active_total",
|
||||
Help: "Total number of active accounts",
|
||||
},
|
||||
)
|
||||
|
||||
requestQueueDepth = prometheus.NewGauge(
|
||||
prometheus.GaugeOpts{
|
||||
Name: "sub2api_request_queue_depth",
|
||||
Help: "Current request queue depth",
|
||||
},
|
||||
)
|
||||
|
||||
opsHealthScore = prometheus.NewGauge(
|
||||
prometheus.GaugeOpts{
|
||||
Name: "sub2api_ops_health_score",
|
||||
Help: "Overall system health score (0-100)",
|
||||
},
|
||||
)
|
||||
|
||||
errorRate = prometheus.NewGauge(
|
||||
prometheus.GaugeOpts{
|
||||
Name: "sub2api_error_rate",
|
||||
Help: "Current error rate",
|
||||
},
|
||||
)
|
||||
|
||||
successRate = prometheus.NewGauge(
|
||||
prometheus.GaugeOpts{
|
||||
Name: "sub2api_success_rate",
|
||||
Help: "Current success rate",
|
||||
},
|
||||
)
|
||||
|
||||
qps = prometheus.NewGauge(
|
||||
prometheus.GaugeOpts{
|
||||
Name: "sub2api_qps",
|
||||
Help: "Queries per second",
|
||||
},
|
||||
)
|
||||
|
||||
tps = prometheus.NewGauge(
|
||||
prometheus.GaugeOpts{
|
||||
Name: "sub2api_tps",
|
||||
Help: "Tokens per second",
|
||||
},
|
||||
)
|
||||
)
|
||||
|
||||
func init() {
|
||||
// Register custom metrics
|
||||
prometheusRegistry.MustRegister(
|
||||
httpRequestsTotal,
|
||||
httpRequestDuration,
|
||||
dbConnectionsActive,
|
||||
dbConnectionsIdle,
|
||||
redisConnectionsTotal,
|
||||
redisConnectionsIdle,
|
||||
accountActiveTotal,
|
||||
requestQueueDepth,
|
||||
opsHealthScore,
|
||||
errorRate,
|
||||
successRate,
|
||||
qps,
|
||||
tps,
|
||||
)
|
||||
}
|
||||
|
||||
// SetHealthChecker sets the health checker instance (called during app initialization)
|
||||
func SetHealthChecker(checker HealthChecker) {
|
||||
healthCheckerOnce.Do(func() {
|
||||
@@ -157,8 +39,8 @@ func RegisterCommonRoutes(r *gin.Engine) {
|
||||
// Liveness check - for Kubernetes liveness probe
|
||||
r.GET("/live", livenessHandler)
|
||||
|
||||
// Prometheus metrics endpoint
|
||||
r.GET("/metrics", gin.WrapH(promhttp.HandlerFor(prometheusRegistry, promhttp.HandlerOpts{})))
|
||||
// Prometheus metrics endpoint - use the shared registry from prommetrics package
|
||||
r.GET("/metrics", gin.WrapH(promhttp.HandlerFor(prommetrics.Registry, promhttp.HandlerOpts{})))
|
||||
|
||||
// Claude Code telemetry logs (ignore, return 200 directly)
|
||||
r.POST("/api/event_logging/batch", func(c *gin.Context) {
|
||||
@@ -275,57 +157,54 @@ func livenessHandler(c *gin.Context) {
|
||||
})
|
||||
}
|
||||
|
||||
// Prometheus metric update functions
|
||||
// Prometheus metric update functions - delegate to prommetrics package
|
||||
|
||||
// RecordHTTPRequest records an HTTP request for Prometheus metrics
|
||||
func RecordHTTPRequest(method, path string, statusCode int, duration time.Duration) {
|
||||
httpRequestsTotal.WithLabelValues(method, path, strconv.Itoa(statusCode)).Inc()
|
||||
httpRequestDuration.WithLabelValues(method, path).Observe(duration.Seconds())
|
||||
prommetrics.RecordHTTPRequest(method, path, statusCode, duration)
|
||||
}
|
||||
|
||||
// SetDBConnections sets database connection metrics
|
||||
func SetDBConnections(active, idle int) {
|
||||
dbConnectionsActive.Set(float64(active))
|
||||
dbConnectionsIdle.Set(float64(idle))
|
||||
prommetrics.SetDBConnections(active, idle)
|
||||
}
|
||||
|
||||
// SetRedisConnections sets Redis connection metrics
|
||||
func SetRedisConnections(total, idle int) {
|
||||
redisConnectionsTotal.Set(float64(total))
|
||||
redisConnectionsIdle.Set(float64(idle))
|
||||
prommetrics.SetRedisConnections(total, idle)
|
||||
}
|
||||
|
||||
// SetActiveAccounts sets the active accounts count
|
||||
func SetActiveAccounts(count int) {
|
||||
accountActiveTotal.Set(float64(count))
|
||||
prommetrics.SetActiveAccounts(count)
|
||||
}
|
||||
|
||||
// SetRequestQueueDepth sets the request queue depth
|
||||
func SetRequestQueueDepth(depth int) {
|
||||
requestQueueDepth.Set(float64(depth))
|
||||
prommetrics.SetRequestQueueDepth(depth)
|
||||
}
|
||||
|
||||
// SetOpsHealthScore sets the overall health score
|
||||
func SetOpsHealthScore(score int) {
|
||||
opsHealthScore.Set(float64(score))
|
||||
prommetrics.SetOpsHealthScore(score)
|
||||
}
|
||||
|
||||
// SetErrorRate sets the error rate
|
||||
func SetErrorRate(rate float64) {
|
||||
errorRate.Set(rate)
|
||||
prommetrics.SetErrorRate(rate)
|
||||
}
|
||||
|
||||
// SetSuccessRate sets the success rate
|
||||
func SetSuccessRate(rate float64) {
|
||||
successRate.Set(rate)
|
||||
prommetrics.SetSuccessRate(rate)
|
||||
}
|
||||
|
||||
// SetQPS sets queries per second
|
||||
func SetQPS(value float64) {
|
||||
qps.Set(value)
|
||||
prommetrics.SetQPS(value)
|
||||
}
|
||||
|
||||
// SetTPS sets tokens per second
|
||||
func SetTPS(value float64) {
|
||||
tps.Set(value)
|
||||
prommetrics.SetTPS(value)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user