lib.rs
  1  //! Constants for categorizing the logging type
  2  //!
  3  //! To help stabilize logging targets, avoid typos and improve consistency,
  4  //! it's preferable for logging statements use static target constants,
  5  //! that we define in this module.
  6  //!
  7  //! Core + server side components should use global namespace,
  8  //! while client should generally be prefixed with `client::`.
  9  //! This makes it easier to filter interesting calls when
 10  //! running e.g. `devimint`, that will run both server and client
 11  //! side.
 12  
 13  use std::fs::File;
 14  use std::{env, io};
 15  
 16  use tracing_subscriber::layer::SubscriberExt;
 17  use tracing_subscriber::util::SubscriberInitExt;
 18  use tracing_subscriber::{EnvFilter, Layer};
 19  
 20  pub const LOG_BLOCKCHAIN: &str = "fm::net::blockchain";
 21  pub const LOG_CONSENSUS: &str = "fm::consensus";
 22  pub const LOG_CORE: &str = "fm::core";
 23  pub const LOG_DB: &str = "fm::db";
 24  pub const LOG_DEVIMINT: &str = "fm::devimint";
 25  pub const LOG_ECASH_RECOVERY: &str = "fm::ecash-recovery";
 26  pub const LOG_NET_API: &str = "fm::net::api";
 27  pub const LOG_NET_PEER_DKG: &str = "fm::net::peer::dkg";
 28  pub const LOG_NET_PEER: &str = "fm::net::peer";
 29  pub const LOG_NET: &str = "fm::net";
 30  pub const LOG_TASK: &str = "fm::task";
 31  pub const LOG_RUNTIME: &str = "fm::runtime";
 32  pub const LOG_TEST: &str = "fm::test";
 33  pub const LOG_TIMING: &str = "timing";
 34  pub const LOG_CLIENT: &str = "fm::client";
 35  pub const LOG_CLIENT_DB: &str = "fm::client::db";
 36  pub const LOG_MODULE_MINT: &str = "fm::module::mint";
 37  pub const LOG_MODULE_META: &str = "fm::module::meta";
 38  pub const LOG_MODULE_WALLET: &str = "fm::module::wallet";
 39  pub const LOG_CLIENT_REACTOR: &str = "fm::client::reactor";
 40  pub const LOG_CLIENT_NET_API: &str = "fm::client::net::api";
 41  pub const LOG_CLIENT_BACKUP: &str = "fm::client::backup";
 42  pub const LOG_CLIENT_RECOVERY: &str = "fm::client::recovery";
 43  pub const LOG_CLIENT_RECOVERY_MINT: &str = "fm::client::recovery::mint";
 44  pub const LOG_CLIENT_MODULE_META: &str = "fm::client::module::meta";
 45  pub const LOG_CLIENT_MODULE_MINT: &str = "fm::client::module::mint";
 46  pub const LOG_CLIENT_MODULE_LN: &str = "fm::client::module::ln";
 47  
 48  /// Consolidates the setup of server tracing into a helper
 49  #[derive(Default)]
 50  pub struct TracingSetup {
 51      base_level: Option<String>,
 52      extra_directives: Option<String>,
 53      #[cfg(feature = "telemetry")]
 54      tokio_console_bind: Option<std::net::SocketAddr>,
 55      #[cfg(feature = "telemetry")]
 56      with_jaeger: bool,
 57      #[cfg(feature = "telemetry")]
 58      with_chrome: bool,
 59      with_file: Option<File>,
 60  }
 61  
 62  impl TracingSetup {
 63      /// Setup a console server for tokio logging <https://docs.rs/console-subscriber>
 64      #[cfg(feature = "telemetry")]
 65      pub fn tokio_console_bind(&mut self, address: Option<std::net::SocketAddr>) -> &mut Self {
 66          self.tokio_console_bind = address;
 67          self
 68      }
 69  
 70      /// Setup telemetry through Jaeger <https://docs.rs/tracing-jaeger>
 71      #[cfg(feature = "telemetry")]
 72      pub fn with_jaeger(&mut self, enabled: bool) -> &mut Self {
 73          self.with_jaeger = enabled;
 74          self
 75      }
 76  
 77      /// Setup telemetry through Chrome <https://docs.rs/tracing-chrome>
 78      #[cfg(feature = "telemetry")]
 79      pub fn with_chrome(&mut self, enabled: bool) -> &mut Self {
 80          self.with_chrome = enabled;
 81          self
 82      }
 83  
 84      pub fn with_file(&mut self, file: Option<File>) -> &mut Self {
 85          self.with_file = file;
 86          self
 87      }
 88  
 89      /// Sets the log level applied to most modules. Some overly chatty modules
 90      /// are muted even if this is set to a lower log level, use the `RUST_LOG`
 91      /// environment variable to override.
 92      pub fn with_base_level(&mut self, level: impl Into<String>) -> &mut Self {
 93          self.base_level = Some(level.into());
 94          self
 95      }
 96  
 97      /// Add a filter directive.
 98      pub fn with_directive(&mut self, directive: &str) -> &mut Self {
 99          if let Some(old) = self.extra_directives.as_mut() {
100              *old = format!("{old},{directive}");
101          } else {
102              self.extra_directives = Some(directive.to_owned());
103          }
104          self
105      }
106  
107      /// Initialize the logging, must be called for tracing to begin
108      pub fn init(&mut self) -> anyhow::Result<()> {
109          use tracing_subscriber::fmt::writer::{BoxMakeWriter, Tee};
110  
111          let var = env::var(tracing_subscriber::EnvFilter::DEFAULT_ENV).unwrap_or_default();
112          let filter_layer = EnvFilter::builder().parse(format!(
113              // We prefix everything with a default general log level and
114              // good per-module specific default. User provided RUST_LOG
115              // can override one or both
116              "{},{},{},{},{},{}",
117              self.base_level.as_deref().unwrap_or("info"),
118              "jsonrpsee_core::client::async_client=off",
119              "jsonrpsee_server=warn,jsonrpsee_server::transport=off",
120              "AlephBFT-=error",
121              var,
122              self.extra_directives.as_deref().unwrap_or(""),
123          ))?;
124  
125          let fmt_writer = if let Some(file) = self.with_file.take() {
126              BoxMakeWriter::new(Tee::new(io::stderr, file))
127          } else {
128              BoxMakeWriter::new(io::stderr)
129          };
130  
131          let fmt_layer = tracing_subscriber::fmt::layer()
132              .with_thread_names(false) // can be enabled for debugging
133              .with_writer(fmt_writer)
134              .with_filter(filter_layer);
135  
136          let console_opt = || -> Option<Box<dyn Layer<_> + Send + Sync + 'static>> {
137              #[cfg(feature = "telemetry")]
138              if let Some(l) = self.tokio_console_bind {
139                  let tracer = console_subscriber::ConsoleLayer::builder()
140                      .retention(std::time::Duration::from_secs(60))
141                      .server_addr(l)
142                      .spawn()
143                      // tokio-console cares only about these layers, so we filter separately for it
144                      .with_filter(EnvFilter::new("tokio=trace,runtime=trace"));
145                  return Some(tracer.boxed());
146              }
147              None
148          };
149  
150          let telemetry_layer_opt = || -> Option<Box<dyn Layer<_> + Send + Sync + 'static>> {
151              #[cfg(feature = "telemetry")]
152              if self.with_jaeger {
153                  // TODO: https://github.com/fedimint/fedimint/issues/4591
154                  #[allow(deprecated)]
155                  let tracer = opentelemetry_jaeger::new_agent_pipeline()
156                      .with_service_name("fedimint")
157                      .install_simple()
158                      .unwrap();
159  
160                  return Some(tracing_opentelemetry::layer().with_tracer(tracer).boxed());
161              }
162              None
163          };
164  
165          let chrome_layer_opt = || -> Option<Box<dyn Layer<_> + Send + Sync + 'static>> {
166              #[cfg(feature = "telemetry")]
167              if self.with_chrome {
168                  let (cr_layer, guard) = tracing_chrome::ChromeLayerBuilder::new()
169                      .include_args(true)
170                      .build();
171                  // drop guard cause file to written and closed
172                  // in this case file will closed after exit of program
173                  std::mem::forget(guard);
174  
175                  return Some(cr_layer.boxed());
176              }
177              None
178          };
179  
180          tracing_subscriber::registry()
181              .with(fmt_layer)
182              .with(console_opt())
183              .with(telemetry_layer_opt())
184              .with(chrome_layer_opt())
185              .try_init()?;
186          Ok(())
187      }
188  }
189  
190  pub fn shutdown() {
191      #[cfg(feature = "telemetry")]
192      opentelemetry::global::shutdown_tracer_provider();
193  }