Backend logging: stderr + configurable rotating file

Add configure_logging() (main.py): always logs to stderr, plus a rotating
file when PIRATS_LOG_FILE is set; level from PIRATS_LOG_LEVEL (default INFO).
Called from both the CLI entrypoint and the app lifespan (idempotent), which
also logs startup/migration/shutdown.

Targeted server-side events for ops/debugging (not every game event): game
created, player joined, player removed (kick/leave), game ended.

NixOS service: new logFile (/var/log/pirats/pirats.log) and logLevel options,
wired to the env vars; LogsDirectory=pirats makes the path writable under the
sandboxed DynamicUser. README documents the env vars/options.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-15 15:42:06 -07:00
parent b1a559cf39
commit 5e9f9bfb13
8 changed files with 107 additions and 3 deletions

View File

@@ -112,6 +112,22 @@
default = "/var/lib/pirats/rats_with_gats.db";
description = "Path to the SQLite database file.";
};
logFile = lib.mkOption {
type = lib.types.str;
default = "/var/log/pirats/pirats.log";
description = ''
Path to the server log file (rotating, 10 MB x 5 backups). stderr is
also captured by the systemd journal. The default lives under the
service's LogsDirectory (/var/log/pirats), which the sandboxed
DynamicUser can write to; a custom path elsewhere must be made
writable by the service separately.
'';
};
logLevel = lib.mkOption {
type = lib.types.enum [ "debug" "info" "warning" "error" "critical" ];
default = "info";
description = "Minimum severity of log messages to record.";
};
openFirewall = lib.mkOption {
type = lib.types.bool;
default = false;
@@ -137,15 +153,21 @@
# Unset means "local checkout" and defaults Dev Mode on, so the
# service must always set it explicitly.
PIRATS_DEV_MODE = lib.boolToString cfg.devModeDefault;
PIRATS_LOG_FILE = cfg.logFile;
PIRATS_LOG_LEVEL = cfg.logLevel;
};
serviceConfig = {
ExecStart = "${cfg.package}/bin/pirats --host ${cfg.host} --port ${toString cfg.port}";
Restart = "always";
# Sandboxing and security
DynamicUser = true;
StateDirectory = "pirats";
# Creates /var/log/pirats owned by the dynamic user and adds it to
# ReadWritePaths, so the default logFile under it is writable
# despite ProtectSystem=strict.
LogsDirectory = "pirats";
WorkingDirectory = "/var/lib/pirats";
ProtectSystem = "strict";