import os import json import time import requests from django.conf import settings from django.shortcuts import render from django.http import JsonResponse, HttpResponse from django.template.loader import render_to_string # Helper: query Prometheus HTTP API (query_range) def query_prometheus_range(query, start, end, step="60s"): url = settings.PROMETHEUS_URL.rstrip("/") + "/api/v1/query_range" params = {"query": query, "start": start, "end": end, "step": step} r = requests.get(url, params=params, timeout=10) r.raise_for_status() return r.json() # API endpoint used by Chart.js frontend def metrics_api(request): # get parameters or default (last 1 hour) metric = request.GET.get("metric", settings.PROMETHEUS_DEFAULT_METRIC) now = int(time.time()) start = request.GET.get("start", str(now - 3600)) # unix epoch seconds end = request.GET.get("end", str(now)) step = request.GET.get("step", "60s") # Example: if the metric is a gauge giving bytes, we may want to convert ... keep raw for now q = metric data = query_prometheus_range(q, start, end, step) # Prometheus returns JSON; keep it minimal for Chart.js: {labels: [...], datasets: [{label,...,data:[...]}]} series = [] labels = [] datasets = [] if data.get("status") != "success": return JsonResponse({"error": "prometheus error", "detail": data}) result = data["data"]["result"] # list of time series # if no series, return empty if not result: return JsonResponse({"labels": [], "datasets": []}) # Build labels from first series timestamps # Prometheus returns values as [[ts, value], ...] first_values = result[0]["values"] labels = [int(float(t[0])) * 1000 for t in first_values] # JS prefers ms for s in result: # create dataset for each timeseries (label from metric labels) metric_labels = s.get("metric", {}) label = metric_labels.get("instance") or metric_labels.get("domain") or json.dumps(metric_labels) values = [float(v[1]) if v[1] != "NaN" else None for v in s["values"]] datasets.append({ "label": label, "data": values, }) return JsonResponse({"labels": labels, "datasets": datasets}) # Dashboard page (Jinja template) def dashboard(request): # let template ask API for data with JS. return render(request, "dashboard.html", { "default_metric": settings.PROMETHEUS_DEFAULT_METRIC, }) # Render page to PDF using WeasyPrint def report_pdf(request): # optionally accept ?metric=...&start=...&end=... metric = request.GET.get("metric", settings.PROMETHEUS_DEFAULT_METRIC) now = int(time.time()) start = int(request.GET.get("start", now - 3600)) end = int(request.GET.get("end", now)) # fetch data server-side to include in report try: resp = query_prometheus_range(metric, start, end, step="60s") except Exception as e: return HttpResponse(f"Error fetching metrics: {e}", status=500) context = { "metric": metric, "prom_data": resp.get("data", {}), "generated_at": time.strftime("%Y-%m-%d %H:%M:%S", time.gmtime()), } html = render_to_string("report.html", context) # Generate PDF via WeasyPrint from weasyprint import HTML pdf = HTML(string=html, base_url=request.build_absolute_uri("/")).write_pdf() return HttpResponse(pdf, content_type="application/pdf")