response_time_ms for successful requests, or no_data
with a reason code when the request fails (timeout, connection
refused, body mismatch, unexpected status).
Configuration shape
Field reference
Reason codes
The full catalog, with the hint the console shows for each code, is in Reason codes. Thereason field on no_data results is a stable code. The agent
normalises network errors from its runtime into one set, shared with
the TCP, DNS, TLS certificate and Prometheus sources:
ETIMEDOUT: request exceededtimeout_ms.ECONNREFUSED: the host resolved but refused the connection (port closed, service down, or a firewall rejecting it).ENOTFOUND,EAI_AGAIN: DNS resolution failed.ECONNRESET: the target closed the connection before answering.EHOSTUNREACH: no network route from the agent to the target.connect_failed: the connection could not be opened for another reason.CERT_HAS_EXPIRED,DEPTH_ZERO_SELF_SIGNED_CERT,ERR_TLS_CERT_ALTNAME_INVALIDand the other certificate codes, ortls_handshake_failed: the TLS handshake failed.ConnectionRefused: reported by older agents for both a refused port and a hostname that does not resolve. The console shows it as Could not connect. Current agents reportECONNREFUSEDorENOTFOUNDinstead.invalid_url:urlcould not be parsed.invalid_url_scheme:urluses a scheme other thanhttporhttps.http_error: the request failed without a more specific error code.unexpected_status:<code>: status code not inexpected_status.body_mismatch:body_matchwas set and the response body did not contain it.header_ref_missing: an env var named inheader_refsis not set (or is blank) on the agent host. The request is not sent.header_ref_invalid: an env var named inheader_refsholds a line break or control character, which is not allowed in a header.
Body match limitOnly the first 4KB of the response body is read. If the marker
string is later in the response, the probe reports
body_mismatch. Move the marker earlier in the response, or use
a dedicated health endpoint that returns it in the first kilobyte.Threshold examples
For pure reachability with no latency requirement, set the
unhealthy threshold equal to the timeout and rely on
no_data
for failures.
JSON path extraction
Setjson_path when the value worth thresholding lives inside the
response body, not in the response time. The agent fetches the URL,
parses the body as JSON, applies the JSONPath expression, and uses
the extracted value as the probe value.
pending_count is 42 in the response, the probe value is 42.
Threshold on it like any other numeric probe.
When to use it
- A custom health endpoint that returns a payload like
{"status": "ok", "queue_depth": 42}and you want to alert on queue depth, not just status code. - A third-party JSON API where the field you care about is buried in the response.
- An internal metric endpoint that returns several numbers; pick one per probe.
When not to use it
- The endpoint exposes Prometheus exposition format. Use the
prometheussource type instead, which understands the format natively and handles labels. - The value lives across multiple fields and needs computation (sum, ratio, percentile). Compute it at the source and expose a single field, or move to a Prometheus-style metric.
- The response is large (multi-MB). The agent caps the body at
10 MB and reports
json_body_too_large. Add a dedicated probe endpoint instead.
Path syntax
The agent evaluates paths with thejsonpath-plus dialect of JSONPath. Common patterns:
Value rules
The expression must resolve to exactly one value. The agent coerces:- Numbers are used directly.
- Booleans:
truebecomes1,falsebecomes0. - Strings that parse as finite numbers (e.g.
"42","3.14") become the parsed number. Surrounding whitespace is ignored. - Anything else reports
no_datawith a specific reason code (see below).
Reason codes specific to JSON path
json_parse_failed: response body was not valid JSON.json_path_invalid: thejson_pathexpression could not be evaluated. Check its syntax.json_path_no_match: the path matched nothing in the response.json_path_multi_match: the path matched more than one value. Tighten the expression.json_path_non_numeric: the matched value was a string that could not be parsed as a number, or another non-numeric scalar.json_path_unsupported_type: the matched value was an array, object, ornull. The path must point at a leaf value.json_body_too_large: the response exceeded 10 MB. The agent caps body reads to protect memory.
Body match still applies
body_match and json_path work together. If both are set, the
body must contain the substring AND the JSONPath must extract a
numeric value. Use body_match as a coarse sanity check (e.g.
the response includes the word ok) and json_path for the
actual probe value.Troubleshooting
- The probe always returns
json_parse_failed. Check the endpoint’sContent-Type. The agent does not requireapplication/json, but the body must be parseable as JSON. If the response istext/plainwith JSON inside it, the parse still works; if the response is HTML or XML, it does not. - The probe returns
json_path_multi_matchfor a single element. A path like$.items[*]matches every element. Use an index ($.items[0]) or a filter ($.items[?(@.name=='checkout')].count) to pick exactly one. - The probe returns
json_path_non_numericon a value that looks numeric. The matched string may contain units or separators ("42ms","1,024"). Test the path manually withjqorjsonpath-plusagainst the literal response body.
Secret headers
Useheader_refs for any header that carries a credential: bearer
tokens, API keys, session cookies. Each entry maps a header name to the
name of an environment variable on the agent host. The agent reads
the value at probe time and sends it with the request. Observer stores
only the variable name, never the token.
-e, a Compose
environment: block, or a Kubernetes secret mapped to env) and restart
the agent:
Bearer yourself.
Rules:
- Header names must be valid HTTP header names. Variable names must be
UPPER_SNAKE_CASE. Up to 32 entries. - A header can be in
headersorheader_refs, not both. - Secret headers are merged over
headersand follow the same redirect rule: they are sent on same-origin redirects and dropped when a redirect leaves the original origin. - If a variable is unset or blank the probe reports
no_datawithheader_ref_missingand does not send the request. The result names the header and the variable, never the value. - The agent never logs secret header values or includes them in results.
json_path runs the check on the metric’s
agent, with its secret headers, when that agent is online and runs
1.7.0 or later. Otherwise it runs from Observer’s servers, which cannot
read agent env vars, so secret headers are not sent.
Agent version
header_refs requires agent 1.6.0 or later. Agents at 1.5.0 or
older do not recognise the field and report invalid_config for any
probe that uses it. Upgrade the agent before adding secret headers.mTLS authentication
Set the three*_ref fields to monitor an HTTPS endpoint that requires
a client certificate (service meshes, zero-trust networks, internal
APIs with cert-based auth).
When not to use mTLS
mTLS is only for endpoints that demand a client certificate. For ordinary HTTPS, including endpoints with a self-signed or private-CA server cert, leave the*_ref fields blank:
- Standard public HTTPS: nothing to configure;
verify_tlsdefaults on. - Self-signed server cert you don’t want to verify: set
verify_tlstofalse(don’t reach for mTLS). - Private-CA server cert you do want to verify, but no client cert is required: that’s a server-trust concern, not mTLS. Point the agent’s system trust store at your CA, or use a probe without verification.
How certificates are stored
The cloud never sees your certificate or private key. Each*_ref
field holds the name of an environment variable on the agent host.
The agent reads the PEM material from that variable at probe time. The
value can be either:
- the PEM text directly (handy for Docker
-e/ Compose env), or - a filesystem path to a PEM file (handy for Kubernetes secret mounts).
- Client certificate env var:
OBSERVER_MTLS_CLIENT_CERT - Client private key env var:
OBSERVER_MTLS_CLIENT_KEY - CA certificate env var (optional):
OBSERVER_MTLS_CA_CERT
Generating a client certificate
Your service operator issues client certs from the mesh / internal CA. For a quick local test against an mTLS server:mtls_weak_key. EC keys (openssl ecparam -genkey) are also
accepted, with no bit-floor caveat. If the server rejects the cert
with mtls_client_cert_rejected, the most common cause is a missing
clientAuth extended-key-usage.
Certificate expiry
The agent parses the client cert on every probe. While the cert is still valid, the probe succeeds and nothing about its expiry is reported to Observer, so track the expiry date yourself (for exampleopenssl x509 -enddate -noout -in client.crt on the agent host). Once
the cert is actually expired, the probe
returns no_data with reason mtls_cert_expired.
mTLS reason codes
Troubleshooting
mtls_client_cert_rejectedbut the cert looks valid. The server decides which CAs to trust for client auth. Confirm your client cert chains to a CA in the server’s client-CA list, and that the cert isn’t revoked.mtls_server_verify_failedagainst an internal server. The server presents a cert signed by a private CA the agent’s system trust store doesn’t know. Setca_cert_refto a CA bundle env var.mtls_ref_missingafter setting the variable. The agent readsprocess.envat probe time. Set the variable on the agent process / pod, not just your shell, and restart the agent.

