log: send records natively to journald, keep stdout off-unit
A record written to stdout carries no priority, so journald files the whole stream at one level and the swarm log store shows `info` whatever level `tracing` gave it. Under a systemd unit the process's stdout already *is* the journal, so the fix is to speak the journal protocol directly and let each record carry its own severity. New `hive-log` crate holds the one sink chooser, called by `hive-c0re`, `hive-agent` and `swarm-controller`. It builds the same `EnvFilter` those binaries always built, then installs exactly one layer — never both, since a journald layer stacked on the `fmt` layer under a unit stores every record twice. The choice is an fstat compare, not a presence test: a child inherits `$JOURNAL_STREAM` even when its own stdout was redirected elsewhere, so the variable existing proves nothing. The crate parses `dev:inode` out of it and compares both numbers against an fstat of stdout, the descriptor the `fmt` layer writes to by default. No match, unset, or unparseable takes the `fmt` branch. A journald layer that fails to construct despite a match falls back to `fmt` and warns through it — a process must never fail to start because of its logger.
This commit is contained in:
parent
893747a0e4
commit
8cc7f90c98
12 changed files with 316 additions and 36 deletions
|
|
@ -38,6 +38,7 @@ problem_details = { version = "0.9.0", features = ["axum"] }
|
|||
# same shape `hive-c0re/src/job_queue/scheduler.rs` uses over its own graph.
|
||||
hive-jobq.workspace = true
|
||||
hive-jobq-wire.workspace = true
|
||||
hive-log.workspace = true
|
||||
# The jobq-rollup OTEL exporter, wired up in `main` via
|
||||
# `hive_jobq_metrics::spawn_exporter` — moved to its own crate (rather than
|
||||
# living here as `jobq_metrics.rs`) specifically so a future second caller
|
||||
|
|
@ -115,7 +116,6 @@ bytes.workspace = true
|
|||
http.workspace = true
|
||||
tokio.workspace = true
|
||||
tracing.workspace = true
|
||||
tracing-subscriber.workspace = true
|
||||
url.workspace = true
|
||||
utoipa.workspace = true
|
||||
utoipa-axum.workspace = true
|
||||
|
|
|
|||
|
|
@ -1669,16 +1669,7 @@ fn keep_forge_for_state(
|
|||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<()> {
|
||||
tracing_subscriber::fmt()
|
||||
.with_env_filter(
|
||||
tracing_subscriber::EnvFilter::try_from_default_env()
|
||||
.unwrap_or_else(|_| tracing_subscriber::EnvFilter::new("info")),
|
||||
)
|
||||
// This is a systemd-managed daemon — stdout always goes to journald,
|
||||
// never a human terminal, and journald doesn't strip ANSI escapes:
|
||||
// they land in victorialogs as raw byte-array spam otherwise.
|
||||
.with_ansi(false)
|
||||
.init();
|
||||
hive_log::init();
|
||||
|
||||
let path = socket_path();
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue