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#[allow(unused_mut)]
15pub fn setup_logger(opts: &CliOpts) -> anyhow::Result<Vec<BackgroundTask>> {
16 let mut background_tasks: Vec<BackgroundTask> = vec![];
17 let mut layers: Vec<Box<dyn tracing_subscriber::layer::Layer<Registry> + Send + Sync>> =
18 vec![Box::new(
20 tracing_subscriber::fmt::Layer::new()
21 .with_ansi(opts.color.coloring_enabled())
22 .with_filter(get_env_filter(default_env_filter())),
23 )];
24
25 if let Some(log_dir) = &opts.log_dir {
27 let file_appender = tracing_appender::rolling::hourly(log_dir, "forest.log");
28 layers.push(Box::new(
29 tracing_subscriber::fmt::Layer::new()
30 .with_ansi(false)
31 .with_writer(file_appender)
32 .with_filter(get_env_filter(default_env_filter())),
33 ));
34 }
35
36 if opts.tokio_console {
37 #[cfg(not(feature = "tokio-console"))]
38 tracing::warn!(
39 "`tokio-console` is unavailable, forest binaries need to be recompiled with `tokio-console` feature"
40 );
41
42 #[cfg(feature = "tokio-console")]
43 layers.push(Box::new(
44 console_subscriber::ConsoleLayer::builder()
45 .with_default_env()
46 .spawn(),
47 ));
48 }
49
50 if opts.loki {
51 #[cfg(not(feature = "tracing-loki"))]
52 tracing::warn!(
53 "`tracing-loki` is unavailable, forest binaries need to be recompiled with `tracing-loki` feature"
54 );
55
56 #[cfg(feature = "tracing-loki")]
57 {
58 use anyhow::Context as _;
59 let (layer, task) = tracing_loki::layer(
60 tracing_loki::url::Url::parse(&opts.loki_endpoint).with_context(|| {
61 format!("Unable to parse loki endpoint {}", opts.loki_endpoint)
62 })?,
63 vec![(
64 "host".into(),
65 gethostname::gethostname()
66 .to_str()
67 .unwrap_or_default()
68 .into(),
69 )]
70 .into_iter()
71 .collect(),
72 Default::default(),
73 )
74 .context("Unable to create loki layer")?;
75 background_tasks.push(Box::pin(task));
76 layers.push(Box::new(
77 layer.with_filter(tracing_subscriber::filter::LevelFilter::INFO),
78 ));
79 }
80 }
81
82 tracing_subscriber::registry().with(layers).init();
83 Ok(background_tasks)
84}
85
86pub fn setup_minimal_logger() {
88 tracing_subscriber::registry()
89 .with(
90 tracing_subscriber::fmt::Layer::new()
91 .with_ansi(LoggingColor::Auto.coloring_enabled())
92 .with_writer(std::io::stderr)
93 .with_filter(get_env_filter(default_tool_filter())),
94 )
95 .init();
96}
97
98fn get_env_filter(def: EnvFilter) -> EnvFilter {
105 use std::env::{
106 self,
107 VarError::{NotPresent, NotUnicode},
108 };
109 match env::var(tracing_subscriber::EnvFilter::DEFAULT_ENV) {
110 Ok(s) => EnvFilter::new(s),
111 Err(NotPresent) => def,
112 Err(NotUnicode(_)) => EnvFilter::default(),
113 }
114}
115
116fn default_env_filter() -> EnvFilter {
117 let default_directives = [
118 "info",
119 "bellperson::groth16::aggregate::verify=warn",
120 "axum=warn",
121 "filecoin_proofs=warn",
122 "libp2p_bitswap=off",
123 "libp2p_gossipsub=error",
124 "libp2p_kad=error",
125 "storage_proofs_core=warn",
126 "tracing_loki=off",
127 "quinn_udp=error",
128 ];
129 EnvFilter::try_new(default_directives.join(",")).expect("hardcoded log directives are valid")
130}
131
132fn default_tool_filter() -> EnvFilter {
133 let default_directives = [
134 "info",
135 "bellperson::groth16::aggregate::verify=warn",
136 "storage_proofs_core=warn",
137 "axum=warn",
138 "filecoin_proofs=warn",
139 "forest::snapshot=info",
140 "forest::progress=info",
141 "libp2p_bitswap=off",
142 "tracing_loki=off",
143 "hickory_resolver::hosts=off",
144 "libp2p_swarm=off",
145 ];
146 EnvFilter::try_new(default_directives.join(",")).expect("hardcoded log directives are valid")
147}
148
149#[test]
150fn test_default_env_filter() {
151 let _did_not_panic = default_env_filter();
152}