Krolyxon
Commit 9ff7ca4

rmptuisrclogging.rs

86 lines · 2.2 KB · Rust

1use std::{
2 fs::{self, OpenOptions},
3 io::{self, Write},
4 path::{Path, PathBuf},
5 sync::{Mutex, OnceLock},
6 time::{SystemTime, UNIX_EPOCH},
7};
8
9use crate::AppResult;
10
11static LOG_FILE: OnceLock<Mutex<fs::File>> = OnceLock::new();
12
13pub fn init(path: &Path) -> AppResult<PathBuf> {
14 if let Some(parent) = path.parent() {
15 fs::create_dir_all(parent)?;
16 }
17
18 let mut options = OpenOptions::new();
19 options.create(true).append(true);
20 #[cfg(unix)]
21 {
22 use std::os::unix::fs::OpenOptionsExt;
23 options.mode(0o600);
24 }
25 let file = options.open(path)?;
26 let _ = LOG_FILE.set(Mutex::new(file));
27
28 let panic_hook = std::panic::take_hook();
29 std::panic::set_hook(Box::new(move |panic| {
30 let message = panic
31 .payload()
32 .downcast_ref::<&str>()
33 .copied()
34 .or_else(|| panic.payload().downcast_ref::<String>().map(String::as_str))
35 .unwrap_or("non-string panic payload");
36 let location = panic
37 .location()
38 .map(|location| {
39 format!(
40 " at {}:{}:{}",
41 location.file(),
42 location.line(),
43 location.column()
44 )
45 })
46 .unwrap_or_default();
47 error(&format!("panic: {message}{location}"));
48 panic_hook(panic);
49 }));
50
51 info(&format!("logging initialized: {}", path.display()));
52 Ok(path.to_path_buf())
53}
54
55pub fn info(message: &str) {
56 write("INFO", message);
57}
58
59pub fn error(message: &str) {
60 write("ERROR", message);
61}
62
63fn write(level: &str, message: &str) {
64 let Some(file) = LOG_FILE.get() else {
65 return;
66 };
67
68 let timestamp = SystemTime::now()
69 .duration_since(UNIX_EPOCH)
70 .unwrap_or_default();
71 let line = format!(
72 "[{}.{:03}] {level} {message}",
73 timestamp.as_secs(),
74 timestamp.subsec_millis()
75 );
76 let mut file = file
77 .lock()
78 .unwrap_or_else(std::sync::PoisonError::into_inner);
79 if let Err(error) = writeln!(file, "{line}") {
80 report_write_error(error);
81 }
82}
83
84fn report_write_error(error: io::Error) {
85 eprintln!("failed to write rmptui log: {error}");
86}