Skip to main content

Monitoring & Alerts

Two things worth separating: checking a node right now, and being told when something breaks at 3am. The first is a curl; the second is the monitoring stack.


Health checks​

Every role answers the same RPC, whatever its firewall posture. On a node whose RPC is loopback-only, go through the container. Replace <node> with orbinum-validator or orbinum-rpc-node:

docker exec <node> curl -s -H 'Content-Type: application/json' \
-d '{"id":1,"jsonrpc":"2.0","method":"system_health"}' \
http://localhost:9944

A healthy node returns isSyncing: false and a non-zero peers:

{"jsonrpc":"2.0","result":{"peers":3,"isSyncing":false,"shouldHavePeers":true},"id":1}

Sync progress, when it is still catching up:

docker exec <node> curl -s -H 'Content-Type: application/json' \
-d '{"id":1,"jsonrpc":"2.0","method":"system_syncState"}' \
http://localhost:9944

Compare currentBlock against highestBlock.

The node version, and the runtime it executes:

docker exec <node> curl -s -H 'Content-Type: application/json' \
-d '{"id":1,"jsonrpc":"2.0","method":"system_version"}' \
http://localhost:9944

docker exec <node> curl -s -H 'Content-Type: application/json' \
-d '{"id":1,"jsonrpc":"2.0","method":"state_getRuntimeVersion"}' \
http://localhost:9944

system_version returns <version>-<commit>; check it against Current versions. For validators, the version each one declared in its last authored block is on-chain in validatorSet.lastAuthorVersion — see Minimum node version.


Prometheus metrics​

Every role exposes metrics on 9615. Where that port listens is the part that differs — see Ports & Endpoints. Keep it on a private interface; the endpoint is unauthenticated, so the firewall is the only thing protecting it.

The metrics worth watching:

MetricWhat it tells you
substrate_block_height{status="best"}Chain is still producing
substrate_block_height{status="finalized"}GRANDPA is still finalizing
substrate_sub_libp2p_peers_countPeering health
substrate_ready_transactions_numberTransaction pool backlog
process_resident_memory_bytesMemory pressure

The alerting stack​

node-deploy ships a complete monitoring stack — use it rather than writing rules by hand. testnet/monitoring/ runs Prometheus, Alertmanager (with Telegram delivery) and Grafana in one Compose file, with alert rules already written and tested.

It is generic: you declare which nodes to watch in prometheus/targets/, so the same stack works for one node on your laptop or a fleet on a private VPC.

Everything binds to 127.0.0.1 on the monitoring host. Reach Grafana and Prometheus over an SSH tunnel:

ssh -L 3000:localhost:3000 -L 9090:localhost:9090 user@<monitoring-host>

Each node host also runs the small node-exporter stack from testnet/monitoring/node-exporter/, which reports CPU, memory and disk.

What it already alerts on​

The shipped prometheus/rules/ cover the failures that matter:

AlertFires when
FinalityStalledBest and finalized heights diverge
GrandpaRoundStalledNo GRANDPA round progress for 5m
ChainHaltedNo new blocks for 3m
ChainForkDetectedMore than one leaf for 10m
ValidatorHeightDivergenceOne validator falls behind the others
BlockTimeDegradedBlocks arriving slower than target
TransactionPoolBacklogReady transactions above threshold

FinalityStalled is the one to act on first — see Finality is stalled.

The monitoring stack deliberately runs no Watchtower: the thing that tells you the chain is broken must not restart itself mid-incident.