gameserver-observability · v0.1.1

Installation

The pack is a set of files for a Prometheus and a Grafana you already run: install the scrape jobs, the exporter modules and the rules on the host that runs Prometheus (Install), and the dashboard on the host that runs Grafana (Dashboards). The pack adds to your setup and changes none of your own jobs, rules or dashboards: Prometheus gets one more scrape file and five rule files, json_exporter and blackbox_exporter get this pack’s modules (in a new config, or merged into the one they have), and Grafana gets one dashboard in its own folder. The game server needs no software from this pack, only the two /perf/ credentials (configuration); if it is set up with the luminare.gameserver collection, its roles set them (With the luminare.gameserver collection). To look at the pack first without a game server, start the demo stack.

Check out a release tag rather than the main branch, which can hold unreleased changes, and verify the download as shown below.

The commands in Install, and those for Prometheus and the exporters in Uninstall, were run on 2026-10-21 as root in a python:3.13-slim container, against the fake server: from a local copy instead of git clone, without sudo, with the password written by printf instead of sudoedit, with the exporters started by the commands of their ExecStart= lines and Prometheus 3.15.0 started directly instead of as services, with fxserver.yml, the optional versions.yml and the rules included. All seven targets were up (the version list job read 35245 from the real list), the five rule groups were evaluated without an error, no alert was active, and the queries in Check that it works returned their series. On a second run, with an exporter config already in each place, the first Install block left both files unchanged. Run again on 2026-10-22 in the same image, the password block kept an existing password file and its content.

Requirements

Requirement Version Notes
Prometheus 3.15.0 tested 3.x; scrape_config_files needs 2.43 or newer, the scrape jobs are checked with promtool 3.15.0
json_exporter 0.8.0 tested the module format of 0.8.0 (toolchain has the download and sha256)
blackbox_exporter 0.29.0 tested
Game server (FXServer) build 35245 read in the source not yet tried against a running server; see the README’s Limitations
node_exporter, mysqld_exporter not run here optional, for the host, build and database alerts; scraped by jobs of your own (configuration)
Grafana 13.2.4 tested optional, for the dashboard; dashboard schema 42, the latest of Grafana 13.2.4; other versions not tried
cloudflared 2026.10.2 tested optional, for the dashboard’s tunnel panels; its metrics scraped by a job of your own
Network the Prometheus host reaches the game port (30120) over loopback, a private network or a tunnel; the exporters listen on 127.0.0.1; the optional version list job needs outbound HTTPS from json_exporter
Python 3.10 or newer only for the pack check, the fake server and the repository’s tests

Install

/etc/prometheus/scrape/fxserver.yml is this pack’s own file. The two exporter configs are installed only where none exists yet: test -e … || skips a file that is already there, so an exporter that serves other modules keeps them. If json_exporter or blackbox_exporter already runs on this host (a distribution package may keep its config in another place), copy this pack’s modules into that config under modules: instead, after checking that it has no modules of the same names: fxserver_dynamic, fxserver_info and fxserver_versions from json_exporter/config.yml, and tcp_connect, http_fxserver_info, http_401_expected and http_access_protected from blackbox/blackbox.yml.

git clone https://github.com/luminare-dev/gameserver-observability.git
cd gameserver-observability
sudo install -D -m 0644 prometheus/scrape/fxserver.yml /etc/prometheus/scrape/fxserver.yml
sudo install -D -m 0644 -t /etc/prometheus/rules rules/*.yml
test -e /etc/json_exporter/config.yml || sudo install -D -m 0644 json_exporter/config.yml /etc/json_exporter/config.yml
test -e /etc/blackbox_exporter/blackbox.yml || sudo install -D -m 0644 blackbox/blackbox.yml /etc/blackbox_exporter/blackbox.yml

/etc/prometheus/rules/ then holds this pack’s five rule files; if you keep rules of your own there, check first that none has the same name. Leave out a rule file whose data you do not collect, or keep it: rules without data stay silent (configuration).

Then change the targets and the server label in /etc/prometheus/scrape/fxserver.yml (configuration), and write the /perf/ password into a file only Prometheus can read (the group is the one Prometheus runs as, often prometheus):

sudo install -d -m 0750 -g prometheus /etc/prometheus/secrets
test -e /etc/prometheus/secrets/fxserver_perf || sudo install -m 0640 -g prometheus /dev/null /etc/prometheus/secrets/fxserver_perf
sudoedit /etc/prometheus/secrets/fxserver_perf   # the password only, one line

Include the jobs and the rules in /etc/prometheus/prometheus.yml:

scrape_config_files:
  - /etc/prometheus/scrape/fxserver.yml
rule_files:
  - /etc/prometheus/rules/*.yml

The host, build and database alerts read node_exporter and mysqld_exporter: give their jobs the server label of the game server (configuration).

Run both exporters as services of your init system, listening on loopback. If they are not services yet, these are the ExecStart= lines of their systemd units (binaries in /usr/local/bin; the downloads and their sha256 are on the toolchain page); use the path of the merged config if you merged the modules:

# json_exporter.service
ExecStart=/usr/local/bin/json_exporter --config.file=/etc/json_exporter/config.yml --web.listen-address=127.0.0.1:7979
# blackbox_exporter.service
ExecStart=/usr/local/bin/blackbox_exporter --config.file=/etc/blackbox_exporter/blackbox.yml --web.listen-address=127.0.0.1:9115

Restart an exporter that was already running, so that it loads the new modules. Then check the Prometheus config and reload Prometheus:

promtool check config /etc/prometheus/prometheus.yml
sudo systemctl reload prometheus

The two optional jobs are installed the same way and added to scrape_config_files: the admin hostname probe (prometheus/scrape/tunnel.yml, set its target first) and the version list for FXServerBuildBehindRecommended (prometheus/scrape/versions.yml, needs outbound HTTPS):

sudo install -D -m 0644 prometheus/scrape/versions.yml /etc/prometheus/scrape/versions.yml

Dashboards

The dashboard “Game server overview” needs Grafana with a Prometheus data source that holds the pack’s series. It picks Grafana’s default Prometheus data source; switch it with the Data source selector at the top. Only if Grafana has no data source for this Prometheus yet, install the pack’s one first and set its url to your Prometheus, for example http://127.0.0.1:9090 (configuration). On the Grafana host, from the clone (paths of the Grafana packages; adapt them for another setup):

sudo install -D -m 0644 grafana/provisioning/datasources/gameserver-observability.yml /etc/grafana/provisioning/datasources/gameserver-observability.yml
sudoedit /etc/grafana/provisioning/datasources/gameserver-observability.yml   # url: your Prometheus

Then install the dashboard and restart Grafana. Copy only grafana/dashboards/*.json, not the shareable/ folder:

sudo install -D -m 0644 grafana/provisioning/dashboards/gameserver-observability.yml /etc/grafana/provisioning/dashboards/gameserver-observability.yml
sudo install -D -m 0644 -t /var/lib/grafana/dashboards/gameserver-observability grafana/dashboards/*.json
sudo systemctl restart grafana-server

Without access to Grafana’s files, import the copy without variables instead: Dashboards → New → Import, upload grafana/dashboards/shareable/game-server-overview.json and choose the Prometheus data source. It shows every game server at once. Do not import it into the folder of the provisioned dashboard, which has the same title.

The commands above were run on 2026-10-21 as root in a grafana/grafana:13.2.4 container (without sudo, with the container’s start instead of systemctl, the data source file unchanged and Prometheus reachable as prometheus:9090): Grafana created the folder “Game server” with the dashboard and the data source “Game server metrics”, the dashboard opened with that data source and the Game server selector on All (game-01), and every panel showed data from the fake server and the exporters. The import of the shareable copy was run through Grafana’s import API.

With the luminare.gameserver collection

The luminare.gameserver Ansible collection installs and updates the game server. Its roles already do the game server’s side of this pack; set these variables for your game servers:

This pack needs Variable of the collection
The /perf/ credentials (sv_prometheusBasicAuthUser, sv_prometheusBasicAuthPassword in secrets.cfg) fxserver_perf_user and fxserver_perf_password of the fxserver role, or, when the txadmin role runs too, its toggle txadmin_prometheus_basic_auth (enabled, user, password) instead; use one of the two. The password needs at least 24 characters.
The build metrics of FXServerArtifactOld and FXServerBuildBehindRecommended (fxserver_artifact.prom) fxserver_textfile_dir of the fxserver role: the folder that node_exporter’s textfile collector reads

For example, in the group variables of the game servers, with the password taken from your secret store (an encrypted variables file, never plain text in git):

fxserver_perf_user: prometheus
fxserver_perf_password: "{{ vault_fxserver_perf_password }}"
fxserver_textfile_dir: /var/lib/node_exporter/textfile_collector

Then install this pack on the Prometheus host as in Install, with the same user name in basic_auth.username and the same password in /etc/prometheus/secrets/fxserver_perf, and run node_exporter on the game server with --collector.textfile.directory=/var/lib/node_exporter/textfile_collector and a job of your own (configuration). The collection has no role that installs this pack, Prometheus, the exporters or Grafana; those stay with your monitoring setup. The variables above are documented in the collection’s fxserver and txadmin role READMEs.

Verify the release download

Every release has a SHA256SUMS file and a build provenance attestation (the attestation only for releases made while the repository is public):

sha256sum -c SHA256SUMS
gh attestation verify gameserver-observability-X.Y.Z.tar.gz --repo luminare-dev/gameserver-observability

Check that it works

In Prometheus (Status → Targets) the jobs fxserver_perf, fxserver_json and fxserver_blackbox are up, and these queries return one series per game server (three for the probe):

fxserver_clients
fxserver_tick_time_seconds_count{thread="svMain"}
probe_success{job="fxserver_blackbox"}

probe_success{module="http_401_expected"} must be 1: it is 0 when /perf/ answers without credentials. Status → Rules lists the groups fxserver-tick-time, fxserver-alerts, fxserver-build-alerts, host-alerts and mariadb-alerts with every rule OK, and within a minute or two this query returns three series per game server (svMain, svNetwork, svSync):

server_thread:fxserver_tick_time_seconds:p95_1m

With the version list job, fxserver_recommended_build returns the current Recommended build. Status → Alerts shows what is pending or firing. Troubleshooting covers the usual errors.

In Grafana, Dashboards → Game server → Game server overview shows your game servers in the Game server selector, Status Up and the player count. Panels of rows whose exporter you do not scrape (host, MariaDB, tunnel, admin hostname) show “No data”.

Check the repository

bash scripts/test.sh                    # unit tests, including the fake server and the pack check
python3 scripts/check_pack.py           # configs parse, privacy rules, and promtool when on the PATH
bash scripts/check_promtool.sh          # rule checks and rule tests (needs promtool)
python3 scripts/smoke_exporters.py      # end to end (needs prometheus, json_exporter, blackbox_exporter)
python3 scripts/lint_dashboards.py      # dashboards and their shareable copies, and promtool when on the PATH
python3 scripts/smoke_demo.py           # starts, checks and removes the demo stack (needs Docker with Compose)

scripts/test.sh ends with a summary like this one, from a machine without gitleaks, markdownlint-cli2 and promtool (the tests that need them are skipped):

Ran 276 tests in 9.276s

OK (skipped=13)

python3 scripts/check_pack.py with promtool on the PATH prints:

check_pack: 0 finding(s) in 6 parsed file(s); promtool: 4 file(s) passed promtool check config

python3 scripts/lint_dashboards.py with promtool on the PATH prints:

lint_dashboards: 0 finding(s) in 2 file(s), 75 queries; promtool: 75 queries passed promtool check rules

python3 scripts/smoke_exporters.py --bin-dir bin (binaries as on the toolchain page) prints one line per check and ends with:

smoke_exporters: all checks passed (187 s)

python3 scripts/smoke_demo.py (demo stack) prints one line per check and ends with:

smoke_demo: all checks passed, stack removed (57 s)

Uninstall

Remove the scrape_config_files entries and reload Prometheus. Stop the exporters, or, if they serve other modules too, delete this pack’s modules from their configs and restart them. Then delete the files this pack installed, the clone and the virtual environment of scripts/test.sh:

sudo rm -f /etc/prometheus/scrape/fxserver.yml /etc/prometheus/secrets/fxserver_perf
sudo rm -f /etc/prometheus/rules/{fxserver.recording,fxserver.alerts,build.alerts,host.alerts,mariadb.alerts}.yml
rm -rf gameserver-observability "${XDG_CACHE_HOME:-$HOME/.cache}/gameserver-observability"

Only where they apply: the optional jobs, if you installed them, and the exporter configs, if Install created them (keep them if the modules were merged into existing configs):

sudo rm -f /etc/prometheus/scrape/tunnel.yml /etc/prometheus/scrape/versions.yml
sudo rm -f /etc/json_exporter/config.yml /etc/blackbox_exporter/blackbox.yml

Directories that are empty afterwards (/etc/prometheus/secrets, /etc/prometheus/rules, /etc/prometheus/scrape, /etc/json_exporter, /etc/blackbox_exporter) can be removed with sudo rmdir.

For the dashboard, remove the provisioning file together with the dashboard files and restart Grafana; it then deletes the dashboard (with only the dashboard files gone, it would keep it). The empty folder “Game server” stays until you delete it in Grafana:

sudo rm -f /etc/grafana/provisioning/dashboards/gameserver-observability.yml
sudo rm -rf /var/lib/grafana/dashboards/gameserver-observability
sudo systemctl restart grafana-server

A provisioned data source cannot be deleted in Grafana, and it stays when its file is removed. If you installed the pack’s one, replace its file with one that deletes it, restart Grafana, then remove the file:

printf 'apiVersion: 1\ndeleteDatasources:\n  - name: Game server metrics\n    orgId: 1\n' |
  sudo tee /etc/grafana/provisioning/datasources/gameserver-observability.yml
sudo systemctl restart grafana-server
sudo rm /etc/grafana/provisioning/datasources/gameserver-observability.yml

These steps were run on 2026-10-21 in the same container: after the first restart the dashboard was gone and the folder was left; after the second the data source was gone.

Not affiliated with or endorsed by Cfx.re, Rockstar Games or Take-Two.

docs/install.md on GitHub

Licensed under Apache-2.0. Source: luminare-dev/gameserver-observability at v0.1.1.