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 }