feat(health): Steward records its own health and Settings → System shows it (#5467)
#5467 "Steward's own health: metrics, rules can watch them, a page that shows them". The self-monitor tick now records, under source "steward", resource "process": ingest_posts / ingest_failed / ingest_slowest_ms (the host-agent posts since the last tick, tallied in steward/core/health.py), db_roundtrip_ms (a timed SELECT 1), and unwatched_secs (the gap before this tick past watch.GAP_S, from Steward's own last sample). The hourly cleanup records cleanup_secs. The open-file pair is still recorded, and is now only skipped on its own where /proc is absent. All of these are in CORE_METRICS, so an alert rule can watch them under "Steward itself". Settings → System (/settings/system/, admin) shows a verdict first (failed posts, a gap in watching, open files near the limit), then each measure now and over the last day, with a sparkline scaled to its own peak. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -623,6 +623,22 @@ async def _reports_page(settings: dict, flash):
|
||||
shown_day=shown_day, shown_hour=shown_hour, last_sent=last_sent)
|
||||
|
||||
|
||||
@settings_bp.get("/system/")
|
||||
@require_role(UserRole.admin)
|
||||
async def system():
|
||||
"""Steward's own health (#5467): its process metrics now and over the day,
|
||||
each one an alert rule can watch (source "Steward itself")."""
|
||||
from steward.core.health import process_health
|
||||
from steward.core.status import sparkline_svg
|
||||
async with current_app.db_sessionmaker() as db:
|
||||
health = await process_health(db)
|
||||
for row in health["rows"]:
|
||||
# From zero to the row's own peak, with a floor (UI & Design ruling 8).
|
||||
row["spark"] = sparkline_svg(row["series"], width=120, height=20,
|
||||
stroke="currentColor", floor=1.0) if len(row["series"]) > 1 else ""
|
||||
return await render_template("settings/system.html", **health)
|
||||
|
||||
|
||||
@settings_bp.get("/reports/")
|
||||
@require_role(UserRole.admin)
|
||||
async def reports():
|
||||
|
||||
Reference in New Issue
Block a user