hkxc/
logger.rs

1use parse_display::{Display, FromStr};
2use serde_hkx_features::error::Result;
3use std::fs::File;
4use std::path::Path;
5use tracing::Level;
6
7/// Log level.
8#[derive(Debug, clap::ValueEnum, Clone, Copy, Default, PartialEq, Eq, Display, FromStr)]
9pub enum LogLevel {
10    #[display("trace")]
11    Trace,
12    #[display("debug")]
13    Debug,
14    #[display("info")]
15    Info,
16    #[display("warn")]
17    Warn,
18    #[default]
19    #[display("error")]
20    Error,
21}
22
23impl From<LogLevel> for Level {
24    #[inline]
25    fn from(value: LogLevel) -> Self {
26        match value {
27            LogLevel::Trace => Self::TRACE,
28            LogLevel::Debug => Self::DEBUG,
29            LogLevel::Info => Self::INFO,
30            LogLevel::Warn => Self::WARN,
31            LogLevel::Error => Self::ERROR,
32        }
33    }
34}
35
36/// Initialize loggers globally.
37///
38/// # Note
39/// - This will live until the end of the program.
40///
41/// # Panics
42/// Panics if called twice.
43pub(crate) fn init<P, L>(log_path: Option<P>, filter: L, with_stdout: bool) -> Result<()>
44where
45    P: AsRef<Path>,
46    L: Into<Level>,
47{
48    use tracing_subscriber::{fmt, layer::SubscriberExt};
49
50    if let Some(log_parent) = log_path.as_ref().and_then(|p| p.as_ref().parent()) {
51        std::fs::create_dir_all(log_parent)?;
52    }
53
54    let subscriber_builder = fmt::Subscriber::builder()
55        .compact()
56        .with_file(true)
57        .with_line_number(true)
58        .with_max_level(filter.into())
59        .with_target(false);
60
61    if with_stdout {
62        if let Some(log_path) = log_path {
63            let log_file = File::create(log_path.as_ref())?;
64
65            let log_file_config = fmt::Layer::default()
66                .compact()
67                .with_ansi(false)
68                .with_file(true)
69                .with_line_number(true)
70                .with_target(false)
71                .with_writer(log_file);
72            tracing::subscriber::set_global_default(
73                subscriber_builder.pretty().finish().with(log_file_config),
74            )?;
75        } else {
76            tracing::subscriber::set_global_default(
77                subscriber_builder
78                    .pretty()
79                    .with_ansi(true)
80                    .with_line_number(true)
81                    .with_target(false)
82                    .finish(),
83            )?;
84        }
85    } else if let Some(log_path) = log_path {
86        let log_file = File::create(log_path.as_ref())?;
87        subscriber_builder
88            .with_writer(log_file)
89            .with_ansi(false)
90            .init();
91    }
92
93    Ok(())
94}