Functional Weave
Code in TypeScript

monitor.http-check-result@1.0.0

README.md

3,140 bytes · view raw

# 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