hive-log

One shared log-sink chooser for the hyperhive daemons: hive_log::init() builds the EnvFilter every binary built before, then installs exactly one sink.

Why one sink and not both

Under a systemd unit the process's stdout already is the journal. Adding a journald layer on top of the fmt layer therefore stores every record twice — once as the native journal entry, once as the text line fmt wrote to a descriptor that leads to the same journal.

Writing to stdout also throws the severity away. A stdout line carries no priority field, so journald files the whole stream at one level and the swarm log store shows info whatever level tracing gave the record. Logging natively carries the level across. That is the reason to prefer journald where a journal exists, and the reason never to run both layers.

How the choice happens

systemd sets $JOURNAL_STREAM to the device and inode numbers of the journal-connected descriptor, in decimal, separated by a colon.

Checking that the variable exists is not enough. A child process inherits $JOURNAL_STREAM from its parent even when the parent redirected that child's stdout somewhere else, so presence alone reports a journal that the process does not actually write to. hive-log instead stats stdout — the descriptor the fmt layer writes to by default, and the one a journald layer would double up on — and compares both numbers against the parsed pair.

A match installs the native journald layer alone. No match, an unset variable, or a value that does not parse installs the fmt layer alone.

When the journald layer fails to build

tracing_journald::layer() validates the journal socket up front and returns an io::Result, so a missing journal surfaces as an error rather than a silent no-op. On that error hive-log installs the fmt layer and emits one warning through it. A process must never fail to start because of its logger, and a logger that drops every record in silence is worse than a degraded one that says so.

Scope

The sink chooser and its tests. Nothing else belongs here: the crate exists so three binaries share one copy of this decision, not as a place for general utilities.