Files
fips/packaging/macos/com.fips.daemon.plist
T
ArjenandJohnathan Corgan 62994c14a8 feat(logging): let the daemon own and roll its log file
The macOS package accumulated a single unbounded log file, 717 MB on a
node running at debug level. launchd redirects stdout to a plain file,
appends to it forever, and holds the descriptor itself, so the daemon
has no way to reopen a file rotated out from under it and a
rename-and-signal rotator cannot help. Rotation has to happen in the
process that writes, so the daemon has to own the file.

master already carries a size-rolling, unbuffered writer for the Windows
service (utils::logfile). Use it on every platform: the live file keeps
its name so `tail -F` follows it, rolls touch only <name>.N, and the
disk taken is bounded by size rather than by how loud a day was.

- `node.log_file` names the file. Unset by default, so platforms whose
  supervisor already rotates stdout (journald, syslog) are unchanged.
- `--log-file` overrides it and is opened before the config loads, so a
  config error is recorded too. The macOS plist passes it, because an
  upgrade keeps the existing fips.yaml.
- `node.log_max_size_mb` (default 10) and `node.log_max_files` (default
  4, clamped to 1..=100) set the limits, for the Windows service log as
  well. A roll renames every kept file with the log locked, hence the
  cap; lowering the count removes the excess on the next roll. All
  three keys skip serializing when unset, like `drain_timeout_secs`.

Writes stay synchronous and unbuffered, as stdout under launchd was, so
the line logged before a process::exit is on disk when the process ends.

Errors raised before logging is up, and panics, go to the log file, and
to stderr only when no log is open or stderr is a terminal: launchd
restarts a failing daemon every ten seconds, and the stderr file it
appends to (now fips.stderr.log rather than the log itself) is never
rolled.

The daemon writes the log as root and recreates it on every roll, so on
Unix it refuses to open the log through a symlink, and the macOS
postinstall makes /usr/local/var/log/fips root-owned in case it predates
the package.

An upgraded node's old unbounded fips.log rolls to fips.log.1 on the
first write and ages out with the rest. The launchd behaviour itself is
not covered by the Docker harness; the writer, limits and flag
precedence are unit-tested.
2026-10-06 01:22:40 +00:00

46 lines
1.4 KiB
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>
<string>--log-file</string>
<string>/usr/local/var/log/fips/fips.log</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>KeepAlive</key>
<dict>
<key>SuccessfulExit</key>
<false/>
</dict>
<!-- The daemon owns and rolls its own log (the log-file argument
above), 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. Passed as a flag rather than set in fips.yaml so that an
upgrade, which keeps the existing config, turns it on too.
stdout carries nothing once the log file is open. stderr keeps
only what is written before it opens, chiefly a failure to open
it; errors and panics after that go to the log file alone, so a
restart loop cannot grow this unrolled file. -->
<key>StandardOutPath</key>
<string>/dev/null</string>
<key>StandardErrorPath</key>
<string>/usr/local/var/log/fips/fips.stderr.log</string>
<key>WorkingDirectory</key>
<string>/usr/local/etc/fips</string>
</dict>
</plist>