fix: make log_msg writes atomic
Each log_msg opened the file in O_APPEND mode then used writeln!, which issues a separate write() syscall per formatting fragment. O_APPEND only guarantees atomicity per write() call, so concurrent log_msg calls from the app's many threads/tasks could interleave their fragments mid-line. Format the full line (timestamp + msg + newline) into one String, then emit it with a single write_all so each log line lands as one atomic append. No behavior change beyond non-interleaved output. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+9
-5
@@ -32,17 +32,21 @@ pub fn log_file_path() -> PathBuf {
|
||||
}
|
||||
|
||||
pub fn log_msg(msg: &str) {
|
||||
// Format the whole line into one buffer first, then emit it with a single
|
||||
// `write_all`. The file is opened with `O_APPEND`, so a lone `write()` is
|
||||
// atomic w.r.t. concurrent writers; building the line up front avoids the
|
||||
// multi-syscall `writeln!` path that would let threads interleave fragments.
|
||||
let line = match std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH) {
|
||||
Ok(time) => format!("[{}.{:03}] {}\n", time.as_secs(), time.subsec_millis(), msg),
|
||||
Err(_) => format!("{}\n", msg),
|
||||
};
|
||||
if let Ok(mut file) = std::fs::OpenOptions::new()
|
||||
.create(true)
|
||||
.append(true)
|
||||
.open(log_path())
|
||||
{
|
||||
use std::io::Write;
|
||||
if let Ok(time) = std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH) {
|
||||
let _ = writeln!(file, "[{}.{:03}] {}", time.as_secs(), time.subsec_millis(), msg);
|
||||
} else {
|
||||
let _ = writeln!(file, "{}", msg);
|
||||
}
|
||||
let _ = file.write_all(line.as_bytes());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user