# 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.