near_o11y/
env_filter.rs

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