Health and Monitoring¶
Platform Health¶
To monitor the health of the platform from an external service, you have the option to enable a healthcheck route on one or more Portals. This route allows you to display a global status of the platform. It is accessible via the URL:
https://your-portal-url/api/healthcheck
Example of the JSON response:
{
"status": "OK",
"internalServicesStatus": "OK",
"globalStatus": "WARNING",
"certificatesStatus": "OK",
"version": "2.15.0",
"globalVersion": "2.15.0",
"services": {
"api": {
"status": "OK",
"internalServicesStatus": "OK",
"version": "3.26.1",
"services": {
"db": { "status": "OK" },
"provision-api": { "status": "OK", "version": "3.10.4" },
"provision-relay-api": { "status": "OK", "version": "1.9.0" },
"container-providers": [
{ "status": "OK", "name": "Swarm cluster EU-West - SWARM", "type": "SWARM" }
],
"ws-relays": [
{ "status": "OK", "name": "Websocket relay EU-West - WS_SWARM", "type": "WS_SWARM" },
{ "status": "OK", "name": "Websocket relay EU-West - Traefik status", "type": "WS_SWARM" }
]
},
"relayDiagnostics": [
{
"name": "Websocket relay EU-West",
"type": "WS_SWARM",
"status": "ERROR",
"proxy": {
"reachable": true,
"url": "http://relay.example.com:8404/stats;json",
"backends": [
{
"name": "relay_swarm_back",
"status": "UP",
"active": 2,
"backup": 0,
"sessions": { "current": 2, "max": 4, "limit": 26209, "queue": 0 },
"errors": { "connection": 0, "response": 0, "retries": 0, "redispatches": 0 }
}
]
},
"cluster": { "reachable": true, "error": null, "members": 3 },
"nodes": [
{
"address": "10.0.0.13",
"hostname": "node2",
"state": "NGINX_DOWN",
"detail": "no answer on the node address",
"role": "manager",
"proxyExpected": true,
"cluster": { "member": true, "state": "down", "availability": "active", "reachability": "unreachable" },
"proxy": [
{ "backend": "relay_swarm_back", "port": 8375, "status": "DOWN", "check": "L4TOUT", "checkCode": null, "lastCheck": "", "failures": 3, "flaps": 2, "downtime": 154, "since": 154 }
],
"engine": { "ping": null, "version": null, "swarm": null, "manager": null, "clusterId": null }
}
]
}
],
"providerDiagnostics": [],
"ndbDiagnostics": null
},
"signals": [
{ "status": "OK", "url": "https://signal.example.com", "certificateExpiration": "2027-04-14 17:29:00", "error": null }
]
},
"license": { "expiration": "2028-01-01 01:00:00" }
}
The response above is abridged: each list holds one entry per object of that kind.
Reading the aggregates¶
The response opens with four aggregates. An external supervision usually watches the last two:
status — the API and its database only.
internalServicesStatus — every internal service except the database.
globalStatus — the platform as a whole: ERROR when the API, one of its internal services or every signal server is down, WARNING when only some signal servers, a provider or the database cluster are degraded.
certificatesStatus — the TLS certificates, against the instance’s warning and error thresholds.
The route always answers 200, including during a total outage: read the verdict in the body rather than the HTTP code.
Node diagnostics¶
relayDiagnostics and providerDiagnostics report each cluster machine by machine. Each entry names the cluster, its aggregated status (OK, WARNING, ERROR or UNAVAILABLE), the load balancer it was read from, and one object per node.
Fields available for each node:
Field |
Content |
|---|---|
|
|
|
One sentence naming what led to that state, or |
|
|
|
Whether the node’s role requires the load balancer to serve it. A node in a state other than |
|
One entry per load balancer backend serving this node, with the port and the state HAProxy gives it. |
|
What the node itself answered: engine version and swarm state for Swarm, api server liveness for Kubernetes. |
ndbDiagnostics carries the same kind of detail for a MySQL NDB Cluster: its verdict (ok, warn, crit, stale or unknown), the coded reasons behind it and the node groups. It is null on an instance with no cluster supervision enabled.
Note
These three fields hold host names and addresses of the infrastructure. They are part of the response on the anonymous route as well: restrict that route by IP.
Enabling the route¶
To enable this route on the Portal, you can use the options:
HEALTHCHECK_ENABLE: “true”
HEALTHCHECK_RESTRICT_IP: “192.168.1.1,192.168.10.0/24”
And to enable this route on the Admin Portal:
HEALTHCHECK_PORTALADMIN_ENABLE: “true”
HEALTHCHECK_PORTALADMIN_RESTRICT_IP: “192.168.1.1,192.168.10.0/24”
Prometheus Format¶
If you wish to obtain this information in Prometheus format, it is accessible on the route https://your-portal-url/api/healthcheck/prometheus
# HELP app_status API and database status (1 = up, 0 = down)
# TYPE app_status gauge
app_status 1
# HELP app_internal_services_status Internal services status (1 = all up, 0 = at least one down)
# TYPE app_internal_services_status gauge
app_internal_services_status 0
# HELP app_service_status Services status (1 = up, 0 = down)
# TYPE app_service_status gauge
app_service_status{service="db"} 1
app_service_status{service="provision-api"} 0
app_service_status{service="provision-relay-api"} 0
app_service_status{service="My provider - SWARM", parent="container-providers", type="SWARM"} 0
app_service_status{service="My websocket relay 1 - WS_SWARM", parent="ws-relays", type="WS_SWARM"} 0
app_service_status{service="My websocket relay 1 - Traefik status", parent="ws-relays", type="WS_SWARM"} 0
# HELP app_service_items Services items numbers
# TYPE app_service_items gauge
app_service_items{service="My provider - SWARM", parent="container-providers", type="SWARM"} 12
app_statusThe API and its database. A value of
1means both answer.app_internal_services_statusThe internal services, the database excluded. A value of
0means at least one of them is down.app_service_statusIndicates the status of each monitored service. A value of
1means the service is operational. A value of0means it is unavailable.
An instance whose database runs on a MySQL NDB Cluster also exposes the cluster itself:
# HELP app_ndb_status NDB cluster verdict (2 = ok, 1 = warn, 0 = crit, stale, unknown or unreachable)
# TYPE app_ndb_status gauge
app_ndb_status 2
# HELP app_ndb_min_redundancy Fewest live nodes in any node group; 1 means the next incident is an outage
# TYPE app_ndb_min_redundancy gauge
app_ndb_min_redundancy 2
# HELP app_ndb_data_nodes Data nodes the cluster reports
# TYPE app_ndb_data_nodes gauge
app_ndb_data_nodes{state="live"} 4
app_ndb_data_nodes{state="total"} 4
The same route also carries app_ndb_data_memory_max_pct, app_ndb_redo_max_pct and app_ndb_snapshot_age_seconds. A snapshot that stops ageing means the supervision sidecar no longer collects, so app_ndb_status drops to 0.
Warning
The node-by-node diagnostic of the relays and container providers is not exposed in Prometheus format. app_service_status reports the cluster’s entry point only. Read the JSON route for the per-node detail.
Monitoring Example¶
Here is an example of setting up platform health monitoring using Nagios
Prerequisites¶
On the Nagios server: have the curl and jq commands available
Command¶
define command {
command_name reemo_healthcheck
command_line /usr/lib/nagios/plugins/reemo_healthcheck $ARG1$
}
Script¶
#!/bin/bash
# Check if an argument (URL) is provided
if [ -z "$1" ]; then
echo "CRITICAL: No URL provided. Usage: $0 <URL>"
exit 2
fi
HEALTHCHECK_URL="$1"
# Fetch JSON response
response=$(curl -s "$HEALTHCHECK_URL/api/healthcheck")
# Check if the request was successful
if [ $? -ne 0 ] || [ -z "$response" ]; then
echo "CRITICAL: Unable to access the health check page ($HEALTHCHECK_URL)"
exit 2
fi
# Extract service statuses using jq
status=$(echo "$response" | jq -r '.status')
errors=$(echo "$response" | jq -r '.. | objects | select(.status? and .status != "OK")')
# Check if the global status is OK
if [ "$status" != "OK" ]; then
echo "CRITICAL: Global health check status is $status"
exit 2
fi
# Check if any sub-services have issues
if [ -n "$errors" ]; then
echo "WARNING: Some services are not OK:"
echo "$errors"
exit 1
fi
# Everything is OK
echo "OK: All services are operational"
exit 0
Service¶
define service{
host_name < HOSTNAME >
use generic-service ; Name of service template to use
service_description Reemo Healthcheck
check_command reemo_healthcheck!https://< URL >
}
Prometheus Monitoring¶
It is possible to enable Prometheus on the Traefik entry points; several options are available:
Enable Prometheus¶
To enable Prometheus, you can add the option TRAEFIK_PROMETHEUS_ENABLE: true in the inventory file.
Port¶
By default, the Prometheus page will be accessible on the same port as the Portal. Use the option TRAEFIK_PROMETHEUS_PORT: “<port number>” to change it.
URL¶
By default, the Prometheus page will be accessible on the Portal URL with the /metrics path. It is possible to specify one or more dedicated URLs:
TRAEFIK_PROMETHEUS_URLS:
- "metrics1.domain.tld"
- "metrics2.domain.tld"
Note
In the case of a 3-node cluster, it is recommended to set 3 URLs so that Prometheus can retrieve the metrics from all nodes.
IP Filtering¶
To restrict access to specific IP addresses, you can use the TRAEFIK_PROMETHEUS_RESTRICT_IP option.
Example:
TRAEFIK_PROMETHEUS_RESTRICT_IP: "1.1.1.1,2.2.2.2"
Datadog Monitoring¶
To send platform logs to Datadog, use the following options:
DATADOG_ENABLED: true
DATADOG_API_KEY: "<your_datadog_api_key>"
DATADOG_SITE: "datadoghq.eu"
DATADOG_SYSLOG_PREFIX: ""
DATADOG_ENABLED: enables the Datadog integration.
DATADOG_API_KEY: your Datadog API key, to replace with your own.
DATADOG_SITE: the Datadog site associated with your account (e.g.
datadoghq.eu), provided by Datadog.DATADOG_SYSLOG_PREFIX: optional prefix added to each forwarded log line.