Prometheus Monitor
Monitor any metric with a PromQL instant query and threshold-based status
Prometheus monitors run a PromQL instant query against a Prometheus server's /api/v1/query endpoint, derive status from optional threshold conditions on the returned value, and record the metric value itself as the per-check measurement.
This replaces pointing an API monitor at Prometheus and hand-writing an eval function.
Minimum setup
Set:
url— the Prometheus base URL (e.g.https://prometheus.example.com; base paths likehttps://host/promwork)query— a PromQL instant query that returns a scalar or an instant vector
With no thresholds configured, the monitor is UP whenever the query succeeds and returns data, and follows noDataStatus when it returns nothing.
Status logic
For each check the metric value is evaluated in this order:
- Transport, HTTP, or query error →
errorStatus(default DOWN) - Empty result or
NaNvalue →noDataStatus(default DOWN) downcondition matches → DOWNdegradedcondition matches → DEGRADED- Otherwise → UP
A condition matches when value <operator> threshold is true, with the metric value as the left operand. For example a down condition of > 0.95 reads "down when the value is greater than 0.95". down is checked before degraded, so overlapping conditions resolve to DOWN.
noDataStatus and errorStatus cover different failures and are set independently. noDataStatus
applies when the query succeeded and matched nothing (an empty instant vector, or a NaN
sample) — the scrape worked and the answer was "no series". errorStatus applies when there is no
usable answer at all: a connection failure, a timeout, a non-2xx response, a body that is not a
Prometheus success envelope, or a result whose type or shape cannot be read. Whatever errorStatus
is set to, the check still records the real type (ERROR / TIMEOUT) and its error message, so
softening the status never hides the cause.
Recorded measurement
The charted per-check number is always the metric value, not the HTTP round-trip time. Non-finite values (NaN, ±Inf) and empty results are charted as 0; status still follows the rules above.
Configuration fields
| Field | Type | Default | Notes |
|---|---|---|---|
url |
string |
— | Required. Prometheus base URL; base paths like /prom work |
query |
string |
— | Required. PromQL instant query |
down |
object |
— | Optional { operator, value }; matches → DOWN |
degraded |
object |
— | Optional { operator, value }; matches → DEGRADED |
noDataStatus |
string |
"DOWN" |
Empty-result status: UP / DEGRADED / DOWN |
errorStatus |
string |
"DOWN" |
Unreachable/unusable-response status: UP / DEGRADED / DOWN |
headers |
array |
[] |
Key/value pairs; $SECRET env substitution applies |
timeout |
number |
10000 |
Request timeout in ms |
allowSelfSignedCert |
boolean |
false |
Skip TLS certificate verification |
proxy |
string |
— | Optional forward proxy, e.g. http://user:$PROXY_PASS@proxy.internal:3128; overrides the environment proxy |
operator is one of >, >=, <, <=, ==, !=.
Example
{
"type": "PROMETHEUS",
"type_data": {
"url": "https://prometheus.example.com",
"query": "avg(rate(http_requests_total{job=\"api\"}[5m]))",
"degraded": { "operator": "<", "value": 100 },
"down": { "operator": "<", "value": 10 },
"noDataStatus": "DOWN",
"errorStatus": "DOWN",
"timeout": 10000
}
}
Notes and caveats
- Aggregate multi-series queries in PromQL. If a query returns more than one series, only the first is used. Wrap the query in
max(...),sum(...),avg(...), etc. so a single series is returned deterministically. - Metric magnitude and precision. The charted value is stored in Kener's shared
latencycolumn, defined asfloat(8, 2). On MySQL this caps values at ±999999.99 and rounds to 2 decimal places; on PostgreSQL it keeps roughly 7 significant digits; SQLite (the default) stores full precision. Status and alerting are unaffected — they're derived from the full-precision value before storage — but for large-magnitude metrics (byte counts,_totalcounters) or values below0.01on MySQL/PostgreSQL, scale the query in PromQL (e.g.... / 1e6or... * 100) so the charted number stays in range. - Float-equality caveat. Prometheus sample values are floating point. Avoid
==/!=against computed values (rates, averages) — floating-point rounding makes exact matches unreliable. Prefer range operators (<,>,<=,>=); reserve==/!=for integer-valued gauges. - Absent-but-healthy metrics. For metrics that legitimately disappear (e.g. a counter that only exists while a job runs), append
or vector(0)to the query so it always returns a value, instead of relying onnoDataStatus. - Authentication. Add an
Authorizationheader underheaders; use$SECRET_NAMEto substitute an environment variable. Secret substitution applies to the URL and header values only — never to the query.
Troubleshooting
- Immediate DOWN with an error message: use "Test Monitor" — a bad PromQL query surfaces the Prometheus
errorfield; an unreachable server surfaces the network error. - Always no-data: the query matched no series. Verify the query in Prometheus's own UI, or append
or vector(0). - "query must return an instant vector or scalar": the query produced a range/matrix result. Use an instant query (no
[range]in the outermost expression), or aggregate. Failed to establish tunnel: the proxy refused the connection; see proxy settings