feat(norms): hosts, containers and monitor response times are graded against their own normal (#5742)
Host CPU, memory and load per core, container CPU and memory, and every monitor's response time learn a normal per hour (milestone 513, System 182). A reading past its fixed cutoff but within its normal reads healthy and says what is usual at this hour; one well out of it keeps its grade and is a metric anomaly. Disk, a monitor down and an agent offline keep their cutoffs. - Each normal's floor, the smallest departure that counts, is a setting: Settings -> Thresholds -> Normals (norms.floor.*). Defaults: host CPU 10 points, host memory 5, load per core 10, container CPU 10 points of one core, container memory 5, monitor response 100 ms; Traefik's 2-point 4xx and 50 ms p95 floors move there from constants. learn_normal takes a floor function (floor_setting) read at each pass. - learn_normal(parts=False): a host learns, its cores don't. - Ingest records load_pct (load_1m / cores x 100), the figure pages grade. - Shared grading: anomalies.against / graded, worst_reading(normals=), hosts' host_grades, docker usage(thresholds=, norms=), monitors' latency_grade. Applied to host vitals, the Hosts widget, MCP overview, Docker usage, and the monitor list, widget and page. - The monitor and container pages list their anomalies. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,7 +1,8 @@
|
||||
{% extends "base.html" %}
|
||||
{% from "_macros.html" import crumbs, page_header, stat_tile %}
|
||||
{# One monitor: its state and for how long, latency and uptime against
|
||||
Settings → Thresholds, its response time over the last day, its last
|
||||
Settings → Thresholds (latency against its own normal once it has one,
|
||||
with its anomalies), its response time over the last day, its last
|
||||
checks, the failures behind them and how it is set up. #}
|
||||
{% block title %}{{ monitor.name }} — Monitors — Steward{% endblock %}
|
||||
{% block breadcrumb %}{{ crumbs([("Monitors", "/monitors/"), (monitor.name, "")]) }}{% endblock %}
|
||||
@@ -23,7 +24,7 @@
|
||||
{% set since_hint = ((("for at least " if since_at_least else "for ") ~ (since|ago|striptags|replace(" ago", ""))) if since and state in ("up", "down", "degraded") else none) %}
|
||||
{{ stat_tile("State", status_info(state)[1], state=state, hint=since_hint) }}
|
||||
{% if latest and latest.response_ms is not none %}
|
||||
{{ stat_tile("Latency", "%.0f ms"|format(latest.response_ms), state=status_class(latest.response_ms, "latency")) }}
|
||||
{{ stat_tile("Latency", "%.0f ms"|format(latest.response_ms), state=latency[0], hint=latency[1]) }}
|
||||
{% endif %}
|
||||
{% for window in ("24h", "7d", "30d") %}
|
||||
{% set pct = uptime.get(window) %}
|
||||
@@ -34,6 +35,8 @@
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
{% with back="/monitors/" ~ monitor.id, base_resource=monitor.name %}{% include "_anomaly_card.html" %}{% endwith %}
|
||||
|
||||
{% set timed = history | selectattr("ms", "ne", none) | list %}
|
||||
{% if timed|length > 1 %}
|
||||
<section class="card" aria-labelledby="m-chart">
|
||||
|
||||
Reference in New Issue
Block a user