{# traefik/rows.html — HTMX fragment for the Traefik page: the verdict (swapped into #traefik-verdict above the request chart, #5710), routers that need attention (routes.router_state), their metric anomalies, the proxy's own figures, the healthy routers folded into one table (one over a cutoff but within its normal says so, #5741), then certificates by soonest expiry. #} {% from "_macros.html" import stat_tile, status_badge %} {# ── Verdict: what needs a look and since when, then the counts ─────────── #} {% set shown = 3 %}
{%- if problems %}{{ problems|length }} router{{ "s" if problems|length != 1 }} need{{ "s" if problems|length == 1 }} a look {%- for r in problems[:shown] %}{{ ":" if loop.first else ";" }} {{ r.name }}, {{ r.why }} {%- if r.since_before %}, all of the last {{ current_range }}{% elif r.since %}, started {{ r.since|ago }}{% endif %} {%- endfor %} {%- if problems|length > shown %}; {{ problems|length - shown }} more below{% endif %}. {%- if healthy %} {{ healthy|length }} healthy.{% endif %} {%- elif healthy %}All {{ healthy|length }} router{{ "s" if healthy|length != 1 }} healthy {%- else %}No routers reported yet. {%- endif %} {%- if gone %} {{ gone|length }} no longer reported.{% endif %}
{# ── The proxy's own figures: shown even before any router reports ───────── #} {% macro proxy_figures() %} {% if global_stat and (global_stat.config_last_reload_at or global_stat.open_conns_total is not none or global_stat.process_memory_bytes is not none) %}{{ r.why }} {%- if r.since_before %}, all of the last {{ current_range }}{% elif r.since %}, started {{ r.since|ago }}{% endif %}
{% if r.codes %}Last 15 min: {% for code, n in r.codes[:5] %}{{ code }} ×{{ "{:,}".format(n) }}{{ ", " if not loop.last }}{% endfor %} {%- if r.codes|length > 5 %}, {{ r.codes|length - 5 }} more code{{ "s" if r.codes|length - 5 != 1 }}{% endif %}
{% elif codes_known %}No 4xx or 5xx responses in the last 15 min.
{% else %}Status codes not recorded yet: Steward keeps them from this version on.
{% endif %}| Req/s | {{ "%.2f"|format(r.latest.request_rate) }} | {{ r.sparkline_req|safe }} |
| Bandwidth | {{ r.latest.response_bytes_rate|rate }} | {{ r.sparkline_bytes|safe }} |
| p95 | {{ latency_cell(r.latest.latency_p95_ms) }}{{ r.sparkline_p95|safe }} | |
| p99 | {{ ms(r.latest.latency_p99_ms) }} | |
| 4xx | {{ "%.1f"|format(r.latest.error_rate_4xx_pct) }}% | {{ r.sparkline_4xx|safe }} |
| 5xx | {{ "%.1f"|format(r.latest.error_rate_5xx_pct) }}% | {{ r.sparkline_5xx|safe }} |
| Router | Req/s | Bandwidth | p95 | 4xx | 5xx |
|---|---|---|---|---|---|
| {{ r.name }}{% if r.why %} {{ r.why }} {% endif %} |
{{ "%.2f"|format(r.latest.request_rate) }} | {{ r.latest.response_bytes_rate|rate }} | {{ latency_cell(r.latest.latency_p95_ms) }}{{ "%.1f"|format(r.latest.error_rate_4xx_pct) }}% | {{ "%.1f"|format(r.latest.error_rate_5xx_pct) }}% |
Traefik stopped reporting these, usually because the service behind them was removed.
| Name | Routers | Expires | Left |
|---|---|---|---|
| {{ cert.cn }}{% if cert.sans %} also {{ cert.sans|join(", ") }} {% endif %} |
{% if cert.routers is none %}—{% elif cert.routers %}{{ cert.routers|join(", ") }}{% else %}not in use{% endif %} | {{ cert.not_after.strftime("%Y-%m-%d") }} | {{ cert_left(cert.days_remaining) }} |
| Name | Expires |
|---|---|
| {{ cert.cn }} | {{ cert.not_after.strftime("%Y-%m-%d") }} |
No Traefik metrics yet. Configure metrics_url in config.yaml under plugins.traefik.