Krolyxon
Commit a3a311f

rmptuisrclogging.rs

58 lines · 1.6 KB · Rust

1//! File logging. The terminal belongs to the UI, so diagnostics go to a file.
2
3use std::{
4 fs::OpenOptions,
5 io,
6 path::Path,
7 sync::{Arc, Mutex},
8};
9
10use tracing_subscriber::{EnvFilter, fmt};
11
12pub const LOG_PATH: &str = "/tmp/rmptui.log";
13
14/// Appends logs to `path`. The level can be set with `RMPTUI_LOG`
15/// (e.g. `RMPTUI_LOG=debug`); the default is `info`.
16pub fn init(path: &Path) -> io::Result<()> {
17 let mut options = OpenOptions::new();
18 options.create(true).append(true);
19 #[cfg(unix)]
20 {
21 use std::os::unix::fs::OpenOptionsExt;
22 options.mode(0o600);
23 }
24 let file = Arc::new(Mutex::new(options.open(path)?));
25 let filter = EnvFilter::try_from_env("RMPTUI_LOG").unwrap_or_else(|_| EnvFilter::new("info"));
26 fmt()
27 .with_env_filter(filter)
28 .with_ansi(false)
29 .with_writer(move || MutexWriter(Arc::clone(&file)))
30 .try_init()
31 .map_err(io::Error::other)?;
32
33 // Record panics in the log as well as on the (restored) terminal.
34 let previous = std::panic::take_hook();
35 std::panic::set_hook(Box::new(move |info| {
36 tracing::error!("panic: {info}");
37 previous(info);
38 }));
39 Ok(())
40}
41
42struct MutexWriter(Arc<Mutex<std::fs::File>>);
43
44impl io::Write for MutexWriter {
45 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
46 self.0
47 .lock()
48 .unwrap_or_else(std::sync::PoisonError::into_inner)
49 .write(buf)
50 }
51
52 fn flush(&mut self) -> io::Result<()> {
53 self.0
54 .lock()
55 .unwrap_or_else(std::sync::PoisonError::into_inner)
56 .flush()
57 }
58}