forked from wrenn/wrenn
96 lines
2.6 KiB
Go
96 lines
2.6 KiB
Go
package api
|
|
|
|
import (
|
|
"log/slog"
|
|
"net/http"
|
|
"time"
|
|
|
|
"git.omukk.dev/wrenn/wrenn/internal/auth"
|
|
"git.omukk.dev/wrenn/wrenn/internal/service"
|
|
)
|
|
|
|
type statsHandler struct {
|
|
svc *service.StatsService
|
|
}
|
|
|
|
func newStatsHandler(svc *service.StatsService) *statsHandler {
|
|
return &statsHandler{svc: svc}
|
|
}
|
|
|
|
type statsCurrentResponse struct {
|
|
RunningCount int32 `json:"running_count"`
|
|
VCPUsReserved int32 `json:"vcpus_reserved"`
|
|
MemoryMBReserved int32 `json:"memory_mb_reserved"`
|
|
}
|
|
|
|
type statsPeaksResponse struct {
|
|
RunningCount int32 `json:"running_count"`
|
|
VCPUs int32 `json:"vcpus"`
|
|
MemoryMB int32 `json:"memory_mb"`
|
|
}
|
|
|
|
type statsSeriesResponse struct {
|
|
Labels []string `json:"labels"`
|
|
Running []int32 `json:"running"`
|
|
VCPUs []int32 `json:"vcpus"`
|
|
MemoryMB []int32 `json:"memory_mb"`
|
|
}
|
|
|
|
type statsResponse struct {
|
|
Range string `json:"range"`
|
|
Current statsCurrentResponse `json:"current"`
|
|
Peaks statsPeaksResponse `json:"peaks"`
|
|
Series statsSeriesResponse `json:"series"`
|
|
}
|
|
|
|
// GetStats handles GET /v1/capsules/stats?range=5m|1h|6h|24h|30d
|
|
func (h *statsHandler) GetStats(w http.ResponseWriter, r *http.Request) {
|
|
ac := auth.MustFromContext(r.Context())
|
|
|
|
rangeParam := r.URL.Query().Get("range")
|
|
if rangeParam == "" {
|
|
rangeParam = string(service.Range1h)
|
|
}
|
|
tr := service.TimeRange(rangeParam)
|
|
if !service.ValidRange(tr) {
|
|
writeError(w, http.StatusBadRequest, "invalid_request", "range must be one of: 5m, 1h, 6h, 24h, 30d")
|
|
return
|
|
}
|
|
|
|
current, peaks, series, err := h.svc.GetStats(r.Context(), ac.TeamID, tr)
|
|
if err != nil {
|
|
slog.Error("stats handler: get stats failed", "team_id", ac.TeamID, "error", err)
|
|
writeError(w, http.StatusInternalServerError, "internal_error", "failed to retrieve stats")
|
|
return
|
|
}
|
|
|
|
resp := statsResponse{
|
|
Range: rangeParam,
|
|
Current: statsCurrentResponse{
|
|
RunningCount: current.RunningCount,
|
|
VCPUsReserved: current.VCPUsReserved,
|
|
MemoryMBReserved: current.MemoryMBReserved,
|
|
},
|
|
Peaks: statsPeaksResponse{
|
|
RunningCount: peaks.RunningCount,
|
|
VCPUs: peaks.VCPUs,
|
|
MemoryMB: peaks.MemoryMB,
|
|
},
|
|
Series: statsSeriesResponse{
|
|
Labels: make([]string, len(series)),
|
|
Running: make([]int32, len(series)),
|
|
VCPUs: make([]int32, len(series)),
|
|
MemoryMB: make([]int32, len(series)),
|
|
},
|
|
}
|
|
|
|
for i, pt := range series {
|
|
resp.Series.Labels[i] = pt.Bucket.UTC().Format(time.RFC3339)
|
|
resp.Series.Running[i] = pt.RunningCount
|
|
resp.Series.VCPUs[i] = pt.VCPUsReserved
|
|
resp.Series.MemoryMB[i] = pt.MemoryMBReserved
|
|
}
|
|
|
|
writeJSON(w, http.StatusOK, resp)
|
|
}
|