forest/cli_shared/logger/
mod.rs1use std::pin::Pin;
5
6use futures::Future;
7use tracing_subscriber::{EnvFilter, Registry, prelude::*};
8
9use crate::cli_shared::cli::CliOpts;
10use crate::utils::misc::LoggingColor;
11
12type BackgroundTask = Pin<Box<dyn Future<Output = ()> + Send>>;
13
14#[derive(Default)]
15pub struct Guards {
16 #[cfg(feature = "tracing-chrome")]
17 tracing_chrome: Option<tracing_chrome::FlushGuard>,
18}
19
20#[allow(unused_mut)]
21pub fn setup_logger(opts: &CliOpts) -> (Vec<BackgroundTask>, Guards) {
22 let mut background_tasks: Vec<BackgroundTask> = vec![];
23 let mut guards = Guards::default();
24 let mut layers: Vec<Box<dyn tracing_subscriber::layer::Layer<Registry> + Send + Sync>> =
25 vec![Box::new(
27 tracing_subscriber::fmt::Layer::new()
28 .with_ansi(opts.color.coloring_enabled())
29 .with_filter(get_env_filter(default_env_filter())),
30 )];
31
32 if let Some(log_dir) = &opts.log_dir {
34 let file_appender = tracing_appender::rolling::hourly(log_dir, "forest.log");
35 layers.push(Box::new(
36 tracing_subscriber::fmt::Layer::new()
37 .with_ansi(false)
38 .with_writer(file_appender)
39 .with_filter(get_env_filter(default_env_filter())),
40 ));
41 }
42
43 if opts.tokio_console {
44 #[cfg(not(feature = "tokio-console"))]
45 tracing::warn!(
46 "`tokio-console` is unavailable, forest binaries need to be recompiled with `tokio-console` feature"
47 );
48
49 #[cfg(feature = "tokio-console")]
50 layers.push(Box::new(
51 console_subscriber::ConsoleLayer::builder()
52 .with_default_env()
53 .spawn(),
54 ));
55 }
56
57 if opts.loki {
58 #[cfg(not(feature = "tracing-loki"))]
59 tracing::warn!(
60 "`tracing-loki` is unavailable, forest binaries need to be recompiled with `tracing-loki` feature"
61 );
62
63 #[cfg(feature = "tracing-loki")]
64 {
65 let (layer, task) = tracing_loki::layer(
66 tracing_loki::url::Url::parse(&opts.loki_endpoint)
67 .map_err(|e| {
68 format!("Unable to parse loki endpoint {}: {e}", &opts.loki_endpoint)
69 })
70 .unwrap(),
71 vec![(
72 "host".into(),
73 gethostname::gethostname()
74 .to_str()
75 .unwrap_or_default()
76 .into(),
77 )]
78 .into_iter()
79 .collect(),
80 Default::default(),
81 )
82 .map_err(|e| format!("Unable to create loki layer: {e}"))
83 .unwrap();
84 background_tasks.push(Box::pin(task));
85 layers.push(Box::new(
86 layer.with_filter(tracing_subscriber::filter::LevelFilter::INFO),
87 ));
88 }
89 }
90
91 if let Some(_chrome_trace_file) = std::env::var_os("CHROME_TRACE_FILE") {
94 #[cfg(not(feature = "tracing-chrome"))]
95 tracing::warn!(
96 "`tracing-chrome` is unavailable, forest binaries need to be recompiled with `tracing-chrome` feature"
97 );
98
99 #[cfg(feature = "tracing-chrome")]
100 {
101 let (layer, guard) = match _chrome_trace_file.is_empty() {
102 true => tracing_chrome::ChromeLayerBuilder::new().build(),
103 false => tracing_chrome::ChromeLayerBuilder::new()
104 .file(_chrome_trace_file)
105 .build(),
106 };
107
108 guards.tracing_chrome = Some(guard);
109 layers.push(Box::new(layer));
110 }
111 }
112
113 tracing_subscriber::registry().with(layers).init();
114 (background_tasks, guards)
115}
116
117pub fn setup_minimal_logger() {
119 tracing_subscriber::registry()
120 .with(
121 tracing_subscriber::fmt::Layer::new()
122 .with_ansi(LoggingColor::Auto.coloring_enabled())
123 .with_writer(std::io::stderr)
124 .with_filter(get_env_filter(default_tool_filter())),
125 )
126 .init();
127}
128
129fn get_env_filter(def: EnvFilter) -> EnvFilter {
136 use std::env::{
137 self,
138 VarError::{NotPresent, NotUnicode},
139 };
140 match env::var(tracing_subscriber::EnvFilter::DEFAULT_ENV) {
141 Ok(s) => EnvFilter::new(s),
142 Err(NotPresent) => def,
143 Err(NotUnicode(_)) => EnvFilter::default(),
144 }
145}
146
147fn default_env_filter() -> EnvFilter {
148 let default_directives = [
149 "info",
150 "bellperson::groth16::aggregate::verify=warn",
151 "axum=warn",
152 "filecoin_proofs=warn",
153 "libp2p_bitswap=off",
154 "libp2p_gossipsub=error",
155 "libp2p_kad=error",
156 "storage_proofs_core=warn",
157 "tracing_loki=off",
158 "quinn_udp=error",
159 ];
160 EnvFilter::try_new(default_directives.join(",")).unwrap()
161}
162
163fn default_tool_filter() -> EnvFilter {
164 let default_directives = [
165 "info",
166 "bellperson::groth16::aggregate::verify=warn",
167 "storage_proofs_core=warn",
168 "axum=warn",
169 "filecoin_proofs=warn",
170 "forest::snapshot=info",
171 "forest::progress=info",
172 "libp2p_bitswap=off",
173 "tracing_loki=off",
174 "hickory_resolver::hosts=off",
175 "libp2p_swarm=off",
176 ];
177 EnvFilter::try_new(default_directives.join(",")).unwrap()
178}
179
180#[test]
181fn test_default_env_filter() {
182 let _did_not_panic = default_env_filter();
183}