feat(settings): Settings brought into line with the rest of Steward (milestone 493)
The last page of #5214's walk. Settings still described Steward as it was before monitors were unified and SNMP was rebuilt, drew its tabs below the breadcrumb, and showed the report schedule in UTC. - Tabs (#5377): settings/_tabs.html is a settings_tabs() macro called in each page's section_tabs block, above the trail, as Ansible's are. The breadcrumb guard also fails any page that {% include %}s a tab strip. - Report time (#5378): reports.schedule_tz keeps the zone of whoever saved the schedule; check_and_send compares in it (report_due), and the form shows the day and hour on the reader's clock (schedule_in) under their zone's name. "Last sent" uses |when. - Wording (#5379): the report contents list what the report holds (monitors, not ping-enabled hosts); "Ping latency" is "Response time" and says what it grades; plugin detail says enabling loads now and disabling needs a restart; the monitor interval says it applies on the next check (the scheduler reads it every pass); the dead list-config branch is gone. - Traefik (#5380): the 5xx and 4xx cutoffs are settings (traefik.threshold.error_5xx_pct 0.1, error_4xx_pct 1.0) in a "Traefik routers" group on Thresholds while the plugin runs, read by router_state through error_cutoffs(). The Traefik page has a Thresholds button for admins, to /settings/thresholds/#traefik. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
+17
-11
@@ -42,24 +42,29 @@ def _sparkline(values: list[float], width: int = 80, height: int = 20) -> str:
|
||||
)
|
||||
|
||||
|
||||
# A router serving any real share of 5xx is failing; a 4xx share above this
|
||||
# is worth a look (clients hitting missing routes, auth failures).
|
||||
ERROR_5XX_PCT = 0.1
|
||||
ERROR_4XX_PCT = 1.0
|
||||
_GRADE_ORDER = {"crit": 0, "warn": 1, "ok": 2}
|
||||
|
||||
|
||||
def error_cutoffs(thresholds: dict) -> tuple[float, float]:
|
||||
"""(5xx, 4xx): the error shares, in percent, past which a router is failing
|
||||
or worth a look. Settings → Thresholds, Traefik routers (#5380)."""
|
||||
return (float(thresholds.get("error_5xx", {}).get("crit", 0.1)),
|
||||
float(thresholds.get("error_4xx", {}).get("warn", 1.0)))
|
||||
|
||||
|
||||
def router_state(reading, thresholds: dict, over: str = "") -> tuple[str, str | None]:
|
||||
"""(grade, why) for a router's reading (recent_window's, or one scrape's):
|
||||
crit while it serves 5xx, warn on a p95 past the latency critical cutoff
|
||||
(Settings → Thresholds) or a high 4xx share, otherwise ok with nothing to
|
||||
say. `over` names the span the reading covers, for the why."""
|
||||
if (reading.error_rate_5xx_pct or 0) > ERROR_5XX_PCT:
|
||||
crit while it serves 5xx past its cutoff, warn on a p95 past the latency
|
||||
critical cutoff or a 4xx share past its cutoff (all Settings → Thresholds),
|
||||
otherwise ok with nothing to say. `over` names the span the reading
|
||||
covers, for the why."""
|
||||
error_5xx, error_4xx = error_cutoffs(thresholds)
|
||||
if (reading.error_rate_5xx_pct or 0) > error_5xx:
|
||||
return "crit", f"{reading.error_rate_5xx_pct:.1f}% of responses are 5xx{over}"
|
||||
p95 = reading.latency_p95_ms
|
||||
if p95 is not None and status_class(p95, "latency", thresholds) == "crit":
|
||||
return "warn", f"p95 latency is {p95:.0f} ms{over}"
|
||||
if (reading.error_rate_4xx_pct or 0) > ERROR_4XX_PCT:
|
||||
if (reading.error_rate_4xx_pct or 0) > error_4xx:
|
||||
return "warn", f"{reading.error_rate_4xx_pct:.1f}% of responses are 4xx{over}"
|
||||
return "ok", None
|
||||
|
||||
@@ -298,13 +303,14 @@ async def rows():
|
||||
old_certs = [cert_row(c) for c in old]
|
||||
problems, healthy = split_routers(current)
|
||||
phases.mark("cert_rows")
|
||||
error_5xx, error_4xx = error_cutoffs(thresholds)
|
||||
page = await render_template(
|
||||
"traefik/rows.html",
|
||||
problems=problems,
|
||||
healthy=healthy,
|
||||
gone=gone,
|
||||
error_4xx=ERROR_4XX_PCT,
|
||||
error_5xx=ERROR_5XX_PCT,
|
||||
error_4xx=error_4xx,
|
||||
error_5xx=error_5xx,
|
||||
global_stat=global_stat,
|
||||
certs=certs,
|
||||
old_certs=old_certs,
|
||||
|
||||
@@ -7,7 +7,12 @@
|
||||
<h1 class="page-title" style="margin-bottom:0;">Traefik Services</h1>
|
||||
<span style="color:var(--text-muted);font-size:0.85rem;">polling every {{ poll_interval }}s</span>
|
||||
</div>
|
||||
{% include "_time_range.html" %}
|
||||
<div style="display:flex;align-items:center;gap:0.75rem;flex-wrap:wrap;">
|
||||
{% if session.user_role == 'admin' %}
|
||||
<a href="/settings/thresholds/#traefik" class="btn btn-ghost btn-sm">Thresholds</a>
|
||||
{% endif %}
|
||||
{% include "_time_range.html" %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="traefik-rows"
|
||||
|
||||
Reference in New Issue
Block a user