Each scpcap invocation now starts its log fresh. Appending meant a re-run after a failed attempt mixed new output in with (or could be mistaken for) stale output from the previous run -- confusing when diagnosing exactly this kind of issue in production.
34 lines
1.2 KiB
Rust
34 lines
1.2 KiB
Rust
use std::fs::{File, OpenOptions};
|
|
use std::io::Write;
|
|
use std::path::Path;
|
|
use std::sync::Mutex;
|
|
use std::time::{SystemTime, UNIX_EPOCH};
|
|
|
|
/// Optional diagnostic trace, one timestamped line per event, for diagnosing
|
|
/// where a transfer stalls (e.g. which side is still waiting, and on what).
|
|
/// `Logger::none()` is a no-op so call sites don't need to branch on whether
|
|
/// `--log` was given.
|
|
pub struct Logger(Option<Mutex<File>>);
|
|
|
|
impl Logger {
|
|
pub fn none() -> Logger {
|
|
Logger(None)
|
|
}
|
|
|
|
/// Truncates any existing file at `path` -- each run starts a fresh
|
|
/// log, so a re-run never leaves stale lines from a previous attempt
|
|
/// mixed in with (or mistaken for) the current one.
|
|
pub fn open(path: &Path) -> std::io::Result<Logger> {
|
|
let f = OpenOptions::new().create(true).write(true).truncate(true).open(path)?;
|
|
Ok(Logger(Some(Mutex::new(f))))
|
|
}
|
|
|
|
pub fn log(&self, args: std::fmt::Arguments) {
|
|
let Some(m) = &self.0 else { return };
|
|
let now = SystemTime::now().duration_since(UNIX_EPOCH).unwrap_or_default();
|
|
if let Ok(mut f) = m.lock() {
|
|
let _ = writeln!(f, "[{:.6}] {}", now.as_secs_f64(), args);
|
|
}
|
|
}
|
|
}
|