Monitoring
Logs
The server writes to standard error, which the systemd journal collects with the time:
journalctl -u ishtaria-server -f
By default (access_log = "errors") a line is written for every answer with status 400 or more and
for every request slower than 500 ms; "all" writes every request and "off" none. A line looks
like this and never contains a query string, a token or a password:
access ip=203.0.113.5 method=POST path=/players/me/cast status=429 ms=1
access ip=203.0.113.5 method=POST path=/players status=429 limited=true
Metrics
GET /metrics gives counters and gauges in the Prometheus text format. From the server machine:
curl -s http://127.0.0.1:7400/metrics
With a metrics_token a remote scraper may read it (Authorization: Bearer ...). A Prometheus job:
scrape_configs:
- job_name: ishtaria
metrics_path: /metrics
authorization: { type: Bearer, credentials: long-random }
static_configs: [{ targets: ["world.example.org:443"] }]
scheme: https
Metric |
Meaning |
|---|---|
|
answers by status class (2xx, 3xx, 4xx, 5xx) |
|
requests by area: players, world, chat, shops, trades, placed, story, … |
|
requests refused by a limit |
|
requests that ran into the 30 s limit |
|
total time and count (their ratio is the mean) |
|
living characters active in the last 30 s / all living characters |
|
open and idle connections of the database pool (at most 10) |
|
process age and version |
Things worth an alert: 5xx growing, a pool that stays at 10 open and 0 idle, rate_limited jumping
(an attack, or a limit that is too small for a school), timeouts above zero, and no data at all.
GET /health is a cheap liveness check (it asks the database).
Capacity: what one machine did
tools/loadtest.py of ishtaria-server simulates players who register and then walk, look
around, poll events, chat and ask for their profile. A measurement of 2026-10-07 with a release build of
version 0.2.1, PostgreSQL on the same machine and the load generator on the same machine too (a desktop
with a consumer GPU; so the real server would have the CPU for itself):
100 simulated players, 30 s, one request every 100 ms each |
result |
|---|---|
throughput |
about 940 requests per second, no |
walking ( |
mean 4.5 ms, p95 10 ms, p99 17 ms |
looking around ( |
p95 between 2 and 9 ms |
registration of 100 players at once |
mean 0.7 s, p95 1.3 s (passwords are hashed two at a time, on purpose) |
process |
about 200 MB of memory |
These numbers say that a small world has plenty of headroom; they do not say how a world with thousands of
players behaves, how the network of real players looks, or how the server performs with a slow
database. A real client sends about ten requests per second while walking and fewer when standing. Measure
your own setup before an event: raise the limits for the test, run the tool from another machine, and watch
/metrics while it runs. Debug builds are several times slower, notably in password hashing.