1#![deny(clippy::pedantic)]
2#![allow(clippy::missing_errors_doc)]
3#![allow(clippy::missing_panics_doc)]
4
5use std::fs::File;
18use std::{env, io};
19
20use tracing_subscriber::layer::SubscriberExt;
21use tracing_subscriber::util::SubscriberInitExt;
22use tracing_subscriber::{EnvFilter, Layer};
23
24pub const LOG_BLOCKCHAIN: &str = "fm::net::blockchain";
25pub const LOG_CONSENSUS: &str = "fm::consensus";
26pub const LOG_CORE: &str = "fm::core";
27pub const LOG_DB: &str = "fm::db";
28pub const LOG_DEVIMINT: &str = "fm::devimint";
29pub const LOG_NET_API: &str = "fm::net::api";
30pub const LOG_NET_PEER_DKG: &str = "fm::net::peer::dkg";
31pub const LOG_NET_PEER: &str = "fm::net::peer";
32pub const LOG_NET_AUTH: &str = "fm::net::auth";
33pub const LOG_TASK: &str = "fm::task";
34pub const LOG_RUNTIME: &str = "fm::runtime";
35pub const LOG_TEST: &str = "fm::test";
36pub const LOG_TIMING: &str = "fm::timing";
37pub const LOG_CLIENT: &str = "fm::client";
38pub const LOG_CLIENT_DB: &str = "fm::client::db";
39pub const LOG_CLIENT_EVENT_LOG: &str = "fm::client::event-log";
40pub const LOG_MODULE_MINT: &str = "fm::module::mint";
41pub const LOG_MODULE_META: &str = "fm::module::meta";
42pub const LOG_MODULE_WALLET: &str = "fm::module::wallet";
43pub const LOG_CLIENT_REACTOR: &str = "fm::client::reactor";
44pub const LOG_CLIENT_NET_API: &str = "fm::client::net::api";
45pub const LOG_CLIENT_BACKUP: &str = "fm::client::backup";
46pub const LOG_CLIENT_RECOVERY: &str = "fm::client::recovery";
47pub const LOG_CLIENT_RECOVERY_MINT: &str = "fm::client::recovery::mint";
48pub const LOG_CLIENT_MODULE_META: &str = "fm::client::module::meta";
49pub const LOG_CLIENT_MODULE_MINT: &str = "fm::client::module::mint";
50pub const LOG_CLIENT_MODULE_LN: &str = "fm::client::module::ln";
51pub const LOG_CLIENT_MODULE_WALLET: &str = "fm::client::module::wallet";
52
53#[derive(Default)]
55pub struct TracingSetup {
56 base_level: Option<String>,
57 extra_directives: Option<String>,
58 #[cfg(feature = "telemetry")]
59 tokio_console_bind: Option<std::net::SocketAddr>,
60 #[cfg(feature = "telemetry")]
61 with_jaeger: bool,
62 #[cfg(feature = "telemetry")]
63 with_chrome: bool,
64 with_file: Option<File>,
65}
66
67impl TracingSetup {
68 #[cfg(feature = "telemetry")]
70 pub fn tokio_console_bind(&mut self, address: Option<std::net::SocketAddr>) -> &mut Self {
71 self.tokio_console_bind = address;
72 self
73 }
74
75 #[cfg(feature = "telemetry")]
77 pub fn with_jaeger(&mut self, enabled: bool) -> &mut Self {
78 self.with_jaeger = enabled;
79 self
80 }
81
82 #[cfg(feature = "telemetry")]
84 pub fn with_chrome(&mut self, enabled: bool) -> &mut Self {
85 self.with_chrome = enabled;
86 self
87 }
88
89 pub fn with_file(&mut self, file: Option<File>) -> &mut Self {
90 self.with_file = file;
91 self
92 }
93
94 pub fn with_base_level(&mut self, level: impl Into<String>) -> &mut Self {
98 self.base_level = Some(level.into());
99 self
100 }
101
102 pub fn with_directive(&mut self, directive: &str) -> &mut Self {
104 if let Some(old) = self.extra_directives.as_mut() {
105 *old = format!("{old},{directive}");
106 } else {
107 self.extra_directives = Some(directive.to_owned());
108 }
109 self
110 }
111
112 pub fn init(&mut self) -> anyhow::Result<()> {
114 use tracing_subscriber::fmt::writer::{BoxMakeWriter, Tee};
115
116 let var = env::var(tracing_subscriber::EnvFilter::DEFAULT_ENV).unwrap_or_default();
117 let filter_layer = EnvFilter::builder().parse(format!(
118 "{},{},{},{},{},{},{},{}",
122 self.base_level.as_deref().unwrap_or("info"),
123 "jsonrpsee_core::client::async_client=off",
124 "hyper=off",
125 "h2=off",
126 "jsonrpsee_server=warn,jsonrpsee_server::transport=off",
127 "AlephBFT-=error",
128 var,
129 self.extra_directives.as_deref().unwrap_or(""),
130 ))?;
131
132 let fmt_writer = if let Some(file) = self.with_file.take() {
133 BoxMakeWriter::new(Tee::new(io::stderr, file))
134 } else {
135 BoxMakeWriter::new(io::stderr)
136 };
137
138 let fmt_layer = tracing_subscriber::fmt::layer()
139 .with_thread_names(false) .with_writer(fmt_writer)
141 .with_filter(filter_layer);
142
143 let console_opt = || -> Option<Box<dyn Layer<_> + Send + Sync + 'static>> {
144 #[cfg(feature = "telemetry")]
145 if let Some(l) = self.tokio_console_bind {
146 let tracer = console_subscriber::ConsoleLayer::builder()
147 .retention(std::time::Duration::from_secs(60))
148 .server_addr(l)
149 .spawn()
150 .with_filter(EnvFilter::new("tokio=trace,runtime=trace"));
152 return Some(tracer.boxed());
153 }
154 None
155 };
156
157 let telemetry_layer_opt = || -> Option<Box<dyn Layer<_> + Send + Sync + 'static>> {
158 #[cfg(feature = "telemetry")]
159 if self.with_jaeger {
160 #[allow(deprecated)]
162 let tracer = opentelemetry_jaeger::new_agent_pipeline()
163 .with_service_name("fedimint")
164 .install_simple()
165 .unwrap();
166
167 return Some(tracing_opentelemetry::layer().with_tracer(tracer).boxed());
168 }
169 None
170 };
171
172 tracing_subscriber::registry()
173 .with(fmt_layer)
174 .with(console_opt())
175 .with(telemetry_layer_opt())
176 .try_init()?;
177 Ok(())
178 }
179}
180
181pub fn shutdown() {
182 #[cfg(feature = "telemetry")]
183 opentelemetry::global::shutdown_tracer_provider();
184}