See what your factory is actually doing, in Grafana. Production, power reserves, machine status, logistics supply and demand, trains, research and space platforms as Prometheus metrics - straight into your existing node_exporter, no sidecar or extra port needed.
Providing the player with new tools or adjusting the game interface, without fundamentally changing gameplay.
Version: 2.0.0
Date: 2026-08-05
Minor Features:
- Item production and consumption can now be split by quality tier
(graftorio3-production-quality-labels, off by default), using the
input_quality_counts / output_quality_counts statistics.
- New Grafana dashboard "0.0 - graftorio3 Overview" covering exporter
health, machine status, electric network reserves, production rates,
logistic stock and rocket silos on one page, with a surface selector.
The inherited dashboards still describe the graftorio2 metric set; this
one is the entry point for everything added since.
- New depth metrics (graftorio3-depth-metrics, on by default):
* factorio_accumulator_charge_joules and
factorio_accumulator_capacity_joules per electric network: current
flow says what is happening now, buffer level says whether the
network is about to run out.
* factorio_generation_capacity_watts: installed maximum generation per
network, for headroom alerts.
* factorio_logistic_storage_items and factorio_logistic_provider_items:
logistic stock split by where it sits. The API exposes no cheap view
of outstanding requests, so this reports storage versus providers
instead of pretending to measure demand.
* factorio_rocket_silo_parts and factorio_rocket_silo_status per silo.
- Logistic demand: factorio_logistic_requested_items sums outstanding
requester filters, completing the supply/demand picture that the
storage-versus-providers split only half answered. get_supply_counts
takes one item at a time, so requester points are the workable route.
The same chest can appear more than once in requester_points, so points
are deduplicated per owning entity.
- factorio_logistic_robots: logistic robots, construction robots and
roboport cells per network.
- factorio_trains_manual and factorio_trains per surface. A train left in
manual mode is usually a forgotten train blocking a line.
- factorio_daytime per surface, which explains solar and accumulator
swings, and factorio_force_bonus{bonus} covering 17 research bonuses
and modifiers as plain attribute reads.
- CI now verifies the mod on a base-game install with Space Age, quality
and elevated rails disabled, in addition to the full mod set. Every
earlier test ran with the DLC enabled, so base-game behaviour was
unverified; it passes, and is now a standing check rather than an
assumption.
- Space platform depth (part of graftorio3-depth-metrics):
factorio_platform_hub_items with quality, factorio_platform_asteroid_chunks
and factorio_platform_paused. The base collector reports state, weight,
speed and distance; none of that says whether a platform is carrying
anything or whether its asteroid intake has dried up. Collected per
platform inside pcall, since the platform APIs are the newest part of
the runtime.
- Dual publishing for both Factorio channels. The stable channel is still
2.0 while the mod targets 2.1, and factorio_version gates in both
directions, so stable-channel servers could not install it at all.
package.sh now emits a second zip, X.Y.(Z+1), with identical Lua and
factorio_version 2.0, and the release workflow publishes both. The
portal assigns exactly one game version per mod version -- verified
against flib, helmod and even-distribution, none of which has a
duplicate version number -- so a second version number is the only way
to serve both.
- Quality-aware production counts are now feature-probed at runtime.
input_quality_counts does not exist before 2.1, and reading a missing
field on a LuaObject raises rather than returning nil, so with the
setting enabled on 2.0 the collector would have failed. It now falls
back to the aggregate counts and quality="all". Verified on a real
2.0.77 headless with the setting forced on: production still reported,
no collector errors, promtool clean.
- Vendored Prometheus library documented in prometheus/PROVENANCE.md: it
comes from tarantool/metrics (BSD 2-Clause), arrived by inheritance
through the fork chain and has been modified since, so it is a fork
rather than a pinned dependency.
- Removed the library's exported init(), which required
prometheus.tarantool-metrics -- a module that was never part of the
vendored subset, so any caller would have hit a load error. Being
exported made it reachable from mods using the remote interface.
- GitHub issue templates for bug reports and metric requests.
Changes:
- factorio_item_production_input and factorio_item_production_output gained
a "quality" label. With the setting off it carries the constant value
"all", so there is still one series per item and aggregations such as
sum by (name) are unaffected -- but queries that match on an exact label
set need the extra label. Fluid, kill and build statistics are unchanged:
they have no quality dimension.
Version: 1.3.0
Date: 2026-08-04
Minor Features:
- Multi-server support: new startup settings graftorio3-instance-label
(adds instance="..." to every series) and graftorio3-output-filename
(configurable file name inside script-output/graftorio3/), so several
servers can feed one Prometheus / share one textfile directory.
- New metric factorio_surface_pollution (total pollution per surface).
- entity-ghost added to the default entity count types: construction
backlog becomes visible as factorio_entities{type="entity-ghost"}.
- New event counters for rate() queries: factorio_events_total{type}
(rocket_launched, research_finished, player_died). Totals live in
storage and are re-applied after load, so the counter stays monotonic
across server restarts rather than resetting each session.
- New opt-in counters factorio_player_deaths_total and
factorio_player_kills_total (behind graftorio3-collect-player-metrics).
- CI gained a runtime verification job (tools/verify/): it starts a real
headless server with the packaged zip, waits for a collection cycle and
asserts that every expected metric family is written, that the log is
free of Lua errors and that promtool accepts the output. A negative
control deliberately breaks one collector stage and requires the harness
to fail -- a verification job that cannot fail proves nothing.
- Train statistics rewritten (v2):
* Trip, arrival and loop state moved from module locals into storage.
Previously every save/load silently reset it: trips in flight were
lost and the seen table grew for the lifetime of the save, because
trains that no longer exist were never removed.
* New garbage collection stage prunes state for vanished trains,
reported as factorio_train_tracked and factorio_train_gc_removed.
* The train ID label is the largest series source (one per train per
station pair) and is collapsed to the constant "all" unless
graftorio3-train-include-id is enabled; the label stays in the
schema so dashboards keep working either way.
* graftorio3-train-max-series caps distinct label combinations; once
exhausted, new ones are dropped and factorio_train_series_truncated
is set to 1.
- German locale (locale/de), covering every setting.
- docs/: deployment guide (node_exporter textfile collector, containers,
multi-instance hosts, Ansible fragment), ready-made Prometheus recording
rules and Alertmanager rules for exporter staleness, collector errors and
a paused server.
- CONTRIBUTING.md rewritten for the actual toolchain; the stale bun/just
instructions and the leftover Justfile and docker-compose.dev.yml are gone.
- CI actions pinned to commit SHAs (kept at their current major versions
rather than jumping to latest) with a dependabot config to keep the pins
deliberate. The repository holds a portal API key, so a mutable tag in the
release workflow is a real supply-chain surface.
- New machine status aggregate: factorio_entity_status{surface,force,type,status}
counts machines by operational state (no_power, no_ingredients, full_output,
working, ...) -- the "factory is stalled, but where" metric. Configurable via
graftorio3-entity-status-types (default assembling-machine, furnace,
mining-drill, lab; empty disables it). Reading a status needs a real entity
object, so this is the most expensive collector: own time-sliced stage,
capped by graftorio3-entity-status-max-entities. Hitting the cap sets
factorio_entity_status_truncated to 1 and reports
factorio_entity_status_scanned instead of passing partial counts off as
complete.
- Public remote interface: other mods can publish their own metrics through
graftorio3 instead of shipping a second exporter. remote.call("graftorio3",
"register_gauge"/"register_counter"/"set"/"inc"/"api_version"). Names are
validated and namespaced to factorio_*, registration is idempotent so it
can be repeated in on_load, every call returns ok plus an error message,
and the number of external metrics is capped.
- Collection is now spread across ticks (graftorio3-time-slicing, on by
default): one stage per tick slice instead of all stages at once. A full
cycle still completes every "Scheduler timer" ticks, but the periodic
spike drops sharply -- measured on a 5-surface benchmark map: max tick
time 17.67 ms -> 6.70 ms at an unchanged average (0.117 -> 0.113 ms).
Values within one file are then observed up to one cycle apart; turn the
setting off if every series must be sampled in the same tick.
- New /graftorio3 console command: last collection tick, output path,
interval, collected surfaces, active settings and per-module collector
error counts. Answers "nothing arrives in Prometheus" without log diving.
Changes:
- Zero-warning luacheck policy; .luacheckrc is now generated by
scripts/gen_luacheckrc.py so declarations cannot drift from the code.
- Metrics.md is generated from control.lua by scripts/gen_metrics.py;
CI fails when the committed file drifts from the definitions.
Version: 1.2.0
Date: 2026-08-03
Minor Features:
- New environment/state metrics module (env.lua), covering previously unused
parts of the runtime API:
* factorio_game_speed, factorio_tick_paused, factorio_ticks_played
* factorio_technology_price_multiplier, factorio_spoil_time_modifier
* factorio_peaceful_mode, factorio_solar_power_multiplier,
factorio_darkness, factorio_wind_speed, factorio_wind_orientation,
factorio_freeze_daytime (per surface)
* factorio_entities{surface,type} via count_entities_filtered
(default types include unit-spawner for enemy-pressure tracking;
configurable via graftorio3-entity-count-types)
* factorio_technologies_researched / factorio_technologies_available,
factorio_friendly_fire (per force)
* factorio_player_online_time_ticks, factorio_player_afk_time_ticks
(per player, opt-in via graftorio3-collect-player-metrics -- off
by default due to per-player label cardinality)
- New startup settings: graftorio3-entity-count-types,
graftorio3-collect-player-metrics.
- Renamed factorio_items_launched_total to factorio_items_launched: it is a
gauge, and the _total suffix is reserved for counters by Prometheus
convention (same class of fix as factorio_platforms in 1.1.0). Discovered
by promtool while verifying the new metrics; it never surfaced before
because the metric only appears once a rocket has actually launched.
Version: 1.1.0
Date: 2026-08-03
Major Features:
- Renamed to graftorio3 for the standalone mod portal release. All startup
settings use the graftorio3- prefix; existing graftorio2 settings reset to
defaults. Metrics are written to script-output/graftorio3/game.prom.
- Factorio 2.1 compatibility.
- New startup setting "Surface allowlist": restrict collection to named surfaces.
- New startup setting "Include space platforms" (default off): space platforms are
separate surfaces and multiply per-surface work and label cardinality.
Minor Features:
- New metric factorio_rockets_launched (per force).
- Exporter self-metrics: factorio_exporter_series, factorio_exporter_output_bytes
(previous cycle), factorio_exporter_last_collection_tick.
- Collector resilience: every collection stage runs isolated; a failing stage
increments factorio_collector_errors_total{module} and logs once instead of
stopping the game. The metrics file is still written when a stage fails.
Changes:
- Renamed metric factorio_platform_count to factorio_platforms: the _count
suffix is reserved for histogram/summary series by Prometheus convention
(flagged by promtool). Done before the first portal release so no existing
dashboards break.
Bugfixes:
- Replaced LuaEntity.neighbours and LuaEntity.disconnect_neighbour(), both removed
in 2.1, with the LuaWireConnector API. Power switch handling raised
"LuaEntity doesn't contain key neighbours" as soon as a switch was tracked.
- Build and destroy events were registered twice (power.lua, then circuit-network.lua).
Factorio allows one handler per event per mod, so the second registration silently
replaced the first and all power build/destroy tracking was dead. Both modules are
now dispatched from a single combined handler.
- Metric collection iterated game.players instead of game.forces. A dedicated server
that no player had joined produced no production, pollution-per-force, evolution,
logistics, research or platform metrics at all.
- factorio_items_launched was always empty: LuaForce.items_launched is a
dictionary<string, uint>, and the code iterated it with ipairs().
- Research and space platform gauges were reset inside the per-force loop, so each
force wiped the previous force's series. Reset moved ahead of the loop.
- Constant combinator rescan iterated game.players as well: combinators that
existed at server start were never tracked on a player-less dedicated server.
Rescan now iterates game.forces.
- Circuit signal and logistic item quality labels always reported "normal":
quality is a prototype-name string in the 2.x API, not an object with .name.
- Combinator build/destroy tracking filtered by entity name while the rescan
filtered by type; modded constant combinators are now tracked consistently.
Version: 1.0.0
Date: 2026-03-15
Features:
- add Justfile
Optimizations:
- performance improvements and misc fix
Bugfixes:
- correct the git path
- correctly look up max wire distance