You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This issue is implemented in the fresh MIT-licensed Go server under the replacement program. Its gameplay and content-design decisions remain authoritative. C, CPython, classic packet, file-path, and enum details in the preserved specification are historical evidence only; do not copy, translate, or structurally port GPL implementation code.
Replacement implementation contract
Use Go slog, OpenTelemetry, Prometheus/OpenMetrics, and optional pprof, with bounded labels and explicit privacy rules. Keep operational telemetry separate from durable gameplay metrics.
The server remains authoritative, consumes versioned compiled content, and exposes bounded generated Game Protocol 1 messages. Pure rules may use a specifically approved typed CEL environment. Starlark is not part of this issue unless the separate residual-scripting decision explicitly approves it.
Required verification
Preserve every observable rule, balance decision, disclosure boundary, and anti-exploit invariant from the specification below.
Add deterministic Go unit/property tests and wrapper-managed scenario coverage at the appropriate integration boundary.
Add bounded malformed-input and persistence-failure cases where this feature accepts content, network, or stored data.
Add Go/Rust protocol conformance fixtures for every new cross-process field; the client must not reconstruct authoritative rules from prose.
Demonstrate that implementation and tests contain no copied GPL source/test material and execute no runtime Python.
Preserved product/design specification and historical implementation notes
Summary
Replace the old idea of splitting one text log by prefixes (#29) with a deployable, structured observability foundation for the game server and shared networking code.
Atrinik already has timestamped severity-filtered logging in common/toolkit/logger.c, synchronous stdout/file sinks, connection diagnostic IDs, and scattered counters. The proposal should preserve simple local operation while adding stable event fields, bounded runtime metrics, correlation, health diagnostics, and export paths suitable for containers and external tooling.
Gameplay progression metrics in #33 remain authoritative saved player state. Observability data is operational and must never become a gameplay dependency.
Goals
Make logs machine-readable without losing useful human console output.
Correlate a connection/session, packet flow, player lifecycle, map load, save, plugin call, and error without logging secrets.
Expose bounded counters, gauges, and histograms for server health and performance.
Measure important spans and tick latency without requiring a full distributed-tracing service.
Use stdout as the default production sink and let deployment tooling own rotation/retention.
Keep hot gameplay/network paths bounded and non-blocking.
Structured event API
Extend the logger with a typed event entry point while retaining LOG() as a migration wrapper. Each structured record should have a versioned schema containing:
UTC timestamp and monotonic/process elapsed value from the time-service proposal;
severity, subsystem, stable event name, source location, and message;
a bounded list of typed string/integer/boolean fields.
Emit JSON Lines for machine output and retain a human formatter for development. Escape and bound every field. Stable event names are contracts; prose messages are not.
Never log passwords, salts, authentication tokens, join passwords, private keys, packet payloads containing credentials, or unrestricted chat/dialog contents. Network addresses and account/character identifiers need explicit privacy classification and configurable redaction.
Metrics registry
Add a small in-process registry for named operational metrics:
Names, units, labels, and cardinality limits must be registered centrally. Labels may use bounded enums such as command kind or result, never player names, map paths, arbitrary object names, or error strings.
Updates on hot paths should be constant-time. Snapshot/export work must use a bounded per-tick budget.
Export and operator surfaces
Provide three layers:
JSON logs to stdout, with optional human text and file sinks for development.
A privileged in-game/server-console diagnostics command for concise current health and targeted connection/session correlation.
An optional localhost-only health/metrics exporter or sidecar-friendly snapshot using Prometheus/OpenMetrics text.
Do not make the single-threaded game loop serve arbitrary remote HTTP work. If an embedded exporter is used, it must be local-only, authenticated where appropriate, bounded, and fed from immutable snapshots. A sidecar may handle remote access, TLS, dashboards, retention, and alert delivery.
Readiness should mean startup resources/plugins/listeners are usable; liveness should detect a stalled main loop without declaring ordinary game inactivity unhealthy.
Lightweight tracing and profiling
Add span helpers that record start/end monotonic duration and correlation IDs for:
Sample routine successful spans and always retain bounded summaries for errors/slow thresholds. Do not allocate an unbounded trace tree or block on export.
Operational event audit
Define a separately classified audit stream for privileged commands, bans, authentication/security outcomes, and destructive administrative actions. Give it explicit access and retention expectations. Do not mix security records into #33 gameplay metrics or public dashboards.
Migration plan
Specify schemas, field bounds, redaction, cardinality, and event naming.
Add structured logger/events and JSON stdout alongside current human output.
Add the metrics registry, snapshots, and operator health command.
Instrument main loop, sockets/QUIC, authentication, maps, saves, and plugins.
Add local health/metrics export and example container/dashboard configuration.
Migrate high-value LOG() calls; leave low-value prose on the compatibility wrapper until classified.
Remove dependence on split prefix files and document external rotation/retention.
Acceptance criteria
JSON log records are valid, versioned, bounded, and include stable severity/subsystem/event fields.
Human console output remains available for local development.
Secrets and high-cardinality player/content text are excluded or explicitly redacted.
Metrics have registered names/units/labels and enforce cardinality limits.
Tick, connection, packet/queue, map, save, plugin, and QUIC health are observable.
Slow/stalled exporters cannot block the game loop or grow memory without limit.
Liveness/readiness and privileged diagnostics have documented semantics.
Operational/security audit events have a separate classification and retention model.
Container deployments can use stdout plus a standard metrics scraper without server-specific log splitting.
Unit-test JSON escaping/schema, field truncation, redaction, cardinality rejection, counter overflow, histogram boundaries, snapshot consistency, exporter backpressure, and wall-clock changes. Stress log/metric volume while measuring tick time and memory. Add integration tests for connection IDs across handshake/login/disconnect and for slow map/plugin/save spans.
Important
This issue is implemented in the fresh MIT-licensed Go server under the replacement program. Its gameplay and content-design decisions remain authoritative. C, CPython, classic packet, file-path, and enum details in the preserved specification are historical evidence only; do not copy, translate, or structurally port GPL implementation code.
Replacement implementation contract
Use Go
slog, OpenTelemetry, Prometheus/OpenMetrics, and optionalpprof, with bounded labels and explicit privacy rules. Keep operational telemetry separate from durable gameplay metrics.The server remains authoritative, consumes versioned compiled content, and exposes bounded generated Game Protocol 1 messages. Pure rules may use a specifically approved typed CEL environment. Starlark is not part of this issue unless the separate residual-scripting decision explicitly approves it.
Required verification
Preserved product/design specification and historical implementation notes
Summary
Replace the old idea of splitting one text log by prefixes (#29) with a deployable, structured observability foundation for the game server and shared networking code.
Atrinik already has timestamped severity-filtered logging in common/toolkit/logger.c, synchronous stdout/file sinks, connection diagnostic IDs, and scattered counters. The proposal should preserve simple local operation while adding stable event fields, bounded runtime metrics, correlation, health diagnostics, and export paths suitable for containers and external tooling.
Gameplay progression metrics in #33 remain authoritative saved player state. Observability data is operational and must never become a gameplay dependency.
Goals
Structured event API
Extend the logger with a typed event entry point while retaining LOG() as a migration wrapper. Each structured record should have a versioned schema containing:
Emit JSON Lines for machine output and retain a human formatter for development. Escape and bound every field. Stable event names are contracts; prose messages are not.
Never log passwords, salts, authentication tokens, join passwords, private keys, packet payloads containing credentials, or unrestricted chat/dialog contents. Network addresses and account/character identifiers need explicit privacy classification and configurable redaction.
Metrics registry
Add a small in-process registry for named operational metrics:
Names, units, labels, and cardinality limits must be registered centrally. Labels may use bounded enums such as command kind or result, never player names, map paths, arbitrary object names, or error strings.
Updates on hot paths should be constant-time. Snapshot/export work must use a bounded per-tick budget.
Export and operator surfaces
Provide three layers:
Do not make the single-threaded game loop serve arbitrary remote HTTP work. If an embedded exporter is used, it must be local-only, authenticated where appropriate, bounded, and fed from immutable snapshots. A sidecar may handle remote access, TLS, dashboards, retention, and alert delivery.
Readiness should mean startup resources/plugins/listeners are usable; liveness should detect a stalled main loop without declaring ordinary game inactivity unhealthy.
Lightweight tracing and profiling
Add span helpers that record start/end monotonic duration and correlation IDs for:
Sample routine successful spans and always retain bounded summaries for errors/slow thresholds. Do not allocate an unbounded trace tree or block on export.
Operational event audit
Define a separately classified audit stream for privileged commands, bans, authentication/security outcomes, and destructive administrative actions. Give it explicit access and retention expectations. Do not mix security records into #33 gameplay metrics or public dashboards.
Migration plan
Acceptance criteria
Validation
Unit-test JSON escaping/schema, field truncation, redaction, cardinality rejection, counter overflow, histogram boundaries, snapshot consistency, exporter backpressure, and wall-clock changes. Stress log/metric volume while measuring tick time and memory. Add integration tests for connection IDs across handshake/login/disconnect and for slow map/plugin/save spans.
Supersedes atrinik/atrinik#29. Related: atrinik/atrinik#105, #33, #32, atrinik/atrinik#126 and the deterministic server time proposal.