98 lines
3.4 KiB
Python
98 lines
3.4 KiB
Python
# plugins/traefik/scheduler.py
|
|
from __future__ import annotations
|
|
import logging
|
|
import time
|
|
from typing import TYPE_CHECKING
|
|
|
|
from fablednetmon.core.scheduler import ScheduledTask
|
|
|
|
if TYPE_CHECKING:
|
|
from quart import Quart
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
# Module-level state: previous scrape data for delta computation
|
|
_prev_metrics: dict = {}
|
|
_prev_time: float = 0.0
|
|
|
|
|
|
def make_scrape_task(app: "Quart") -> ScheduledTask:
|
|
"""Return a ScheduledTask that scrapes Traefik metrics on the configured interval."""
|
|
interval = app.config["PLUGINS"]["traefik"]["scrape_interval_seconds"]
|
|
|
|
async def scrape() -> None:
|
|
await _do_scrape(app)
|
|
|
|
return ScheduledTask(
|
|
name="traefik_scrape",
|
|
coro_factory=scrape,
|
|
interval_seconds=int(interval),
|
|
run_on_startup=True,
|
|
)
|
|
|
|
|
|
async def _do_scrape(app: "Quart") -> None:
|
|
"""Fetch Traefik metrics, write to DB, and emit plugin_metrics."""
|
|
global _prev_metrics, _prev_time
|
|
|
|
from datetime import datetime, timezone
|
|
from .models import TraefikMetric
|
|
from .scraper import fetch_metrics, compute_router_metrics
|
|
from fablednetmon.core.alerts import record_metric
|
|
|
|
metrics_url: str = app.config["PLUGINS"]["traefik"]["metrics_url"]
|
|
|
|
try:
|
|
current = await fetch_metrics(metrics_url)
|
|
except Exception:
|
|
logger.exception("Traefik scrape failed (url=%s)", metrics_url)
|
|
return
|
|
|
|
now = time.monotonic()
|
|
elapsed = now - _prev_time if _prev_time else 60.0
|
|
router_metrics = compute_router_metrics(current, _prev_metrics or None, elapsed)
|
|
|
|
_prev_metrics = current
|
|
_prev_time = now
|
|
|
|
if not router_metrics:
|
|
logger.debug("Traefik scrape: no router metrics found")
|
|
return
|
|
|
|
scraped_at = datetime.now(timezone.utc)
|
|
|
|
async with app.db_sessionmaker() as session:
|
|
async with session.begin():
|
|
for router_name, metrics in router_metrics.items():
|
|
# Write to traefik_metrics history table
|
|
row = TraefikMetric(
|
|
router_name=router_name,
|
|
scraped_at=scraped_at,
|
|
request_rate=metrics["request_rate"],
|
|
error_rate_4xx_pct=metrics["error_rate_4xx_pct"],
|
|
error_rate_5xx_pct=metrics["error_rate_5xx_pct"],
|
|
latency_p50_ms=metrics["latency_p50_ms"],
|
|
latency_p95_ms=metrics["latency_p95_ms"],
|
|
latency_p99_ms=metrics["latency_p99_ms"],
|
|
)
|
|
session.add(row)
|
|
|
|
# Emit plugin_metrics for alert rules
|
|
for metric_name, value in [
|
|
("request_rate", metrics["request_rate"]),
|
|
("error_rate_4xx_pct", metrics["error_rate_4xx_pct"]),
|
|
("error_rate_5xx_pct", metrics["error_rate_5xx_pct"]),
|
|
("latency_p50_ms", metrics["latency_p50_ms"]),
|
|
("latency_p95_ms", metrics["latency_p95_ms"]),
|
|
("latency_p99_ms", metrics["latency_p99_ms"]),
|
|
]:
|
|
await record_metric(
|
|
session=session,
|
|
source_module="traefik",
|
|
resource_name=router_name,
|
|
metric_name=metric_name,
|
|
value=value,
|
|
)
|
|
|
|
logger.debug("Traefik scrape: wrote metrics for %d router(s)", len(router_metrics))
|