Messages and enums used by more than one service — resource requirements, locations, money and the rest.
LogLine is one line a game server wrote.
The unit is a line rather than a byte stream because that is the unit a pattern matches. Everything downstream — template matching, sampling for the model, the events themselves — works line by line, so splitting once at the source is cheaper than doing it in three places and disagreeing.
When the server printed the line. Not when Plany received it: a server that could not reach Plany for ten minutes buffers its lines, and they keep their original times.
textstringRequiredThe line, verbatim and without its trailing newline.
Verbatim matters: a template is a regular expression over exactly these bytes, so any normalisation here would silently invalidate every template learned before it was introduced.
streamStreamWhich stream it came from.
Kept distinct because a game server that logs everything to stderr is common, and collapsing the two loses the only signal that something was actually wrong.
STREAM_STDOUTSTREAM_STDERRSTREAM_AGENTsequenceint64Monotonic sequence within one agent run, starting at 1.
Two lines can share a timestamp — most servers log to the second — and ordering between a connect and the disconnect that follows it is the whole point. This is what breaks that tie.
{ "observe_time": "2026-10-04T12:00:00Z", "stream": "STREAM_STDOUT", "text": "", "sequence": "0"}Player identifies who an event was about.
Every field is optional because games disagree on what a player is. Steam games have a 64-bit id and nothing else; Minecraft has a UUID and a name that can change; some games log only a name and an address. Requiring any one of them would exclude a game that never prints it.
display_namestringDisplay name as the server printed it. Unstable — Minecraft names change and Steam personas change hourly — so it is for humans, not for joins.
player_idstringStable identifier, when the game logs one: a Minecraft UUID, a SteamID64, an EOS product id. This is what a session is keyed on when it exists.
id_typestringWhich namespace player_id belongs to, e.g. "steam", "minecraft", "eos".
Two games can both log a 17-digit number and mean different things.
addressstringSource address, when logged.
A personal datum, and a game server prints it unasked. It is kept because it is often the only stable identifier a game offers, and it is the field most likely to need suppressing per account — which is why it is separate rather than folded into attributes.
{ "display_name": "My server", "player_id": "my-player", "id_type": "", "address": ""}ResourceRequirements is everything a workload needs to run: CPU, memory, disks, network interfaces, and where and how it is scheduled. Game servers and sandboxes express their needs in the same terms, so a number means the same thing — and is priced the same way — in both.
vcpusint32RequiredNumber of virtual CPUs the workload sees. Required, must be at least 1.
reserved_millisint64CPU time reserved on the host, in millicores (1000 = one full core).
Must be <= vcpus * 1000. Zero means "reserve the full vcpus * 1000", i.e. no oversubscription. Below that, the VM is burstable and the difference is the burst headroom.
limit_millisint64Hard ceiling on host CPU time, in millicores, enforced by the agent via cgroup cpu.max. Zero means the ceiling is vcpus * 1000. Set this below vcpus * 1000 to cap a burstable VM that would otherwise consume all idle capacity on the node.
architectureCpuArchitectureCPU_ARCHITECTURE_X86_64CPU_ARCHITECTURE_ARM64required_featuresrepeated stringCPUID feature flags the workload requires, lowercase as they appear in /proc/cpuinfo — e.g. "avx2", "aes". Placement rejects nodes lacking any of them. Anti-cheat and DRM in game servers occasionally depend on these.
dedicated_coresboolPin each vCPU to a distinct physical core and let no other workload share those cores. Removes noisy-neighbour jitter for latency-sensitive tick loops, at the cost of a dedicated-core price.
isolate_smt_siblingsboolRequire SMT siblings of the pinned cores to stay idle. Only meaningful with dedicated_cores; used for workloads that are sensitive to hyperthread contention or that need side-channel isolation.
size_bytesint64RequiredMemory the workload sees, in bytes. Required.
reserved_bytesint64Memory guaranteed to the workload, in bytes. Must be no more than size_bytes. Zero means all of size_bytes is guaranteed.
Reserving less than size_bytes requires balloon_enabled, so unused memory can be reclaimed when it is needed elsewhere.
balloon_enabledboolAllow memory the workload is not using to be reclaimed. Required when reserved_bytes is less than size_bytes.
hugepagesboolBack the workload's memory with 2 MiB pages. Noticeably faster for memory-heavy servers — large voxel worlds, big entity counts — but can only be placed where such memory is available.
hotplug_max_bytesint64Allow memory to grow to this size while running, without a restart. Zero disables it. Must be at least size_bytes when set.
sharedboolAllow identical memory pages to be shared with other workloads on the same machine. Saves memory when many servers run the same game, at some CPU cost and with weaker isolation between them.
disksrepeated DiskSpecBlock devices, in attachment order. Exactly one must set boot unless the
workload boots from an initramfs alone.
disk_idstringRequiredIdentifier for this disk within the workload, e.g. "root" or "world-data". Must be unique within it.
imagestringOne of sourceBoot from a platform or project image, e.g.
projects/{project}/locations/{location}/images/{image}. The image is
copied (or CoW-cloned where the node supports it) into a fresh disk.
volumestringOne of sourceAttach an existing persistent volume by resource name. The volume must be in the same location and unattached.
snapshotstringOne of sourceRestore from a snapshot resource name.
blankboolOne of sourceCreate an empty, zero-filled disk of size_bytes.
size_bytesint64Size of the device. Required for a blank disk; for an image or snapshot source, zero means "the source's own size" and any larger value grows the filesystem on first boot.
typeDiskTypeDISK_TYPE_LOCAL_NVMEDISK_TYPE_NETWORK_SSDDISK_TYPE_NETWORK_SSD_HIGH_IOPSread_onlyboolAttach read-only. Several instances may share one read-only volume, which is how a common asset bundle is mounted into many game servers at once.
bootboolMarks the disk the workload boots from. Exactly one disk may set this.
delete_on_instance_deleteboolDelete the underlying storage when the instance is deleted. Always true in effect for LOCAL_NVME.
io_limitsDiskSpec.IoLimitsbandwidth_bytes_per_secondint64Sustained bytes/second. Zero means unlimited.
bandwidth_burst_bytesint64Burst allowance in bytes above the sustained rate.
iopsint64Sustained IO operations/second. Zero means unlimited.
iops_burstint64Burst allowance in operations above the sustained rate.
direct_ioboolUse direct IO (O_DIRECT), bypassing the host page cache. Lowers memory pressure on the node and makes latency more predictable, at the cost of losing host-side caching.
network_interfacesrepeated NetworkInterfaceSpecinterface_idstringRequiredStable identifier within the instance, e.g. "eth0".
networkstringPrivate network to attach to, as a resource name. Empty means the project's default network in this location.
private_ipv4stringRequested private IPv4 address. Empty allocates one from the subnet.
public_address_modeNetworkInterfaceSpec.PublicAddressModePUBLIC_ADDRESS_MODE_NONEPUBLIC_ADDRESS_MODE_SHARED_IPV4PUBLIC_ADDRESS_MODE_DEDICATED_IPV4PUBLIC_ADDRESS_MODE_IPV6tierNetworkTierNETWORK_TIER_STANDARDNETWORK_TIER_PREMIUMrate_limitsNetworkInterfaceSpec.RateLimitsingress_bits_per_secondint64Sustained bits/second. Zero means unlimited.
egress_bits_per_secondint64ingress_burst_bitsint64Burst allowance in bits above the sustained rate.
egress_burst_bitsint64ingress_packets_per_secondint64Packets/second ceiling, which is what actually protects a node from a small-packet flood. Zero means unlimited.
egress_packets_per_secondint64mac_addressstringThe interface's MAC address. Empty generates one. Pinning it matters for game licences tied to a MAC.
multi_queueboolEnable multi-queue virtio-net with one queue pair per vCPU. Raises packet throughput for servers handling many concurrent clients.
tagsrepeated stringNetwork tags, which firewall rules on this interface's network target.
Per interface rather than per instance because a rule belongs to one network, and an instance with an interface on each of two networks is answerable to two sets of rules. Lowercase letters, digits and hyphens, up to 63 characters each.
deny_inboundboolRefuse every inbound connection on this interface, whatever the network's firewall rules say. Replies to connections the workload opened still arrive.
For an interface that exists so a workload can reach a network rather than be reached on it — a sandbox connected to one of your networks, for example.
no_default_routeboolSend no internet traffic and no DNS through this interface: only the network's own range is reached through it. Without this, a workload with two interfaces could send its internet traffic out of either.
placementPlacementSpeczonesrepeated stringZones the instance may land in, as location ids ("eu-west-2a"). Empty means any zone in the region. More than one entry is a preference list in priority order, not a hard set.
required_node_selectorsrepeated NodeSelectorRequirementHard node requirements. A node must satisfy every entry.
keystringRequiredOPERATOR_INOPERATOR_NOT_INOPERATOR_EXISTSOPERATOR_DOES_NOT_EXISTOPERATOR_GREATER_THANOPERATOR_LESS_THANvaluesrepeated stringValues to match. Empty for EXISTS and DOES_NOT_EXIST; exactly one entry for GREATER_THAN and LESS_THAN.
preferred_node_selectorsrepeated NodeSelectorRequirementSoft node preferences. Nodes satisfying more of these score higher, but none of them can make placement fail.
keystringRequiredOPERATOR_INOPERATOR_NOT_INOPERATOR_EXISTSOPERATOR_DOES_NOT_EXISTOPERATOR_GREATER_THANOPERATOR_LESS_THANvaluesrepeated stringValues to match. Empty for EXISTS and DOES_NOT_EXIST; exactly one entry for GREATER_THAN and LESS_THAN.
placement_groupstringGroup this workload belongs to, scoped to the project. Workloads sharing a group are spread out or packed together according to policy.
policyPlacementPolicyPLACEMENT_POLICY_PACKPLACEMENT_POLICY_SPREADPLACEMENT_POLICY_STRICT_SPREAD_NODEPLACEMENT_POLICY_STRICT_SPREAD_ZONEcapacity_classstringClass of capacity to draw from. Leave empty to let Plany choose, which is right for almost every workload.
disallow_preemptibleboolRefuse to place onto pre-emptible (spot) capacity. Spot is materially cheaper and fine for a dev server, but wrong for a ranked match in progress.
nodestringPin to one node by resource name. Bypasses scoring entirely; intended for debugging and for rescheduling a VM back onto the node holding its local disk.
schedulingSchedulingSpecon_host_maintenanceSchedulingSpec.OnHostMaintenanceON_HOST_MAINTENANCE_MIGRATEON_HOST_MAINTENANCE_TERMINATErestart_policySchedulingSpec.RestartPolicyRESTART_POLICY_NEVERRESTART_POLICY_ALWAYSRESTART_POLICY_ON_FAILUREpreemptibleboolRun as spot: on spare capacity, at the spot rate, reclaimable with two minutes' notice when an on-demand workload needs the room.
preemption_noticeDurationWarning given before a spot reclaim, readable at /metadata/spot/instance-action on the metadata service. The notice is always two minutes; leave this unset.
max_run_durationDurationStop the instance automatically once it has run this long. Zero means no limit. This is the guard rail that stops a forgotten dev server draining a hobby account's credit overnight.
termination_grace_periodDurationTime between the shutdown signal and a forced stop, so a game server can save its world. Zero uses the default of thirty seconds.
preemptible_fallbackboolWith preemptible: place as an ordinary on-demand workload when no spare
capacity fits, rather than waiting for some. The allocation says which
happened, and it is what the instance is billed at.
{ "cpu": { "vcpus": 0, "reserved_millis": "0", "limit_millis": "0", "architecture": "CPU_ARCHITECTURE_X86_64", "required_features": [ "" ], "dedicated_cores": false, "isolate_smt_siblings": false }, "memory": { "size_bytes": "0", "reserved_bytes": "0", "balloon_enabled": false, "hugepages": false, "hotplug_max_bytes": "0", "shared": false }, "disks": [ { "disk_id": "my-disk", "source": { "image": "" }, "size_bytes": "0", "type": "DISK_TYPE_LOCAL_NVME", "read_only": false, "boot": false, "delete_on_instance_delete": false, "io_limits": { "bandwidth_bytes_per_second": "0", "bandwidth_burst_bytes": "0", "iops": "0", "iops_burst": "0" }, "direct_io": false } ], "network_interfaces": [ { "interface_id": "my-interface", "network": "", "private_ipv4": "", "public_address_mode": "PUBLIC_ADDRESS_MODE_NONE", "tier": "NETWORK_TIER_STANDARD", "rate_limits": { "ingress_bits_per_second": "0", "egress_bits_per_second": "0", "ingress_burst_bits": "0", "egress_burst_bits": "0", "ingress_packets_per_second": "0", "egress_packets_per_second": "0" }, "mac_address": "", "multi_queue": false, "tags": [ "" ], "deny_inbound": false, "no_default_route": false } ], "placement": { "zones": [ "" ], "required_node_selectors": [ { "key": "", "operator": "OPERATOR_IN", "values": [ "" ] } ], "preferred_node_selectors": [ { "key": "", "operator": "OPERATOR_IN", "values": [ "" ] } ], "placement_group": "", "policy": "PLACEMENT_POLICY_PACK", "capacity_class": "", "disallow_preemptible": false, "node": "" }, "scheduling": { "on_host_maintenance": "ON_HOST_MAINTENANCE_MIGRATE", "restart_policy": "RESTART_POLICY_NEVER", "preemptible": false, "preemption_notice": "300s", "max_run_duration": "300s", "termination_grace_period": "300s", "preemptible_fallback": false }}Confidence says whether an event can be acted on.
| Value | Description |
|---|---|
| CONFIDENCE_UNSPECIFIED | |
| CONFIDENCE_CONFIRMED | From a promoted template. Safe to bill and to act on. |
| CONFIDENCE_PROVISIONAL | From a template still being shadowed. Observe, do not act. |
Stream identifies where a line came from.
| Value | Description |
|---|---|
| STREAM_UNSPECIFIED | |
| STREAM_STDOUT | The server's normal output. |
| STREAM_STDERR | Its error output. |
| STREAM_AGENT | The agent's own commentary — install progress, launch, shutdown. Interleaved with the server's output on purpose: "the server died" and "the agent asked it to" are much easier to correlate in one stream. |