forked from wrenn/wrenn
Add 5m, 1h, 6h, 12h range filters to metrics endpoint
Maps each user-facing range to the appropriate underlying ring buffer tier and applies a time cutoff filter. No new ring buffers needed — 5m/10m read from the 10m tier, 1h/2h from the 2h tier, 6h/12h/24h from the 24h tier.
This commit is contained in:
@ -3,6 +3,7 @@ package api
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"connectrpc.com/connect"
|
||||
"github.com/go-chi/chi/v5"
|
||||
@ -45,8 +46,9 @@ func (h *sandboxMetricsHandler) GetMetrics(w http.ResponseWriter, r *http.Reques
|
||||
if rangeTier == "" {
|
||||
rangeTier = "10m"
|
||||
}
|
||||
if rangeTier != "10m" && rangeTier != "2h" && rangeTier != "24h" {
|
||||
writeError(w, http.StatusBadRequest, "invalid_request", "range must be 10m, 2h, or 24h")
|
||||
validRanges := map[string]bool{"5m": true, "10m": true, "1h": true, "2h": true, "6h": true, "12h": true, "24h": true}
|
||||
if !validRanges[rangeTier] {
|
||||
writeError(w, http.StatusBadRequest, "invalid_request", "range must be one of: 5m, 10m, 1h, 2h, 6h, 12h, 24h")
|
||||
return
|
||||
}
|
||||
|
||||
@ -102,23 +104,41 @@ func (h *sandboxMetricsHandler) getFromAgent(w http.ResponseWriter, r *http.Requ
|
||||
})
|
||||
}
|
||||
|
||||
// rangeToDB maps a user-facing range filter to the DB tier and cutoff duration.
|
||||
var rangeToDB = map[string]struct {
|
||||
tier string
|
||||
cutoff time.Duration
|
||||
}{
|
||||
"5m": {"10m", 5 * time.Minute},
|
||||
"10m": {"10m", 10 * time.Minute},
|
||||
"1h": {"2h", 1 * time.Hour},
|
||||
"2h": {"2h", 2 * time.Hour},
|
||||
"6h": {"24h", 6 * time.Hour},
|
||||
"12h": {"24h", 12 * time.Hour},
|
||||
"24h": {"24h", 24 * time.Hour},
|
||||
}
|
||||
|
||||
func (h *sandboxMetricsHandler) getFromDB(ctx context.Context, w http.ResponseWriter, sandboxID, rangeTier string) {
|
||||
mapping := rangeToDB[rangeTier]
|
||||
rows, err := h.db.GetSandboxMetricPoints(ctx, db.GetSandboxMetricPointsParams{
|
||||
SandboxID: sandboxID,
|
||||
Tier: rangeTier,
|
||||
Tier: mapping.tier,
|
||||
})
|
||||
if err != nil {
|
||||
writeError(w, http.StatusInternalServerError, "internal_error", "failed to read metrics")
|
||||
return
|
||||
}
|
||||
|
||||
points := make([]metricPointResponse, len(rows))
|
||||
for i, row := range rows {
|
||||
points[i] = metricPointResponse{
|
||||
threshold := time.Now().Add(-mapping.cutoff).Unix()
|
||||
var points []metricPointResponse
|
||||
for _, row := range rows {
|
||||
if row.Ts >= threshold {
|
||||
points = append(points, metricPointResponse{
|
||||
TimestampUnix: row.Ts,
|
||||
CPUPct: row.CpuPct,
|
||||
MemBytes: row.MemBytes,
|
||||
DiskBytes: row.DiskBytes,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -782,9 +782,9 @@ paths:
|
||||
required: false
|
||||
schema:
|
||||
type: string
|
||||
enum: ["10m", "2h", "24h"]
|
||||
enum: ["5m", "10m", "1h", "2h", "6h", "12h", "24h"]
|
||||
default: "10m"
|
||||
description: Time range tier to query
|
||||
description: Time range filter to query
|
||||
responses:
|
||||
"200":
|
||||
description: Metrics retrieved
|
||||
@ -2042,7 +2042,7 @@ components:
|
||||
type: string
|
||||
range:
|
||||
type: string
|
||||
enum: ["10m", "2h", "24h"]
|
||||
enum: ["5m", "10m", "1h", "2h", "6h", "12h", "24h"]
|
||||
points:
|
||||
type: array
|
||||
items:
|
||||
|
||||
@ -1348,16 +1348,44 @@ func (m *Manager) GetMetrics(sandboxID, rangeTier string) ([]MetricPoint, error)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// Map the requested range to the appropriate ring tier and time cutoff.
|
||||
var points []MetricPoint
|
||||
var cutoff time.Duration
|
||||
switch rangeTier {
|
||||
case "5m":
|
||||
points = sb.ring.Get10m()
|
||||
cutoff = 5 * time.Minute
|
||||
case "10m":
|
||||
return sb.ring.Get10m(), nil
|
||||
points = sb.ring.Get10m()
|
||||
cutoff = 10 * time.Minute
|
||||
case "1h":
|
||||
points = sb.ring.Get2h()
|
||||
cutoff = 1 * time.Hour
|
||||
case "2h":
|
||||
return sb.ring.Get2h(), nil
|
||||
points = sb.ring.Get2h()
|
||||
cutoff = 2 * time.Hour
|
||||
case "6h":
|
||||
points = sb.ring.Get24h()
|
||||
cutoff = 6 * time.Hour
|
||||
case "12h":
|
||||
points = sb.ring.Get24h()
|
||||
cutoff = 12 * time.Hour
|
||||
case "24h":
|
||||
return sb.ring.Get24h(), nil
|
||||
points = sb.ring.Get24h()
|
||||
cutoff = 24 * time.Hour
|
||||
default:
|
||||
return nil, fmt.Errorf("invalid range: %s (valid: 10m, 2h, 24h)", rangeTier)
|
||||
return nil, fmt.Errorf("invalid range: %s (valid: 5m, 10m, 1h, 2h, 6h, 12h, 24h)", rangeTier)
|
||||
}
|
||||
|
||||
// Filter points to the requested time window.
|
||||
threshold := time.Now().Add(-cutoff)
|
||||
filtered := points[:0:0]
|
||||
for _, p := range points {
|
||||
if !p.Timestamp.Before(threshold) {
|
||||
filtered = append(filtered, p)
|
||||
}
|
||||
}
|
||||
return filtered, nil
|
||||
}
|
||||
|
||||
// FlushMetrics returns all three tier ring buffers, clears the ring, and
|
||||
|
||||
Reference in New Issue
Block a user