Observability
Nylon can expose an HTTP server for Prometheus metrics, health checks, and service discovery.
Enable the server
Section titled “Enable the server”Set observability_addr in each node’s node.yaml:
observability_addr: "0.0.0.0:9090"Restart nylon after changing the node configuration. You can then check the local node:
curl http://127.0.0.1:9090/healthzcurl http://127.0.0.1:9090/readyzcurl http://127.0.0.1:9090/metricsEndpoints
Section titled “Endpoints”| Endpoint | Purpose |
|---|---|
/healthz |
Returns 200 OK while the daemon is running and 503 Service Unavailable while it is shutting down. |
/readyz |
Returns 200 OK when nylon’s internal event loop responds, or 503 Service Unavailable if it cannot respond within one second. It does not check whether every peer is reachable. |
/metrics |
Returns metrics in the Prometheus text exposition format. Returns 503 Service Unavailable if nylon cannot collect a status snapshot within one second. |
/discovery |
Returns Prometheus HTTP service-discovery targets for the addresses in central.yaml. |
Configure Prometheus
Section titled “Configure Prometheus”For a single node, add a static scrape target:
scrape_configs: - job_name: nylon static_configs: - targets: - "10.0.0.1:9090"For a mesh, Prometheus can discover the node addresses from any nylon observability server:
scrape_configs: - job_name: nylon http_sd_configs: - url: "http://10.0.0.1:9090/discovery" refresh_interval: 30s relabel_configs: - source_labels: [nylon_node_type] regex: passive action: dropThe discovery response uses every node address from central.yaml. Each target has a nylon_node label containing the node ID and a nylon_node_type label set to either router or passive. The example drops passive targets because they do not run the nylon daemon.
Configure the same observability port on every router, and make sure Prometheus can reach their nylon addresses on that port.
Metrics
Section titled “Metrics”All metric names start with nylon_.
| Metric | Type | Labels | Description |
|---|---|---|---|
nylon_up |
Gauge | — | 1 when nylon can produce a metrics snapshot. |
nylon_config_timestamp_seconds |
Gauge | — | Unix timestamp of the active central configuration. |
nylon_neighbours |
Gauge | — | Number of configured neighbours. |
nylon_active_endpoints |
Gauge | — | Number of active peer endpoints. |
nylon_selected_routes |
Gauge | — | Number of selected Babel routes. |
nylon_advertised_prefixes |
Gauge | — | Number of locally advertised prefixes. |
nylon_wireguard_transmit_bytes_total |
Counter | — | WireGuard bytes transmitted by this node. |
nylon_wireguard_receive_bytes_total |
Counter | — | WireGuard bytes received by this node. |
nylon_wireguard_peer_transmit_bytes_total |
Counter | peer |
WireGuard bytes transmitted to a peer. |
nylon_wireguard_peer_receive_bytes_total |
Counter | peer |
WireGuard bytes received from a peer. |
nylon_wireguard_peer_latest_handshake_seconds |
Gauge | peer |
Unix time of the peer’s latest WireGuard handshake, or 0 before the first handshake. |
nylon_endpoint_active |
Gauge | peer, endpoint |
1 when the endpoint is active, otherwise 0. |
nylon_endpoint_metric |
Gauge | peer, endpoint |
Current Babel endpoint metric. |
nylon_endpoint_rtt_seconds |
Gauge | peer, endpoint |
Filtered endpoint round-trip time in seconds. |
nylon_route_metric |
Gauge | prefix, router, next_hop |
Metric of a selected Babel route. |
For example, alert when a node cannot be scraped or when a peer has not completed a handshake in the last five minutes:
up{job="nylon"} == 0time() - nylon_wireguard_peer_latest_handshake_seconds > 300The handshake metric is 0 before the first successful handshake, so this expression also selects peers that have never connected. When using it in an alerting rule, add for: 5m to avoid firing while nylon starts and establishes its initial peer connections.