snarkos_cli/helpers/
logger.rs

1// Copyright 2024-2025 Aleo Network Foundation
2// This file is part of the snarkOS library.
3
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at:
7
8// http://www.apache.org/licenses/LICENSE-2.0
9
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15
16use crate::helpers::{DynamicFormatter, LogWriter};
17
18use crossterm::tty::IsTty;
19use std::{
20    fs::File,
21    io,
22    path::Path,
23    sync::{Arc, atomic::AtomicBool},
24};
25use tokio::sync::mpsc;
26use tracing_subscriber::{
27    EnvFilter,
28    layer::{Layer, SubscriberExt},
29    util::SubscriberInitExt,
30};
31
32/// Initializes the logger.
33///
34/// ```ignore
35/// 0 => info
36/// 1 => info, debug
37/// 2 => info, debug, trace, snarkos_node_sync=trace
38/// 3 => info, debug, trace, snarkos_node_bft=trace
39/// 4 => info, debug, trace, snarkos_node_bft::gateway=trace
40/// 5 => info, debug, trace, snarkos_node_router=trace
41/// 6 => info, debug, trace, snarkos_node_tcp=trace
42/// ```
43pub fn initialize_logger<P: AsRef<Path>>(
44    verbosity: u8,
45    nodisplay: bool,
46    logfile: P,
47    shutdown: Arc<AtomicBool>,
48) -> mpsc::Receiver<Vec<u8>> {
49    match verbosity {
50        0 => std::env::set_var("RUST_LOG", "info"),
51        1 => std::env::set_var("RUST_LOG", "debug"),
52        2.. => std::env::set_var("RUST_LOG", "trace"),
53    };
54
55    // Filter out undesirable logs. (unfortunately EnvFilter cannot be cloned)
56    let [filter, filter2] = std::array::from_fn(|_| {
57        let filter = EnvFilter::from_default_env()
58            .add_directive("mio=off".parse().unwrap())
59            .add_directive("tokio_util=off".parse().unwrap())
60            .add_directive("hyper=off".parse().unwrap())
61            .add_directive("reqwest=off".parse().unwrap())
62            .add_directive("want=off".parse().unwrap())
63            .add_directive("h2=off".parse().unwrap());
64
65        let filter = if verbosity >= 2 {
66            filter.add_directive("snarkos_node_sync=trace".parse().unwrap())
67        } else {
68            filter.add_directive("snarkos_node_sync=debug".parse().unwrap())
69        };
70
71        let filter = if verbosity >= 3 {
72            filter
73                .add_directive("snarkos_node_bft=trace".parse().unwrap())
74                .add_directive("snarkos_node_bft::gateway=debug".parse().unwrap())
75        } else {
76            filter.add_directive("snarkos_node_bft=debug".parse().unwrap())
77        };
78
79        let filter = if verbosity >= 4 {
80            filter.add_directive("snarkos_node_bft::gateway=trace".parse().unwrap())
81        } else {
82            filter.add_directive("snarkos_node_bft::gateway=debug".parse().unwrap())
83        };
84
85        let filter = if verbosity >= 5 {
86            filter.add_directive("snarkos_node_router=trace".parse().unwrap())
87        } else {
88            filter.add_directive("snarkos_node_router=debug".parse().unwrap())
89        };
90
91        if verbosity >= 6 {
92            filter.add_directive("snarkos_node_tcp=trace".parse().unwrap())
93        } else {
94            filter.add_directive("snarkos_node_tcp=off".parse().unwrap())
95        }
96    });
97
98    // Create the directories tree for a logfile if it doesn't exist.
99    let logfile_dir = logfile.as_ref().parent().expect("Root directory passed as a logfile");
100    if !logfile_dir.exists() {
101        std::fs::create_dir_all(logfile_dir).unwrap_or_else(|e| {
102            panic!("Failed to create a directory: '{}' ({e})", logfile_dir.display());
103        });
104    }
105    // Create a file to write logs to.
106    let logfile =
107        File::options().append(true).create(true).open(logfile).expect("Failed to open the file for writing logs");
108
109    // Initialize the log channel.
110    let (log_sender, log_receiver) = mpsc::channel(1024);
111
112    // Initialize the log sender.
113    let log_sender = match nodisplay {
114        true => None,
115        false => Some(log_sender),
116    };
117
118    // Initialize tracing.
119    let _ = tracing_subscriber::registry()
120        .with(
121            // Add layer using LogWriter for stdout / terminal
122            tracing_subscriber::fmt::Layer::default()
123                .with_ansi(log_sender.is_none() && io::stdout().is_tty())
124                .with_writer(move || LogWriter::new(&log_sender))
125                .with_target(verbosity > 2)
126                .event_format(DynamicFormatter::new(shutdown))
127                .with_filter(filter),
128        )
129        .with(
130            // Add layer redirecting logs to the file
131            tracing_subscriber::fmt::Layer::default()
132                .with_ansi(false)
133                .with_writer(logfile)
134                .with_target(verbosity > 2)
135                .with_filter(filter2),
136        )
137        .try_init();
138
139    log_receiver
140}
141
142/// Returns the welcome message as a string.
143pub fn welcome_message() -> String {
144    use colored::Colorize;
145
146    let mut output = String::new();
147    output += &r#"
148
149         ╦╬╬╬╬╬╦
150        ╬╬╬╬╬╬╬╬╬                    ▄▄▄▄        ▄▄▄
151       ╬╬╬╬╬╬╬╬╬╬╬                  ▐▓▓▓▓▌       ▓▓▓
152      ╬╬╬╬╬╬╬╬╬╬╬╬╬                ▐▓▓▓▓▓▓▌      ▓▓▓     ▄▄▄▄▄▄       ▄▄▄▄▄▄
153     ╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬              ▐▓▓▓  ▓▓▓▌     ▓▓▓   ▄▓▓▀▀▀▀▓▓▄   ▐▓▓▓▓▓▓▓▓▌
154    ╬╬╬╬╬╬╬╜ ╙╬╬╬╬╬╬╬            ▐▓▓▓▌  ▐▓▓▓▌    ▓▓▓  ▐▓▓▓▄▄▄▄▓▓▓▌ ▐▓▓▓    ▓▓▓▌
155   ╬╬╬╬╬╬╣     ╠╬╬╬╬╬╬           ▓▓▓▓▓▓▓▓▓▓▓▓    ▓▓▓  ▐▓▓▀▀▀▀▀▀▀▀▘ ▐▓▓▓    ▓▓▓▌
156  ╬╬╬╬╬╬╣       ╠╬╬╬╬╬╬         ▓▓▓▓▌    ▐▓▓▓▓   ▓▓▓   ▀▓▓▄▄▄▄▓▓▀   ▐▓▓▓▓▓▓▓▓▌
157 ╬╬╬╬╬╬╣         ╠╬╬╬╬╬╬       ▝▀▀▀▀      ▀▀▀▀▘  ▀▀▀     ▀▀▀▀▀▀       ▀▀▀▀▀▀
158╚╬╬╬╬╬╩           ╩╬╬╬╬╩
159
160
161"#
162    .white()
163    .bold();
164    output += &"👋 Welcome to Aleo! We thank you for running a node and supporting privacy.\n".bold();
165    output
166}