Skip to main content

things3_cloud/
logging.rs

1use clap::ValueEnum;
2use std::sync::OnceLock;
3use tracing::level_filters::LevelFilter;
4use tracing_subscriber::EnvFilter;
5use tracing_subscriber::{Layer, prelude::*};
6
7#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, ValueEnum, Default)]
8#[clap(rename_all = "kebab-case")]
9pub enum LogFormat {
10    #[default]
11    Auto,
12    Pretty,
13    Simplified,
14    Json,
15}
16
17#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, ValueEnum, Default)]
18#[clap(rename_all = "kebab-case")]
19pub enum Level {
20    Error,
21    Warn,
22    #[default]
23    Info,
24    Debug,
25    Trace,
26    Off,
27}
28
29impl Level {
30    pub const fn level_filter(self) -> LevelFilter {
31        match self {
32            Self::Error => LevelFilter::ERROR,
33            Self::Warn => LevelFilter::WARN,
34            Self::Info => LevelFilter::INFO,
35            Self::Debug => LevelFilter::DEBUG,
36            Self::Trace => LevelFilter::TRACE,
37            Self::Off => LevelFilter::OFF,
38        }
39    }
40}
41
42pub fn init(log_level: Level, log_format: LogFormat, log_filter: Option<&str>) {
43    static INIT: OnceLock<()> = OnceLock::new();
44    let _ = INIT.get_or_init(|| {
45        let subscriber = tracing_subscriber::fmt::layer()
46            .with_writer(std::io::stderr)
47            .with_target(true);
48
49        let format = match (log_format, console::user_attended()) {
50            (LogFormat::Auto, true) | (LogFormat::Pretty, _) => {
51                subscriber.compact().without_time().boxed()
52            }
53            (LogFormat::Auto, false) | (LogFormat::Simplified, _) => {
54                subscriber.with_ansi(false).boxed()
55            }
56            (LogFormat::Json, _) => subscriber
57                .json()
58                .flatten_event(true)
59                .with_current_span(true)
60                .with_span_list(true)
61                .with_file(true)
62                .with_line_number(true)
63                .boxed(),
64        };
65
66        let filter = match log_filter {
67            Some(directive) => EnvFilter::builder()
68                .with_default_directive(log_level.level_filter().into())
69                .parse_lossy(directive),
70            None => EnvFilter::builder()
71                .with_default_directive(log_level.level_filter().into())
72                .from_env_lossy(),
73        };
74
75        tracing_subscriber::registry()
76            .with(format.with_filter(filter))
77            .init();
78    });
79}