{# Current-state fragment for the full-metrics page — polled live via HTMX. Each poll re-renders the latest snapshot the server has. #} {% from "_macros.html" import status_badge %} {# A percentage bar graded by Settings → Thresholds for `kind` (cpu, mem, disk). #} {% macro bar(pct, kind) %}
{% endmacro %} {% macro gauge(value, kind, text) %}{{ text }}{% endmacro %} {# ── Identity / metadata ─────────────────────────────────────────────────── #}
{{ status_badge('stale' if stale else 'up', 'Stale' if stale else 'Live') }} Address {{ host.address or "—" }} {% if reg %} {% if reg.distro %}OS {{ reg.distro }}{% endif %} {% if reg.kernel %}Kernel {{ reg.kernel }}{% endif %} {% if reg.arch %}Arch {{ reg.arch }}{% endif %} {% if reg.agent_version %}Agent v{{ reg.agent_version }}{% endif %} {% set up = hostlvl.get('uptime_secs') %} {% if up %}Uptime {{ up|duration }}{% endif %} Last seen {{ reg.last_seen_at|ago if reg.last_seen_at else "never" }} {% else %} No agent registration found for this host. {% endif %}
{% if not hostlvl %}
No metrics reported yet. Once the agent checks in, CPU, memory, network, disk I/O, temperatures, and pressure will appear here.
{% else %} {# ── Current headline gauges ─────────────────────────────────────────────── #}
CPU
{% set c = hostlvl.get('cpu_pct') %} {{ gauge(c, 'cpu', ("%.0f%%"|format(c)) if c is not none else "—") }}
{{ bar(c, 'cpu') }}
Memory
{% set mp = hostlvl.get('mem_used_pct') %} {{ gauge(mp, 'mem', ("%.0f%%"|format(mp)) if mp is not none else "—") }}
{{ bar(mp, 'mem') }}
avail {{ hostlvl.get('mem_available_bytes')|bytes }} · cache {{ hostlvl.get('mem_cached_bytes')|bytes }} · swap {{ hostlvl.get('swap_used_bytes')|bytes }}
Load
{% if hostlvl.get('load_1m') is not none %}{{ "%.2f"|format(hostlvl.get('load_1m')) }}{% else %}—{% endif %}
5m {% if hostlvl.get('load_5m') is not none %}{{ "%.2f"|format(hostlvl.get('load_5m')) }}{% else %}—{% endif %} · 15m {% if hostlvl.get('load_15m') is not none %}{{ "%.2f"|format(hostlvl.get('load_15m')) }}{% else %}—{% endif %}
Network
↓ {{ hostlvl.get('net_rx_bps')|rate }}
↑ {{ hostlvl.get('net_tx_bps')|rate }}
Disk I/O
rd {{ hostlvl.get('disk_read_bps')|rate }}
wr {{ hostlvl.get('disk_write_bps')|rate }}
{% if hostlvl.get('temp_c_max') is not none %}
Temp (max)
{% set t = hostlvl.get('temp_c_max') %} {{ gauge(t, 'temp', "%.0f°C"|format(t)) }}
{% endif %} {% if hostlvl.get('psi_mem_some_avg10') is not none %}
Pressure (10s)
mem {{ "%.1f"|format(hostlvl.get('psi_mem_some_avg10')) }}%
{% if hostlvl.get('psi_cpu_some_avg10') is not none %}
cpu {{ "%.1f"|format(hostlvl.get('psi_cpu_some_avg10')) }}%
{% endif %} {% if hostlvl.get('psi_io_some_avg10') is not none %}
io {{ "%.1f"|format(hostlvl.get('psi_io_some_avg10')) }}%
{% endif %}
{% endif %}
{# ── Per-core CPU ─────────────────────────────────────────────────────────── #} {% if cores %}
Per-core CPU
{% for idx, pct in cores %}
core {{ idx }}{% if pct is not none %}{{ "%.0f"|format(pct) }}%{% else %}—{% endif %}
{{ bar(pct, 'cpu') }}
{% endfor %}
{% endif %} {# ── Filesystems ──────────────────────────────────────────────────────────── #} {% if mounts %}
Filesystems
{% for mount, m in mounts.items() %}
{{ mount }} {{ m.get('disk_used_bytes')|bytes }} / {{ m.get('disk_total_bytes')|bytes }}{% if m.get('disk_used_pct') is not none %} · {{ "%.0f"|format(m.get('disk_used_pct')) }}%{% endif %}
{{ bar(m.get('disk_used_pct'), 'disk') }} {% if m.get('nfs_ops_per_sec') is not none %} {# NFS delay (#5996): what a request took since the agent's last sample. #} {% set exe = m.get('nfs_exe_ms') %}
NFS {% if m.get('nfs_ops_per_sec') > 0 and exe is not none -%} {{ "%.1f"|format(exe) }} ms a request · {{ "%.3g"|format(m.get('nfs_ops_per_sec')) }}/s {%- else %}idle{% endif %} {%- if m.get('nfs_retrans') %} · {{ m.get('nfs_retrans')|int }} sent again{% endif %} {%- if m.get('nfs_timeouts') %} · {{ m.get('nfs_timeouts')|int }} timed out{% endif %}
{% endif %}
{% endfor %}
{% endif %} {# ── Drive health (#5789): each drive as the root helper read it with smartctl, hourly; what needs attention first (drives.py judges them). ──── #} {% set drive_badge = {"failing": ("crit", "Failing"), "unreadable": ("warn", "Unreadable"), "worn": ("warn", "Worn"), "watch": ("warn", "Watch"), "ok": ("ok", "OK"), "unavailable": ("inactive", "No SMART")} %} {% if drives or drives_error %}
Drive health {% if drives_at %}read {{ drives_at|ago }}{% endif %}
{% if drives_error %}

Not read: {{ drives_error }}.

{% endif %} {% for d in drives %} {% set tone, label = drive_badge[d.state] %}
{{ status_badge(tone, label) }} {{ d.device }} {% if d.model %}{{ d.model }}{% if d.capacity_bytes %} · {{ d.capacity_bytes|bytes }}{% endif %}{% endif %} {% if d.why %} — {{ d.why }}{% endif %} {%- set parts = [] -%} {%- if d.get("life_used_pct") is not none %}{% set _ = parts.append("%d%% life used"|format(d.life_used_pct)) %}{% endif -%} {%- if d.get("bad_sectors") is not none %}{% set _ = parts.append("%d bad sectors"|format(d.bad_sectors)) %}{% endif -%} {%- if d.get("temp_c") is not none %}{% set _ = parts.append("%d°C"|format(d.temp_c)) %}{% endif -%} {{ parts|join(" · ") if parts else "—" }}
{% endfor %}
{% endif %} {# ── Interfaces / disks (short panels, side by side at natural height) ─────── #} {% if nets or disks_io %}
{% if nets %}
Interfaces
{% for iface, m in nets.items() %}
{{ iface }} ↓ {{ m.get('net_rx_bps')|rate }} · ↑ {{ m.get('net_tx_bps')|rate }}
{% endfor %}
{% endif %} {% if disks_io %}
Disks
{% for dev, m in disks_io.items() %}
{{ dev }} rd {{ m.get('disk_read_bps')|rate }} · wr {{ m.get('disk_write_bps')|rate }}
{% endfor %}
{% endif %}
{% endif %} {# ── Temperatures (full width; cores flow into a compact multi-column grid) ── #} {% if temps %}
Temperatures
{% for label, c in temps.items() %}
{{ label }} {% if c is not none %}{{ "%.0f"|format(c) }}°C{% else %}—{% endif %}
{% endfor %}
{% if unwired_temps %} {# Sensors that aren't thermometers: they run against the CPU or hold a constant (#5783), or read a value no wired sensor gives (#5759). Left out of the host's temperature. Each reason is said once, after its sensors, hottest first within it. #}

Not counted, likely nothing wired to them: {% for why, group in unwired_temps.items()|groupby("1.1") %}{% for label, v in group %}{{ label }} {{ "%.0f"|format(v[0]) }}°C{{ ", " if not loop.last }}{% endfor %} ({{ why }}){{ "; " if not loop.last }}{% endfor %}.

{% endif %}
{% endif %} {% endif %}