feat(prometheus): fold state sets on the target page; forget series an endpoint drops (#5689)
CI / lint (push) Successful in 2s
CI / integration (push) Successful in 1m20s
CI / unit (push) Successful in 1m28s
CI / publish (push) Successful in 20s

#5689 "Prometheus target page: fold state sets, show epoch times, size
bytes", step 1 of milestone 508 "Prometheus widget templates".

- A state set (name ending in _state, a state label, every series 0 or 1;
  or the OpenMetrics form, the label named after the metric) reads as one
  row per thing it describes, naming the current state, the others on
  hover. fabledarchives_jobs{state} is a count and stays as it is.
- label_pairs / state_label / fold_states in service.py, for the widget
  templates to reuse.
- After a good scrape, series it no longer has lose their newest value
  (forget_gone): Archives' old build_info row read as current beside the
  new one. History stays; a failed scrape forgets nothing; alert rules keep
  their own last-sample time.
- Epoch times and _bytes sizes were already read by shown_value /
  metric_value.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-12 15:11:24 -04:00
co-authored by Claude Opus 5.5
parent 4c546a9c4d
commit ec3e5e7e0d
8 changed files with 176 additions and 21 deletions
@@ -1,7 +1,8 @@
{# plugins/prometheus/templates/prometheus/target.html — one scrape target
(milestone 506): what its newest scrape found, then every series it
stored, grouped by metric, each with its labels and newest value and a
link to its chart. #}
link to its chart. A state set reads as one row per thing it describes,
naming the current state (#5689). #}
{% extends "base.html" %}
{% from "_macros.html" import crumbs, page_header, status_badge, stat_tile %}
{% block title %}Prometheus — {{ target.name }} — Steward{% endblock %}
@@ -54,10 +55,12 @@
{% for g in groups %}
{% for r in g.rows %}
<tr>
{% if loop.first %}<td class="mono" rowspan="{{ g.rows|length }}" style="vertical-align:top;overflow-wrap:anywhere;">{{ g.metric }}</td>{% endif %}
{% if loop.first %}<td class="mono" rowspan="{{ g.rows|length }}" style="vertical-align:top;overflow-wrap:anywhere;">{{ g.metric }}
{%- if g.states %}<div class="cell-sub">a state set: the current state is shown</div>{% endif %}</td>{% endif %}
<td class="mono" style="overflow-wrap:anywhere;font-size:0.82rem;">{{ r.labels or "—" }}</td>
<td style="text-align:right;white-space:nowrap;">
<a href="/plugins/prometheus/targets/{{ target.id }}/series?resource={{ r.resource|urlencode }}&metric={{ g.metric|urlencode }}">{% if r.moment %}{{ r.moment|ago }}{% else %}{{ r.text }}{% endif %}</a>
<a href="/plugins/prometheus/targets/{{ target.id }}/series?resource={{ r.resource|urlencode }}&metric={{ g.metric|urlencode }}"
{%- if r.states %} title="One of: {{ r.states|join(', ') }}"{% endif %}>{% if r.moment %}{{ r.moment|ago }}{% else %}{{ r.text }}{% endif %}</a>
</td>
</tr>
{% endfor %}