ayun_logging/
lib.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
pub mod config;
mod instance;

use ayun_core::{Error, Result};
use tracing_subscriber::{
    fmt,
    fmt::{time::OffsetTime, writer::MakeWriterExt},
    layer::SubscriberExt,
    util::SubscriberInitExt,
    Layer, Registry,
};

pub struct Logger {
    config: config::Logger,
}

impl Logger {
    pub fn try_from_config(config: config::Logger) -> Result<Self, Error> {
        let mut layers: Vec<Box<dyn Layer<Registry> + Sync + Send>> = Vec::new();

        #[cfg(feature = "env-filter")]
        with_env_filter(&config, &mut layers)?;

        with_fmt_layer(&config, &mut layers)?;

        #[cfg(feature = "console")]
        with_console_layer(&config, &mut layers);

        #[cfg(feature = "error")]
        with_error_layer(&config, &mut layers);

        tracing_subscriber::registry().with(layers).init();

        Ok(Self { config })
    }

    pub fn config(self) -> config::Logger {
        self.config
    }
}

#[cfg(feature = "env-filter")]
fn with_env_filter(
    config: &config::Logger,
    layers: &mut Vec<Box<dyn Layer<Registry> + Sync + Send>>,
) -> Result<(), Error> {
    use tracing_subscriber::EnvFilter;

    const DEFAULT_ENV_FILTERS: &[&str] = &[
        "ayun",
        "opendal",
        "sea_orm_migration",
        "sqlx:query",
        "tokio::task",
        "tower",
        "tower_http",
    ];

    let env_layer = EnvFilter::try_from_default_env().or_else(|_| {
        config.env_filter.as_ref().map_or_else(
            || {
                EnvFilter::try_new(
                    DEFAULT_ENV_FILTERS
                        .iter()
                        .map(|target| format!("{}={}", target, config.level))
                        .chain(std::iter::once(format!(
                            "{}={}",
                            std::env::var("CARGO_PKG_NAME")
                                .unwrap_or(env!("CARGO_PKG_NAME").to_owned()),
                            config.level
                        )))
                        .collect::<Vec<_>>()
                        .join(","),
                )
            },
            EnvFilter::try_new,
        )
    })?;

    layers.push(Box::new(env_layer));

    Ok(())
}

fn with_fmt_layer(
    config: &config::Logger,
    layers: &mut Vec<Box<dyn Layer<Registry> + Sync + Send>>,
) -> Result<(), Error> {
    let local_offset_time = OffsetTime::local_rfc_3339().expect("could not get local time offset");

    let fmt_layer = fmt::Layer::default()
        .with_writer(std::io::stdout.with_max_level(config.level.to_owned().into()))
        .with_ansi(config.with_ansi)
        .with_timer(local_offset_time)
        .with_target(config.with_target)
        .with_file(config.with_file)
        .with_line_number(config.with_line_number)
        .with_level(config.with_level)
        .with_thread_ids(config.with_thread_ids)
        .with_thread_names(config.with_thread_names);

    let fmt_layer = match config.format {
        config::Format::Compact => fmt_layer.compact().boxed(),
        config::Format::Pretty => fmt_layer.pretty().boxed(),
        _ => fmt_layer.boxed(),
    };

    layers.push(fmt_layer);

    Ok(())
}

#[cfg(feature = "console")]
fn with_console_layer(
    _: &config::Logger,
    layers: &mut Vec<Box<dyn Layer<Registry> + Sync + Send>>,
) {
    layers.push(Box::new(console_subscriber::spawn()))
}

#[cfg(feature = "error")]
fn with_error_layer(_: &config::Logger, layers: &mut Vec<Box<dyn Layer<Registry> + Sync + Send>>) {
    layers.push(Box::new(tracing_error::ErrorLayer::default()))
}