71 lines
2.4 KiB
Python
71 lines
2.4 KiB
Python
# plugins/traefik/routes.py
|
|
from __future__ import annotations
|
|
from quart import Blueprint, current_app, render_template
|
|
from sqlalchemy import select
|
|
|
|
from fablednetmon.auth.middleware import require_role
|
|
from fablednetmon.models.users import UserRole
|
|
from .models import TraefikMetric
|
|
|
|
traefik_bp = Blueprint("traefik", __name__, template_folder="templates")
|
|
|
|
|
|
def _sparkline(values: list[float], width: int = 80, height: int = 20) -> str:
|
|
"""Generate an inline SVG sparkline from a list of float values."""
|
|
if len(values) < 2:
|
|
return f'<svg width="{width}" height="{height}"></svg>'
|
|
mn, mx = min(values), max(values)
|
|
if mx == mn:
|
|
mx = mn + 1.0
|
|
step = width / (len(values) - 1)
|
|
pts = []
|
|
for i, v in enumerate(values):
|
|
x = i * step
|
|
y = height - (v - mn) / (mx - mn) * (height - 2) - 1
|
|
pts.append(f"{x:.1f},{y:.1f}")
|
|
poly = " ".join(pts)
|
|
return (
|
|
f'<svg width="{width}" height="{height}" viewBox="0 0 {width} {height}" '
|
|
f'style="vertical-align:middle;">'
|
|
f'<polyline points="{poly}" fill="none" stroke="#6060c0" stroke-width="1.5"/>'
|
|
f'</svg>'
|
|
)
|
|
|
|
|
|
@traefik_bp.get("/")
|
|
@require_role(UserRole.viewer)
|
|
async def index():
|
|
# Last 20 data points per router for sparklines
|
|
history_limit = 20
|
|
|
|
async with current_app.db_sessionmaker() as db:
|
|
# Get distinct router names with a recent row
|
|
result = await db.execute(
|
|
select(TraefikMetric.router_name)
|
|
.distinct()
|
|
.order_by(TraefikMetric.router_name)
|
|
)
|
|
routers = [row[0] for row in result.all()]
|
|
|
|
router_data = []
|
|
for router in routers:
|
|
result = await db.execute(
|
|
select(TraefikMetric)
|
|
.where(TraefikMetric.router_name == router)
|
|
.order_by(TraefikMetric.scraped_at.desc())
|
|
.limit(history_limit)
|
|
)
|
|
rows = list(reversed(result.scalars().all()))
|
|
if not rows:
|
|
continue
|
|
latest = rows[-1]
|
|
router_data.append({
|
|
"name": router,
|
|
"latest": latest,
|
|
"sparkline_req": _sparkline([r.request_rate for r in rows]),
|
|
"sparkline_p95": _sparkline([r.latency_p95_ms for r in rows]),
|
|
"sparkline_5xx": _sparkline([r.error_rate_5xx_pct for r in rows]),
|
|
})
|
|
|
|
return await render_template("traefik/index.html", router_data=router_data)
|