package httpapi import ( "context" "net/http" "strconv" "time" ) func (s *Server) registerPostgresMonitoringRoutes(m *http.ServeMux) { m.HandleFunc("GET /monitoring/postgres/overview", s.handlePostgresOverview) m.HandleFunc("GET /monitoring/postgres/queries", s.handlePostgresQueries) m.HandleFunc("GET /monitoring/postgres/locks", s.handlePostgresLocks) m.HandleFunc("GET /monitoring/postgres/tables", s.handlePostgresTables) m.HandleFunc("GET /monitoring/postgres/recommendations", s.handlePostgresRecommendations) m.HandleFunc("GET /monitoring/correlation", s.handleMonitoringCorrelation) } func (s *Server) requirePostgres(w http.ResponseWriter) bool { if s.pgMonitor == nil { writeProblem(w, http.StatusServiceUnavailable, "Unavailable", "postgresql backend required") return false } return true } func parseLimitQuery(r *http.Request, def, max int) int { if v := r.URL.Query().Get("limit"); v != "" { if n, err := strconv.Atoi(v); err == nil { return n } } return def } func (s *Server) handlePostgresOverview(w http.ResponseWriter, r *http.Request) { a, ok := authFromContext(r.Context()) if !ok || !s.requirePerm(w, a, "bgp:monitoring:read") || !s.requirePostgres(w) { return } ctx, cancel := context.WithTimeout(r.Context(), 3*time.Second) defer cancel() out, err := s.pgMonitor.Overview(ctx) if err != nil { writeInternalError(w, "postgres_overview", err) return } writeJSON(w, http.StatusOK, out) } func (s *Server) handlePostgresQueries(w http.ResponseWriter, r *http.Request) { a, ok := authFromContext(r.Context()) if !ok || !s.requirePerm(w, a, "bgp:monitoring:read") || !s.requirePostgres(w) { return } ctx, cancel := context.WithTimeout(r.Context(), 3*time.Second) defer cancel() out, err := s.pgMonitor.TopQueries(ctx, parseLimitQuery(r, 20, 100)) if err != nil { writeInternalError(w, "postgres_queries", err) return } writeJSON(w, http.StatusOK, out) } func (s *Server) handlePostgresLocks(w http.ResponseWriter, r *http.Request) { a, ok := authFromContext(r.Context()) if !ok || !s.requirePerm(w, a, "bgp:monitoring:read") || !s.requirePostgres(w) { return } ctx, cancel := context.WithTimeout(r.Context(), 3*time.Second) defer cancel() out, err := s.pgMonitor.Locks(ctx) if err != nil { writeInternalError(w, "postgres_locks", err) return } writeJSON(w, http.StatusOK, map[string]any{"items": out}) } func (s *Server) handlePostgresTables(w http.ResponseWriter, r *http.Request) { a, ok := authFromContext(r.Context()) if !ok || !s.requirePerm(w, a, "bgp:monitoring:read") || !s.requirePostgres(w) { return } ctx, cancel := context.WithTimeout(r.Context(), 3*time.Second) defer cancel() out, err := s.pgMonitor.Tables(ctx, parseLimitQuery(r, 20, 100)) if err != nil { writeInternalError(w, "postgres_tables", err) return } writeJSON(w, http.StatusOK, map[string]any{"items": out}) } func (s *Server) handlePostgresRecommendations(w http.ResponseWriter, r *http.Request) { a, ok := authFromContext(r.Context()) if !ok || !s.requirePerm(w, a, "bgp:monitoring:read") || !s.requirePostgres(w) { return } ctx, cancel := context.WithTimeout(r.Context(), 5*time.Second) defer cancel() out, err := s.pgMonitor.Recommendations(ctx) if err != nil { writeInternalError(w, "postgres_recommendations", err) return } writeJSON(w, http.StatusOK, out) } func (s *Server) handleMonitoringCorrelation(w http.ResponseWriter, r *http.Request) { a, ok := authFromContext(r.Context()) if !ok || !s.requirePerm(w, a, "bgp:monitoring:read") || !s.requirePostgres(w) { return } window := 60 if v := r.URL.Query().Get("window"); v != "" { if n, err := strconv.Atoi(v); err == nil { window = n } } ctx, cancel := context.WithTimeout(r.Context(), 5*time.Second) defer cancel() out, err := s.pgMonitor.Correlation(ctx, window) if err != nil { writeInternalError(w, "monitoring_correlation", err) return } writeJSON(w, http.StatusOK, out) }