mirror of
https://github.com/jmcorgan/fips.git
synced 2026-10-05 11:08:25 +00:00
The macOS package accumulated a single unbounded log file — 717 MB on a node running at debug level. Nothing rotated it, and nothing could. fips logs to stdout and leaves capture to the supervisor, which is right where the platform rotates that stream: journald does, and so does syslog under procd. launchd does not. It redirects stdout to a plain file and appends to it forever, and the usual rename-and-signal rotators cannot help, because launchd holds the descriptor and passes it as fd 1 — the daemon has no way to reopen a file rotated out from under it, and signalling it achieves nothing. Rotation therefore has to happen in the process that writes, which means the daemon has to own the file. `node.log_file` names it, and is unset by default so every platform whose supervisor already rotates keeps logging to stdout exactly as before — setting it there would only duplicate what journald and syslog hold. `node.log_rotation` (hourly/daily/never, default daily) and `node.log_max_files` (default 7) govern the roll. Both parse leniently in the same way as `node.log_level`: a typo falls back to the default rather than refusing to boot, and the resolved values are logged at startup. Rotation is by period rather than by size, so `node.log_level` is what actually governs volume — debug costs roughly an order of magnitude more per day than info. Retention bounds the rest. Writes go through a non-blocking appender, so a slow or full disk cannot stall the tick loop behind a log write. The worker guard is held for the lifetime of the daemon; dropping it would silently discard every line logged afterward. The live file carries the date the current period opened, since that is how the appender names a rolled file. Splitting the configured path on its extension rather than suffixing the whole name keeps `.log` on the end, so `/var/log/fips/fips.log` is written as `fips.2026-08-31.log`. That does mean the current file no longer has a fixed name; the packaged config carries the `tail` incantation for it. Opening the log is fatal on failure, matching how this binary treats an unusable config. A daemon that silently dropped its logging because a directory was unwritable would present as exactly the disappearing-logs problem this exists to fix. macOS packaging is the only one that turns this on. The plist stops redirecting stdout and stderr, which would otherwise reintroduce the unbounded file alongside the rotated one; the cost is that a failure before logging initialises, and a panic, now go nowhere rather than to fips.log. The setting is inserted after the `node:` key rather than appended to the shared config, which ends at a top-level `peers:` key — an appended block would land under the wrong mapping, and a second top-level `node:` would collide with the first.
38 lines
986 B
Plaintext
38 lines
986 B
Plaintext
<?xml version="1.0" encoding="UTF-8"?>
|
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
<plist version="1.0">
|
|
<dict>
|
|
<key>Label</key>
|
|
<string>com.fips.daemon</string>
|
|
|
|
<key>ProgramArguments</key>
|
|
<array>
|
|
<string>/usr/local/bin/fips</string>
|
|
<string>--config</string>
|
|
<string>/usr/local/etc/fips/fips.yaml</string>
|
|
</array>
|
|
|
|
<key>RunAtLoad</key>
|
|
<true/>
|
|
|
|
<key>KeepAlive</key>
|
|
<dict>
|
|
<key>SuccessfulExit</key>
|
|
<false/>
|
|
</dict>
|
|
|
|
<!-- The daemon owns and rotates its own log (node.log_file), because
|
|
launchd holds this descriptor and never truncates or rotates it,
|
|
and gives the daemon no way to reopen one rotated out from under
|
|
it. Redirecting here too would reintroduce the unbounded file. -->
|
|
<key>StandardOutPath</key>
|
|
<string>/dev/null</string>
|
|
|
|
<key>StandardErrorPath</key>
|
|
<string>/dev/null</string>
|
|
|
|
<key>WorkingDirectory</key>
|
|
<string>/usr/local/etc/fips</string>
|
|
</dict>
|
|
</plist>
|