Skip to main content

tydle/
logger.rs

1use std::str::FromStr;
2
3use anyhow::anyhow;
4
5#[derive(Debug, Clone)]
6pub struct LogLevel<'a>(&'a str);
7
8impl<'a> FromStr for LogLevel<'a> {
9    type Err = anyhow::Error;
10
11    fn from_str(s: &str) -> Result<Self, Self::Err> {
12        let level = s.to_ascii_lowercase();
13
14        match level.as_str() {
15            "error" | "warn" | "info" | "debug" | "trace" => {
16                Ok(LogLevel(Box::leak(level.into_boxed_str())))
17            }
18            _ => Err(anyhow!(
19                "Invalid log level: {} (expected one of error, warn, info, debug, trace)",
20                s
21            )),
22        }
23    }
24}
25
26impl<'a> From<&'a str> for LogLevel<'a> {
27    fn from(s: &'a str) -> Self {
28        LogLevel::from_str(s).unwrap_or_else(|_| LogLevel("info"))
29    }
30}
31
32impl<'a> LogLevel<'a> {
33    fn as_str(&self) -> &str {
34        self.0
35    }
36}
37
38impl<'a> Default for LogLevel<'a> {
39    fn default() -> Self {
40        LogLevel("info")
41    }
42}
43
44#[cfg(feature = "logging")]
45pub fn init_logging<L>(level: L)
46where
47    L: Into<LogLevel<'static>>,
48{
49    use std::sync::Once;
50    static INIT: Once = Once::new();
51    let level = level.into();
52
53    INIT.call_once(|| {
54        let level_str = level.as_str();
55        unsafe { std::env::set_var("RUST_LOG", format!("tydle={}", level_str)) };
56
57        env_logger::init();
58        #[cfg(feature = "logging")]
59        log::info!("Logging initialized at level: {}", level_str);
60    });
61}
62
63#[cfg(not(feature = "logging"))]
64pub fn init_logging(_: Option<&str>) {}