Files
watcher-visio/watcher_visio/metrics/views.py
2025-11-28 00:20:23 +03:00

91 lines
3.4 KiB
Python

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")