xecute/
logging.rs

1use std::path::PathBuf;
2
3use anyhow::Result;
4
5use config::Config;
6
7use serde::{Deserialize, Serialize};
8
9use tracing_subscriber::util::SubscriberInitExt;
10use tracing_subscriber::{EnvFilter, FmtSubscriber};
11
12const DEFAULT_TRACKED_CRATES: &[&str] = &[
13    "menmosd",
14    "amphora",
15    "xecute",
16    "rapidquery",
17    "antidns",
18    "lfan",
19    "apikit",
20    "menmos_auth",
21    "menmos_client",
22    "menmos_protocol",
23    "betterstreams",
24    "repository",
25    "menmos-std",
26    "tower_http",
27];
28
29#[cfg(debug_assertions)]
30const NORMAL_CRATE_LEVEL: &str = "debug";
31
32#[cfg(not(debug_assertions))]
33const NORMAL_CRATE_LEVEL: &str = "info";
34
35#[cfg(debug_assertions)]
36const DETAILED_CRATE_LEVEL: &str = "trace";
37
38#[cfg(not(debug_assertions))]
39const DETAILED_CRATE_LEVEL: &str = "debug";
40
41#[derive(Debug, Deserialize, Serialize)]
42#[serde(rename_all = "lowercase")]
43pub enum LogLevel {
44    Normal,
45    Detailed,
46}
47
48#[derive(Debug, Deserialize, Serialize)]
49#[serde(untagged)]
50pub enum LogStructure {
51    Preset(LogLevel),
52    Explicit(Vec<String>),
53}
54
55fn default_json() -> bool {
56    false
57}
58
59#[derive(Debug, Deserialize, Serialize)]
60pub struct LoggingConfig {
61    pub level: LogStructure,
62
63    #[serde(default = "default_json")]
64    pub json: bool,
65}
66
67impl Default for LoggingConfig {
68    fn default() -> Self {
69        Self {
70            level: LogStructure::Preset(LogLevel::Normal),
71            json: false,
72        }
73    }
74}
75
76impl LoggingConfig {
77    fn get_filter(&self) -> EnvFilter {
78        let directives = match &self.level {
79            LogStructure::Explicit(dirs) => dirs.clone(),
80            &LogStructure::Preset(LogLevel::Normal) => DEFAULT_TRACKED_CRATES
81                .iter()
82                .map(|crate_name| format!("{}={}", crate_name, NORMAL_CRATE_LEVEL))
83                .collect::<Vec<_>>(),
84            LogStructure::Preset(LogLevel::Detailed) => DEFAULT_TRACKED_CRATES
85                .iter()
86                .map(|crate_name| format!("{}={}", crate_name, DETAILED_CRATE_LEVEL))
87                .collect::<Vec<_>>(),
88        };
89
90        let joined_directives = directives.join(",");
91
92        EnvFilter::new(joined_directives)
93    }
94}
95
96fn get_logging_config(path: &Option<PathBuf>) -> Result<LoggingConfig> {
97    let mut builder = Config::builder();
98    builder = builder
99        .set_default("level", "normal")?
100        .set_default("json", false)?
101        .add_source(config::Environment::with_prefix("MENMOS_LOG"));
102
103    if let Some(path) = path {
104        builder = builder.add_source(config::File::from(path.as_ref()))
105    }
106
107    let config: LoggingConfig = builder.build()?.try_deserialize()?;
108
109    Ok(config)
110}
111
112pub fn init_logger(log_cfg_path: &Option<PathBuf>) -> Result<()> {
113    let cfg = get_logging_config(log_cfg_path)?;
114
115    let env_filter = cfg.get_filter();
116
117    if cfg.json {
118        FmtSubscriber::builder()
119            .with_env_filter(env_filter)
120            .json()
121            .finish()
122            .init();
123    } else {
124        FmtSubscriber::builder()
125            .with_env_filter(env_filter)
126            .finish()
127            .init();
128    }
129
130    Ok(())
131}