# monitor.http-check-result
Turns what one HTTP probe came back with into a `CheckOutcome`: a
`CheckStatus` (`up`, `degraded`, `down`, from `monitor.check-status`), a
machine-readable `reason`, and a short English `message` for the alert. Store
`{ at, status }` as a `Check` and the rest of `monitor.*` (uptime,
incidents, status pages) works from it.
The prober itself (making the request, timing it) is the caller's I/O; this
is the pure decision afterwards, so every language classifies a probe the
same way.
## Order of checks
The first thing wrong is the reason, in this order, so the alert names what
someone has to fix rather than a symptom of it:
1. `error` set (a transport failure): **down**, reason = the error kind.
An error wins even when a status code also arrived (a protocol error
after the headers).
2. Status code not accepted: **down**, `unexpected-status`. With
`statuses` null any 2xx is accepted, the Prometheus blackbox_exporter
default for `valid_status_codes`; a redirect (3xx) is therefore down
unless listed, since a health endpoint that redirects is usually a
misconfiguration. An explicit list replaces 2xx entirely (`[404]` for a
page that should stay gone).
3. `bodyContains` not found: **down**, `body-mismatch`. Case-sensitive
substring; a null body never contains anything. (blackbox_exporter's
`fail_if_body_not_matches_regexp` is the regex version; this is a plain
substring so all three languages agree exactly.)
4. `latencyMs >= downLatencyMs`: **down**, `too-slow`.
5. `latencyMs >= degradedLatencyMs`: **degraded**, `slow`.
6. Otherwise **up**, `ok`.
Latency thresholds are "at or above" and apply only when `latencyMs` is
non-null; either threshold may be null to skip that stage, and equal
thresholds skip degraded.
## Messages
Fixed English, identical in every language:
| reason | message |
| --- | --- |
| `ok` | `HTTP 200 in 123 ms`, or `HTTP 200` when latency is null |
| `unexpected-status` | `HTTP 503, expected 2xx`; `HTTP 404, expected 200 or 204`; `expected 200, 201 or 204` |
| `body-mismatch` | `body does not contain "ok"` |
| `slow`, `too-slow` | `latency 1500 ms at or above 1000 ms` (the threshold crossed) |
| `timeout` | `timed out` |
| `dns` | `DNS lookup failed` |
| `connection` | `connection failed` |
| `tls` | `TLS handshake failed` |
| `protocol` | `protocol error` |
## Errors
- `probe must have a statusCode or an error`
- `statusCode must be 100 to 599, received X`
- `latencyMs must be a whole number 0 or more, received X`
- `unknown probe error: X`
- `statuses must not be empty; use null to accept any 2xx` (an empty list
would accept nothing and mark every probe down)
- `expected statuses must be 100 to 599, received X`
- `degradedLatencyMs must be a whole number 1 or more, received X` (and the
same for `downLatencyMs`)
- `downLatencyMs must not be below degradedLatencyMs: D < G`
## Sources
- Prometheus blackbox_exporter configuration, `http_probe`:
`valid_status_codes` "Defaults to 2xx", and
`fail_if_body_not_matches_regexp`:
https://github.com/prometheus/blackbox_exporter/blob/master/CONFIGURATION.md