Skip to main content

ferrum_cli/
utils.rs

1//! CLI utility functions
2
3use ferrum_types::Result;
4use std::io;
5use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt, EnvFilter};
6
7/// Setup logging based on verbosity level.
8///
9/// `suppress_chat_template_warnings` is used by the interactive `run` UX:
10/// template fallback diagnostics are useful in server logs, but they should
11/// not be printed in the middle of a user-facing REPL turn.
12pub fn setup_logging(
13    verbose: bool,
14    quiet: bool,
15    suppress_chat_template_warnings: bool,
16) -> Result<()> {
17    let log_level = if quiet {
18        tracing::Level::ERROR
19    } else if verbose {
20        tracing::Level::DEBUG
21    } else {
22        tracing::Level::WARN
23    };
24
25    // Build filter: suppress noisy warnings unless verbose. Default level
26    // is WARN, but the model-load and weight-loader namespaces stay at
27    // INFO so users see per-layer progress during the (10-60s) load.
28    // Without this, `ferrum run /path/to/30b-moe` looks frozen between
29    // "Loading..." and the first decode token.
30    let filter = if verbose {
31        EnvFilter::new(log_level.to_string())
32    } else {
33        EnvFilter::try_from_default_env().unwrap_or_else(|_| {
34            let mut filter = format!(
35                "{},\
36                 tokenizers=error,\
37                 ferrum_models=info,\
38                 ferrum_quantization=info,\
39                 ferrum_engine::registry=info",
40                log_level
41            );
42            if suppress_chat_template_warnings {
43                filter.push_str(",ferrum_server::chat_template=error");
44            }
45            EnvFilter::new(filter)
46        })
47    };
48
49    tracing_subscriber::registry()
50        .with(filter)
51        .with(tracing_subscriber::fmt::layer().with_writer(io::stderr))
52        .init();
53
54    Ok(())
55}