unc_o11y/
env_filter.rs

1use std::borrow::Cow;
2use tracing_subscriber::filter::ParseError;
3use tracing_subscriber::EnvFilter;
4
5/// The default value for the `RUST_LOG` environment variable if one isn't specified otherwise.
6const DEFAULT_RUST_LOG: &str = "tokio_reactor=info,\
7     config=info,\
8     unc=info,\
9     recompress=info,\
10     stats=info,\
11     telemetry=info,\
12     db=info,\
13     delay_detector=info,\
14     unc-performance-metrics=info,\
15     state_viewer=info,\
16     warn";
17
18#[non_exhaustive]
19#[derive(thiserror::Error, Debug)]
20pub enum BuildEnvFilterError {
21    #[error("could not create a log filter for {1}")]
22    CreateEnvFilter(#[source] ParseError, String),
23}
24
25#[derive(Debug)]
26pub struct EnvFilterBuilder<'a> {
27    rust_log: Cow<'a, str>,
28    verbose: Option<&'a str>,
29}
30
31impl<'a> EnvFilterBuilder<'a> {
32    /// Create the `EnvFilter` from the environment variable or the [`DEFAULT_RUST_LOG`] value if
33    /// the environment is not set.
34    pub fn from_env() -> Self {
35        Self::new(
36            std::env::var("RUST_LOG").map(Cow::Owned).unwrap_or(Cow::Borrowed(DEFAULT_RUST_LOG)),
37        )
38    }
39
40    /// Specify an exact `RUST_LOG` value to use.
41    ///
42    /// This method will not inspect the environment variable.
43    pub fn new<S: Into<Cow<'a, str>>>(rust_log: S) -> Self {
44        Self { rust_log: rust_log.into(), verbose: None }
45    }
46
47    /// Make the produced [`EnvFilter`] verbose.
48    ///
49    /// If the `module` string is empty, all targets will log debug output. Otherwise only the
50    /// specified target will log the debug output.
51    pub fn verbose(mut self, target: Option<&'a str>) -> Self {
52        self.verbose = target;
53        self
54    }
55
56    /// Construct an [`EnvFilter`] as configured.
57    pub fn finish(self) -> Result<EnvFilter, BuildEnvFilterError> {
58        let mut env_filter = EnvFilter::try_new(self.rust_log.clone())
59            .map_err(|err| BuildEnvFilterError::CreateEnvFilter(err, self.rust_log.to_string()))?;
60        if let Some(module) = self.verbose {
61            env_filter = env_filter
62                .add_directive("cranelift_codegen=warn".parse().expect("parse directive"))
63                .add_directive("h2=warn".parse().expect("parse directive"))
64                .add_directive("tower=warn".parse().expect("parse directive"))
65                .add_directive("trust_dns_resolver=warn".parse().expect("parse directive"))
66                .add_directive("trust_dns_proto=warn".parse().expect("parse directive"));
67            env_filter = if module.is_empty() {
68                env_filter.add_directive(tracing::Level::DEBUG.into())
69            } else {
70                let directive = format!("{}=debug", module).parse().map_err(|err| {
71                    BuildEnvFilterError::CreateEnvFilter(err, format!("{}=debug", module))
72                })?;
73                env_filter.add_directive(directive)
74            };
75        }
76        Ok(env_filter)
77    }
78}
79
80pub fn make_env_filter(verbose: Option<&str>) -> Result<EnvFilter, BuildEnvFilterError> {
81    let env_filter = EnvFilterBuilder::from_env().verbose(verbose).finish()?;
82    // Sandbox node can log to sandbox logging target via sandbox_debug_log host function.
83    // This is hidden by default so we enable it for sandbox node.
84    let env_filter = if cfg!(feature = "sandbox") {
85        env_filter.add_directive("sandbox=debug".parse().unwrap())
86    } else {
87        env_filter
88    };
89    Ok(env_filter)
90}