Watch
0
0
Fork
You've already forked hyperhive
0

hive-c0re, hive-priv: demote three routine, non-actionable log sites

This commit is contained in:
damocles 2026-10-07 23:50:36 +02:00 • committed by mara
commit 25893d0f95
3 changed files with 46 additions and 3 deletions

View file

@ -806,7 +806,11 @@ pub async fn prebuild_toplevel(name: &str, flake_ref: &str, node_id: Option<u64>
let pump_stderr = tokio::spawn(async move { let pump_stderr = tokio::spawn(async move {
let mut lines = BufReader::new(stderr).lines(); let mut lines = BufReader::new(stderr).lines();
while let Ok(Some(line)) = lines.next_line().await { while let Ok(Some(line)) = lines.next_line().await {
tracing::warn!(target: "nix-prebuild", cmdline = %stderr_cmdline, "{line}"); if is_real_nix_warning(&line) {
tracing::warn!(target: "nix-prebuild", cmdline = %stderr_cmdline, "{line}");
} else {
tracing::info!(target: "nix-prebuild", cmdline = %stderr_cmdline, "{line}");
}
if let (Some(h), Some(id)) = (&stderr_logs, log_id) { if let (Some(h), Some(id)) = (&stderr_logs, log_id) {
h.append_stderr(id, &line); h.append_stderr(id, &line);
} }
@ -889,6 +893,15 @@ pub fn ensure_agent_runtime_dir(name: &str) -> Result<()> {
.with_context(|| format!("create agent runtime dir {}", dir.display())) .with_context(|| format!("create agent runtime dir {}", dir.display()))
} }
/// Whether a `nix`/`nixos-container` stderr line is an actual warning
/// (nix's own convention: a genuine warning starts with `warning:`) rather
/// than routine progress chatter (`copying N paths…`, `fetching git
/// input…`, `structuredAttrs is enabled`, …) — nix writes the latter to
/// stderr too, and it dwarfs the former in volume.
fn is_real_nix_warning(line: &str) -> bool {
line.trim_start().starts_with("warning:")
}
/// Build the per-line callback for `create_container_streaming` / /// Build the per-line callback for `create_container_streaming` /
/// `update_container_streaming`. Both ops share identical dispatch logic /// `update_container_streaming`. Both ops share identical dispatch logic
/// (stdout → info + `append_stdout`, stderr → warn + `append_stderr`); this /// (stdout → info + `append_stdout`, stderr → warn + `append_stderr`); this
@ -907,7 +920,11 @@ fn make_log_callback(
} }
} }
PrivStream::Stderr => { PrivStream::Stderr => {
tracing::warn!(target: "nixos-container", cmdline = %cmdline, "{line}"); if is_real_nix_warning(line) {
tracing::warn!(target: "nixos-container", cmdline = %cmdline, "{line}");
} else {
tracing::info!(target: "nixos-container", cmdline = %cmdline, "{line}");
}
if let (Some(h), Some(id)) = (&logs, log_id) { if let (Some(h), Some(id)) = (&logs, log_id) {
h.append_stderr(id, line); h.append_stderr(id, line);
} }

View file

@ -58,7 +58,15 @@ pub fn start(agent: &str, socket_path: &Path, coord: Arc<Coordinator>) -> Result
let coord = coord.clone(); let coord = coord.clone();
tokio::spawn(async move { tokio::spawn(async move {
if let Err(e) = serve(stream, agent, coord).await { if let Err(e) = serve(stream, agent, coord).await {
tracing::warn!(error = ?e, "agent connection failed"); // A peer closing its end mid-read/write (the harness
// process exiting, a turn ending) is routine and the
// overwhelming majority of what reaches here —
// demoted so it doesn't bury a genuine failure.
if is_broken_pipe(&e) {
tracing::debug!(error = ?e, "agent connection closed by peer");
} else {
tracing::warn!(error = ?e, "agent connection failed");
}
} }
}); });
}, },
@ -201,6 +209,18 @@ async fn read_request_line<R: AsyncBufRead + Unpin>(
}) })
} }
/// Whether `e`'s root cause is the peer closing the connection — `serve`'s
/// own `?`s convert a raw `std::io::Error` straight to `anyhow::Error` with
/// no intervening `.context()`, so a direct downcast reaches it.
fn is_broken_pipe(e: &anyhow::Error) -> bool {
e.downcast_ref::<std::io::Error>().is_some_and(|io_err| {
matches!(
io_err.kind(),
std::io::ErrorKind::BrokenPipe | std::io::ErrorKind::ConnectionReset
)
})
}
/// Answer each request line on `stream` until EOF. An over-long line gets a /// Answer each request line on `stream` until EOF. An over-long line gets a
/// `Response::Err` and then the connection is closed, because the rest of the /// `Response::Err` and then the connection is closed, because the rest of the
/// line is still unread. /// line is still unread.

View file

@ -491,8 +491,14 @@ async fn exec(
async fn start_container(name: &str) -> Result<(String, String)> { async fn start_container(name: &str) -> Result<(String, String)> {
validate_agent_name(name)?; validate_agent_name(name)?;
let machine = container_system_name(name); let machine = container_system_name(name);
// Silenced: a first-time create means the unit doesn't exist yet, and
// `systemctl`'s own "Unit ... not loaded" complaint for that case would
// otherwise land in the journal at error priority on every such start —
// routine, not a signal, since the result is already discarded below.
let _ = Command::new("systemctl") let _ = Command::new("systemctl")
.args(["reset-failed", &format!("container@{machine}.service")]) .args(["reset-failed", &format!("container@{machine}.service")])
.stdout(std::process::Stdio::null())
.stderr(std::process::Stdio::null())
.status() .status()
.await; .await;
container_run(&["start", &machine]).await container_run(&["start", &machine]).await