A daemon that watches systemd services and exposes their status as Prometheus metrics. Point it at a list of units and it polls each one with systemctl is-active
on a fixed interval, then serves the results at /metrics.
It uses the standard library plus four crates and a TcpListener (no async runtime).
- Reads a TOML config listing the services to watch.
- Polls each one every
poll_interval_secs(default 10) usingsystemctl is-active --quiet <name>. - Serves
/metricsin Prometheus text format over HTTP. - Logs every status change to stderr as a structured logfmt line.
- Shuts down cleanly on SIGTERM (and SIGINT, so Ctrl-C works too).
Because it shells out to systemctl, it only does anything useful on a Linux system running systemd. Anywhere else, every service simply reads as down.
# config.toml
services = ["sshd", "cron"]
listen_addr = "0.0.0.0:9100"
poll_interval_secs = 10services(required): the unit names you'd pass tosystemctl is-active. Names vary by distro, so check yours (for example, on Debian/Ubuntu the SSH server isssh, on RHEL it'ssshd).listen_addr(default127.0.0.1:9100): where/metricsbinds. The default is loopback-only. Set it to0.0.0.0:9100(like in the example) when another host needs to scrape it.poll_interval_secs(default10): seconds between polls.
cargo run --release -- config.tomlIf you don't pass a path it looks for config.toml in the working directory.
Then scrape it:
curl localhost:9100/metricsTo run it for real, drop the release binary somewhere and wrap it in a systemd unit of its own. Send SIGTERM to stop it, which it handles.
Two families, in the standard Prometheus text exposition format:
# HELP service_up 1 if the systemd service is active, 0 otherwise.
# TYPE service_up gauge
service_up{name="sshd"} 1
service_up{name="cron"} 0
# HELP service_checks_total Number of polls performed for the service.
# TYPE service_checks_total counter
service_checks_total{name="sshd"} 42
service_checks_total{name="cron"} 42
service_upis a gauge:1when the unit is active,0otherwise.service_checks_totalis a counter: how many times that unit has been polled since startup. It's a liveness signal for the daemon itself, and it keeps climbing even while a service stays down.
Status changes go to stderr as logfmt, one line each:
ts=2026-06-19T12:34:56Z level=info event=startup listen_addr=0.0.0.0:9100 services=2 poll_interval_secs=10
ts=2026-06-19T12:34:56Z level=info event=initial service=sshd state=active
ts=2026-06-19T12:35:46Z level=info event=status_change service=cron old_state=active new_state=inactive
ts=2026-06-19T12:40:12Z level=info event=shutdown
The first time it sees a service it logs an initial line. After that, it only logs when the state actually flips.