- Backend DB komplett auf PostgreSQL 17 + TimescaleDB 2.25.1 umgestellt - pgx pure-Go Driver (kein CGO), modernc/sqlite entfernt - Hypertable 'metrics' fuer Time-Series Daten - Automatische Metrik-Extraktion bei jedem Heartbeat: CPU, RAM, Uptime, Disk, Network-Traffic, Gateway RTT/Loss - Retention Policy: 90 Tage, Compression nach 7 Tagen - Neue API-Endpoints: GET /metrics (raw) + GET /metrics/summary (aggregiert) - time_bucket() Aggregation (5min, 1h, etc.) - config.yaml: database-Block statt db_path - docs/POSTGRES_SETUP.md: Installationsanleitung - README aktualisiert
84 lines
2.0 KiB
Go
84 lines
2.0 KiB
Go
package api
|
|
|
|
import (
|
|
"net/http"
|
|
"strconv"
|
|
"time"
|
|
)
|
|
|
|
// GET /api/v1/agents/{id}/metrics — Metriken abfragen
|
|
func (h *Handler) getMetrics() http.HandlerFunc {
|
|
return func(w http.ResponseWriter, r *http.Request) {
|
|
agentID := r.PathValue("id")
|
|
metric := r.URL.Query().Get("metric")
|
|
|
|
// Zeitraum (default: letzte 24h)
|
|
from := time.Now().Add(-24 * time.Hour)
|
|
to := time.Now()
|
|
|
|
if f := r.URL.Query().Get("from"); f != "" {
|
|
if t, err := time.Parse(time.RFC3339, f); err == nil {
|
|
from = t
|
|
}
|
|
}
|
|
if t := r.URL.Query().Get("to"); t != "" {
|
|
if parsed, err := time.Parse(time.RFC3339, t); err == nil {
|
|
to = parsed
|
|
}
|
|
}
|
|
|
|
limit := 1000
|
|
if l := r.URL.Query().Get("limit"); l != "" {
|
|
if parsed, err := strconv.Atoi(l); err == nil && parsed > 0 {
|
|
limit = parsed
|
|
}
|
|
}
|
|
|
|
results, err := h.db.GetMetrics(agentID, metric, from, to, limit)
|
|
if err != nil {
|
|
writeError(w, http.StatusInternalServerError, "Metriken laden fehlgeschlagen")
|
|
return
|
|
}
|
|
writeJSON(w, http.StatusOK, results)
|
|
}
|
|
}
|
|
|
|
// GET /api/v1/agents/{id}/metrics/summary — Aggregierte Metriken (Durchschnitt/Min/Max)
|
|
func (h *Handler) getMetricsSummary() http.HandlerFunc {
|
|
return func(w http.ResponseWriter, r *http.Request) {
|
|
agentID := r.PathValue("id")
|
|
metric := r.URL.Query().Get("metric")
|
|
|
|
if metric == "" {
|
|
writeError(w, http.StatusBadRequest, "Parameter 'metric' erforderlich")
|
|
return
|
|
}
|
|
|
|
bucket := r.URL.Query().Get("bucket")
|
|
if bucket == "" {
|
|
bucket = "5 minutes"
|
|
}
|
|
|
|
from := time.Now().Add(-24 * time.Hour)
|
|
to := time.Now()
|
|
|
|
if f := r.URL.Query().Get("from"); f != "" {
|
|
if t, err := time.Parse(time.RFC3339, f); err == nil {
|
|
from = t
|
|
}
|
|
}
|
|
if t := r.URL.Query().Get("to"); t != "" {
|
|
if parsed, err := time.Parse(time.RFC3339, t); err == nil {
|
|
to = parsed
|
|
}
|
|
}
|
|
|
|
results, err := h.db.GetMetricsSummary(agentID, metric, bucket, from, to)
|
|
if err != nil {
|
|
writeError(w, http.StatusInternalServerError, "Metriken laden fehlgeschlagen")
|
|
return
|
|
}
|
|
writeJSON(w, http.StatusOK, results)
|
|
}
|
|
}
|