From b557c9887f06b6429b77e81e4972538567db36ad Mon Sep 17 00:00:00 2001 From: reverse Date: Wed, 19 Aug 2026 01:28:42 +0000 Subject: [PATCH] =?UTF-8?q?log=5Fjson:=20cache=20an=20open=20failure=20so?= =?UTF-8?q?=20a=20misconfigured=20path=20doesn't=20re-issue=20an=20open()?= =?UTF-8?q?=20syscall=20(and=20silently=20drop)=20on=20every=20notice=20?= =?UTF-8?q?=E2=80=94=20the=20error=20is=20now=20surfaced=20once=20via=20st?= =?UTF-8?q?derr=20and=20not=20retried=20until=20the=20path=20changes;=20th?= =?UTF-8?q?e=20write-failure=20reopen=20(for=20logrotate)=20is=20preserved?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/modules/log_json.rs | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/src/modules/log_json.rs b/src/modules/log_json.rs index cd4d7ad..2541c6a 100644 --- a/src/modules/log_json.rs +++ b/src/modules/log_json.rs @@ -11,8 +11,10 @@ use std::io::Write; use crate::server::Server; thread_local! { - /// (configured path, open append handle) cached for reuse. - static SINK: RefCell> = const { RefCell::new(None) }; + /// (configured path, open append handle or `None` if opening it failed) cached + /// for reuse. Caching the failure stops us re-issuing an `open` syscall — and a + /// silent drop — on every single notice when the path is misconfigured. + static SINK: RefCell)>> = const { RefCell::new(None) }; } /// Append `msg` as a JSON line to the configured log file. Called at the tail of @@ -30,16 +32,19 @@ pub fn tee(s: &Server, msg: &str) { None => true, }; if need_open { - *slot = OpenOptions::new() - .create(true) - .append(true) - .open(path) - .ok() - .map(|f| (path.to_string(), f)); + match OpenOptions::new().create(true).append(true).open(path) { + Ok(f) => *slot = Some((path.to_string(), Some(f))), + Err(e) => { + // surface once (this branch only runs when the path changes), + // then remember the failure so we don't retry every notice + eprintln!("echoircd: log_json cannot open {path}: {e}"); + *slot = Some((path.to_string(), None)); + } + } } - if let Some((_, f)) = slot.as_mut() { + if let Some((_, Some(f))) = slot.as_mut() { if writeln!(f, "{line}").is_err() { - *slot = None; // reopen next time + *slot = None; // reopen next time (e.g. after a logrotate rename) } } });