Skip to main content

ringo_core/
log.rs

1use std::fs::{File, OpenOptions};
2use std::io::Write;
3use std::sync::{Mutex, OnceLock};
4
5static LOG_FILE: OnceLock<Mutex<File>> = OnceLock::new();
6
7#[derive(Debug, Clone, Copy)]
8pub enum Level {
9    Error,
10    Warn,
11    Info,
12    Debug,
13}
14
15impl Level {
16    fn as_str(self) -> &'static str {
17        match self {
18            Self::Error => "ERROR",
19            Self::Warn => "WARN",
20            Self::Info => "INFO",
21            Self::Debug => "DEBUG",
22        }
23    }
24}
25
26/// Open (or create) `/tmp/ringo-{profile}.log` in append mode.
27/// Safe to call multiple times — only the first call takes effect.
28pub fn init(profile_name: &str) {
29    let path = format!("/tmp/ringo-{}.log", profile_name);
30    let _ = LOG_FILE.set(
31        OpenOptions::new()
32            .create(true)
33            .append(true)
34            .open(path)
35            .map(Mutex::new)
36            .expect("failed to open ringo log file"),
37    );
38}
39
40/// Write a single log line. No-op before `init()` is called.
41pub fn write(level: Level, msg: &str) {
42    if let Some(mtx) = LOG_FILE.get() {
43        if let Ok(mut f) = mtx.lock() {
44            let ts = chrono::Local::now().format("%Y-%m-%d %H:%M:%S");
45            let _ = writeln!(f, "[{}] {}: {}", ts, level.as_str(), msg);
46        }
47    }
48}
49
50/// Log with `format!`-style syntax. No-op before `init()`.
51///
52/// Usage: `rlog!(info, "baresip pid={}", pid);`
53#[macro_export]
54macro_rules! rlog {
55    ($level:ident, $($arg:tt)+) => {
56        $crate::log::write($crate::log::Level::$level, &format!($($arg)+))
57    };
58}