Krolyxon
Commit 828a2c7

Branches

Refs →

budctlcratesbudctl-guisrclog.rs

60 lines · 1.9 KB · Rust

1//! `~/.local/state/budctl/gui.log`: errors and session events (connected, each write and its
2//! answer, closed), so a "Try again" can be explained after the fact even when the window was
3//! started from a launcher and stderr went nowhere. Each launch starts the file afresh.
4//!
5//! Lines start with the seconds since launch, like `--debug` output. Frames are not logged;
6//! `--debug` still hex-dumps them on stderr.
7
8use std::fs::{self, File};
9use std::io::Write;
10use std::path::{Path, PathBuf};
11use std::sync::{Mutex, OnceLock};
12use std::time::{Instant, SystemTime, UNIX_EPOCH};
13
14struct Log {
15 file: Mutex<File>,
16 started: Instant,
17}
18
19static LOG: OnceLock<Log> = OnceLock::new();
20
21/// `gui.log` in budctl's state directory.
22pub fn file() -> Option<PathBuf> {
23 budctl_core::config::state_dir().map(|dir| dir.join("gui.log"))
24}
25
26/// Start the log at `path`, replacing the last launch's. Until this runs, and if it fails,
27/// [`line`] does nothing.
28pub fn start(path: &Path) -> std::io::Result<()> {
29 if let Some(dir) = path.parent() {
30 fs::create_dir_all(dir)?;
31 }
32 let mut file = File::create(path)?;
33 let since_epoch = SystemTime::now()
34 .duration_since(UNIX_EPOCH)
35 .map(|d| d.as_secs())
36 .unwrap_or_default();
37 writeln!(
38 file,
39 "budctl-gui {} started (unix time {since_epoch}, pid {})",
40 env!("CARGO_PKG_VERSION"),
41 std::process::id()
42 )?;
43 let _ = LOG.set(Log {
44 file: Mutex::new(file),
45 started: Instant::now(),
46 });
47 Ok(())
48}
49
50/// Add a line to the log, if it is open.
51pub fn line(message: impl AsRef<str>) {
52 let Some(log) = LOG.get() else {
53 return;
54 };
55 let elapsed = log.started.elapsed().as_secs_f64();
56 if let Ok(mut file) = log.file.lock() {
57 // A log that cannot be written must not take the window down with it.
58 let _ = writeln!(file, "{elapsed:>9.3} {}", message.as_ref());
59 }
60}