# xonotic_exporter Prometheus exporter for [Xonotic](https://xonotic.org/) game servers. Scrapes metrics via RCON (`sv_public` + `status 1`) and exposes them in Prometheus exposition format. ## Features - **Python 3.11+** (fully compatible with 3.13 — no deprecated asyncio `loop=` args) - **TOML configuration** — one file, all servers, one systemd unit - **All three RCON modes** — nonsecure, secure-time, secure-challenge (MD4) - **Blackbox-style multi-target** — one exporter, many game servers - **CLI test interface** — human-readable or raw Prometheus output - **Zero-downtime config reload** — `kill -HUP $PID` or `POST /-/reload` ## Installation ```bash python3 -m venv /opt/xonotic_exporter/venv /opt/xonotic_exporter/venv/bin/pip install . ``` ## Configuration Copy `examples/xonotic_exporter.toml` to `/etc/xonotic_exporter/xonotic_exporter.toml` and fill in your `rcon_password` values. ```toml [exporter] host = "0.0.0.0" port = 9260 [[servers]] name = "vehicles" host = "localhost" port = 26010 rcon_password = "secret" rcon_mode = 2 # 2 = secure-challenge (MD4) — recommended [[servers]] name = "resurrection" host = "localhost" port = 26015 rcon_password = "secret" rcon_mode = 2 [[servers]] name = "insurrection" host = "localhost" port = 26016 rcon_password = "secret" rcon_mode = 2 ``` **rcon_mode values** match your server's `server.cfg`: | Value | Name | server.cfg setting | |-------|-------------------|--------------------| | `0` | nonsecure | `rcon_restricted 0` | | `1` | secure-time | `rcon_secure 1` | | `2` | secure-challenge | `rcon_secure 2` | ## Running ### As a systemd service ```bash sudo cp examples/xonotic_exporter.service /etc/systemd/system/ sudo systemctl daemon-reload sudo systemctl enable --now xonotic_exporter ``` Reload config without restarting: ```bash sudo systemctl reload xonotic_exporter # or curl -XPOST http://localhost:9260/-/reload ``` ### Manually ```bash xonotic-exporter serve /etc/xonotic_exporter/xonotic_exporter.toml ``` ## CLI Testing ```bash # Human-readable output (default) xonotic-exporter query vehicles --config xonotic_exporter.toml # Raw Prometheus exposition xonotic-exporter query vehicles --config xonotic_exporter.toml --prometheus # Ad-hoc (no config file needed) xonotic-exporter query --host localhost --port 26010 --password secret --mode 2 # Ad-hoc with verbose logging xonotic-exporter -v query --host localhost --port 26010 --password secret # Validate config xonotic-exporter validate /etc/xonotic_exporter/xonotic_exporter.toml ``` Human-readable output example: ``` RCON mode : secure-challenge (MD4) ──────────────────────────────────────────────────── Server : vehicles Hostname : My Xonotic Server Map : warfare Public : yes (sv_public=1) ──────────────────────────────────────────────────── Ping : 2.3 ms CPU : 1.4 % Lost : 0.0 % Offset : avg=0.02ms max=1.20ms sdev=0.10ms ──────────────────────────────────────────────────── Players : 4/16 Active : 3 Spectators : 1 Bots : 0 ──────────────────────────────────────────────────── ``` ## Prometheus Configuration See `examples/prometheus.yml` for a ready-to-use scrape config. ## Metrics | Metric | Description | |--------|-------------| | `xonotic_up` | 1 if server reachable | | `xonotic_sv_public` | Value of sv_public cvar | | `xonotic_ping_seconds` | Round-trip time to server | | `xonotic_timing_cpu_percent` | Server CPU usage % | | `xonotic_timing_lost_percent` | Packet loss % | | `xonotic_timing_offset_avg_ms` | Average timing offset ms | | `xonotic_timing_offset_max_ms` | Max timing offset ms | | `xonotic_timing_offset_sdev_ms` | Timing offset std dev ms | | `xonotic_players_active` | Active (scoring) players | | `xonotic_players_spectators` | Spectators | | `xonotic_players_bots` | Bots | | `xonotic_players_total` | Total connected | | `xonotic_players_max` | Max player slots | All metrics carry an `instance` label set to the server name from TOML. ## Endpoints | Endpoint | Method | Description | |----------|--------|-------------| | `/` | GET | HTML index with all configured servers | | `/metrics?target=` | GET | Prometheus metrics for one server | | `/-/reload` | POST | Reload config from disk | | `/-/healthy` | GET | Liveness probe |