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