Releases: gzimbric/TickScope
Release list
TickScope v1.5.0
Changes
- Collection health is now visible even when scrapes succeed. New freshness timestamps,
enabled-stage gauges, and failure counters distinguish a working HTTP endpoint from a
stalled collector./tickscope statusalso reports collection age and failures. - Eight ready-to-use Prometheus alerts cover unreachable exporters, stale collections and
world scans, sustained low Paper and Folia TPS, high regional MSPT, heap pressure, and
incomplete Folia player sampling. The bundle includes tested hold durations and excludes
disabled collection stages and unsupported readings. - Folia sampling no longer builds a queue behind a lagging player. Only one task per
player can remain outstanding. An unfinished batch publishes its available readings when
the next collection cycle starts, with completed and expected player counts showing the
coverage. Expired callbacks cannot overwrite the published results. - Folia sample data and its generation are now published atomically, fixing a race where an
older callback could overwrite a newer reading after passing the generation check. - World exclusions and an entity-type allowlist let operators narrow collection scope.
exclude-worldsskips named worlds before scanning;entity-types.allowlistlimits the
per-type series while preserving full entity totals for included worlds. - The Grafana dashboard now includes server names in legends, collection age, collection
failures, and Folia player coverage. An additional per-server overview repeats a row for
each selected backend. - Malformed YAML and missing configuration files now reject a reload instead of silently
applying defaults, including an empty authentication token. Oversized port values are
rejected before integer conversion can turn them into a different valid port. - Reloading or disabling TickScope now closes active and queued HTTP connections, including
clients that never read the response. Shutdown no longer leaves those sockets waiting
after their deadline watchdog has stopped. - Disabling world metrics or narrowing filters removes the corresponding cached series
immediately. Still-enabled cached readings survive a reload until the next scan. - Scheduled collection exceptions retain the last snapshot, increment failure counters,
and retry on the next cycle. Health readings remain available independently of snapshot
publication.
Upgrading: existing configuration files continue to work; the new filters default to
including every world and entity type. Add the optional settings manually to use them, and
re-import the dashboard to see the new panels. Collection-health timestamps and failure
counters reset on configuration reload. Folia ping and regional summaries can now represent
partial batches, so consult the coverage metrics alongside them. The default alert thresholds
assume the standard collection intervals; adjust them if you sample less often. Alertmanager
must be configured separately to deliver notifications. Setup instructions and metric semantics
are in the monitoring guide.
Full changelog: v1.4.0...v1.5.0
TickScope v1.4.0
Changes
- The metrics endpoint can no longer be silenced by a stalled client. A connection that sent
a partial request previously held the only HTTP worker indefinitely, and every scrape timed out
until that client disconnected — with no token required, since parsing stalls before
authentication. The endpoint now runs on its own socket with per-connection deadlines and
recovers on its own. Still no runtime dependencies. Authorization: bearer <token>is now accepted alongsideBearer, as the HTTP specification
requires. A scrape configured with a lowercase scheme used to fail like a mistyped token.- Per-world entity and tile-entity totals moved to the slower scan interval
(entity-types.interval-ticks). Counting tile entities walks every loaded chunk, and before
Minecraft 26 counting entities walked every entity, so neither belonged on the 5-second
collection cycle.mc_world_chunksandmc_world_playersare unchanged and still sampled
every collection. - These three series are now omitted on Folia rather than read from the global region, which does
not own the world data they walk. - Readings the platform cannot supply are omitted instead of reported as zero. CPU load on a JVM
that does not expose it no longer looks like an idle server, and player ping is published only
when a player was actually measured. - On Folia, a batch of per-player samples that finishes late is now used rather than thrown
away. With several regions lagging at staggered times no batch ever finished before the
next began, so ping and regional figures could stay frozen at the last success. - Deaths cancelled by another plugin are no longer counted.
- A configuration value of the wrong type is now rejected with the setting named.
port: "9200"
previously bound the default port andper-world: "false"silently stayed enabled. /tickscope reloadreports what actually happened, including when a rollback failed, and two
simultaneous reloads on Folia can no longer leave an endpoint running that nothing can close.- The entity-type series survive a reload instead of disappearing until the next scan, and
/tickscope statusprints a valid URL for an IPv6 bind address. - The bundled Grafana dashboard gained a Folia regions row; its tick panels were blank on Folia,
which is the one platform where those metrics do not exist. - Release jars are now reproducible, so a download can be checked against its published checksum
by rebuilding the tag.
Upgrading: two panels can look empty after this release. mc_player_ping_avg_ms and
mc_player_ping_max_ms are absent while nobody is online, and the CPU ratios are absent on a JVM
that cannot report them, instead of both reading zero. That is the documented "missing series"
behaviour rather than a removal — add or vector(0) where a panel needs a visible zero, exactly
as the entity-type series already require. Per-world entity and tile-entity totals now refresh
every entity-types.interval-ticks (600 ticks) rather than every collection, so those graphs are
coarser; they are absent entirely on Folia.
Full changelog: v1.3.0...v1.4.0
TickScope v1.3.0
Changes
- Folia and Canvas support. TickScope now runs on Folia-compatible servers and exports
mc_folia_region_tps, sampled at the locations of online players. - Regional MSPT (
mc_folia_region_mspt_ms) is exported where the server API exposes
per-region tick times, which today means Canvas. Pure Folia reports regional TPS only. - Server-wide
mc_mspt_msandmc_tpsare intentionally absent on Folia, which has no
truthful global equivalent, rather than being reported as a misleading single number. - Entity-by-type metrics are disabled on Folia, where a world-wide entity walk has no
safe scheduler to run on. - Release jars now ship a
.sha256file alongside them so downloads can be verified.
Still one jar for Paper and Purpur 1.18.2 through 26.2, still no runtime dependencies.
Full changelog: v1.2.2...v1.3.0
TickScope v1.2.2
Changes
- Login counting moved to the async pre-login event, which the modern login pipeline is
guaranteed to fire. - Added the Grafana dashboard and a security policy; long-form documentation moved to the wiki.
Full changelog: v1.2.1...v1.2.2
TickScope v1.2.1
What changed
- Made /tickscope reload failure-safe while preserving process-lifetime event counters.
- Fixed listener and HTTP executor leaks across reloads.
- Changed fresh installs to bind to loopback by default and added endpoint validation.
- Added build/runtime information and separate entity-scan timing metrics.
- Added correct GET, HEAD, 404, and 405 endpoint behavior.
- Added automated tests and CI coverage on Java 17, 21, and 25.
- Corrected documentation for supported versions, command aliases, authentication, and Docker configuration.
One dependency-free jar supports Paper 1.18.2 through 26.2 on Java 17 or newer.
TickScope 1.2.0
Wider version support
One jar now covers Paper 1.18.2 through 26.2. Nothing in the exporter needed a modern API — the
only blocker was a single call in the status command. The build targets Java 17, which is Minecraft
1.18's own runtime requirement, so there is no version-specific code, no multi-module build, and no
meaningful change in size.
Verified against real 1.18.2, 1.19.4, 1.20.6, 1.21.4 and 26.2 servers: identical metric families,
identical label values, no startup warnings.
Optional bearer auth on the endpoint
The metrics endpoint has always been open, on the assumption it sits on loopback or behind a
firewall. That is not available to everyone, so auth-token in config.yml now requires
Authorization: Bearer <token> on every scrape.
It is empty by default, so nothing changes for an existing install. The comparison is
constant-time, and a refused scrape gets an empty body rather than anything describing the server.
This is not confidentiality — the endpoint is plain HTTP and the token crosses the wire in the clear.
Put a TLS-terminating reverse proxy in front if the scrape path leaves a network you control.
Fixed
Entity type labels are now the Minecraft registry name rather than the Bukkit enum name. Bukkit
realigned the enum with the registry in 1.20.5, so on older servers 18 of 114 entity types were
labelled differently — including dropped_item, which is item everywhere now. No effect on
26.2, where the two already agree, so existing dashboards and history are untouched.
Upgrading
Drop the new jar in and restart. No configuration changes required.
TickScope 1.1.0
First public release.
A Prometheus exporter for Minecraft Paper servers in a 28 KB jar with zero runtime dependencies — no Spring, no Micrometer, nothing shaded. Drop it in plugins/, scrape http://127.0.0.1:9101/metrics, graph it in Grafana.
Highlights
- Exact tick percentiles —
mc_mspt_msat avg/min/max/p50/p95/p99, computed from Paper's raw per-tick nanosecond array rather than estimated from buckets. TPS caps at 20 and hides everything below it; MSPT does not. - Per-world counts — entities, tile entities, chunks and players, from Paper's O(1) counters.
- Entities by type —
mc_world_entities_by_type{world,type}, for finding what is actually piling up. - JVM and process — heap and non-heap memory, threads, GC cycles and time per collector, process and system CPU.
- Player event counters — login, join, quit, chat, death. Counters rather than gauges, so nothing is missed between scrapes.
- Its own overhead, reported as
mc_collection_duration_seconds— typically 2–3 ms.
Scrapes never touch the server thread: collection runs on a scheduler task and publishes an immutable snapshot that the HTTP handler serialises.
Requirements
Paper 26.2+, Java 25+. Purpur works. Plain Spigot and Bukkit do not, and Folia is not supported.
Docker
Set bind-address: "0.0.0.0" and restrict on the publish side with ports: ["127.0.0.1:9101:9101"]. Binding to loopback inside the container makes the port unreachable even with a correct -p mapping.