lib_flutter_rust_bridge_codegen/library/utils/
logs.rs1use crate::utils::console::MULTI_PROGRESS;
4use fern::colors::{Color, ColoredLevelConfig};
5use log::LevelFilter;
6use std::io::IsTerminal;
7
8pub fn configure_opinionated_logging(path: &str, verbose: bool) -> Result<(), fern::InitError> {
25 let level_filter = log_level_from_env_var().unwrap_or_else(|| verbose_to_level_filter(verbose));
26
27 if level_filter == LevelFilter::Debug {
28 std::fs::create_dir_all(path).unwrap();
29 }
30
31 let mut fern_logger = fern::Dispatch::new();
32 fern_logger = log_format_simple(fern_logger);
33 fern_logger = match level_filter {
34 LevelFilter::Debug => fern_logger
35 .level(LevelFilter::Debug)
36 .chain(fern::DateBased::new(path, "%Y-%m-%d.log"))
37 .chain(std::io::stdout()),
38 LevelFilter::Info => fern_logger
39 .level(LevelFilter::Info)
40 .level_for("cbindgen", LevelFilter::Error)
41 .chain(std::io::stdout()),
42 _ => fern_logger.level(level_filter).chain(std::io::stdout()),
43 };
44
45 let (max_level, fern_logger) = fern_logger.into_log();
46 let log_wrapper = indicatif_log_bridge::LogWrapper::new(MULTI_PROGRESS.clone(), fern_logger);
47
48 log::set_boxed_logger(Box::new(log_wrapper))?;
50 log::set_max_level(max_level);
51
52 let prev = std::panic::take_hook();
53 std::panic::set_hook(Box::new(move |info| {
54 log::error!("{}", info);
55 prev(info);
56 }));
57
58 Ok(())
59}
60
61fn log_level_from_env_var() -> Option<LevelFilter> {
62 (std::env::var("RUST_LOG").ok()).map(|value| log_level_from_str(&value))
63}
64
65fn log_level_from_str(value: &str) -> LevelFilter {
66 match value {
67 "trace" => LevelFilter::Trace,
68 "debug" => LevelFilter::Debug,
69 "info" => LevelFilter::Info,
70 "warn" => LevelFilter::Warn,
71 "error" => LevelFilter::Error,
72 "off" => LevelFilter::Off,
73 _ => panic!("{}", "unknown RUST_LOG level: {value}"),
75 }
77}
78
79fn verbose_to_level_filter(verbose: bool) -> LevelFilter {
80 if verbose {
81 LevelFilter::Debug
82 } else {
83 LevelFilter::Info
84 }
85}
86
87fn log_format_simple(d: fern::Dispatch) -> fern::Dispatch {
88 let colored_output = ColoredLevelConfig::new()
89 .error(Color::Red)
90 .warn(Color::Yellow)
91 .info(Color::Green)
92 .debug(Color::Blue)
93 .trace(Color::BrightBlack);
94
95 d.format(move |out, message, record| {
96 let time = chrono::Utc::now().format("%Y-%m-%dT%H:%M:%S%.3fZ");
97
98 let level = record.level();
99 let level = if std::io::stdout().is_terminal() {
100 colored_output.color(level).to_string()
101 } else {
102 level.to_string()
103 };
104
105 out.finish(format_args!(
106 "[{} {} {}:{}] {}",
107 time,
108 level,
109 record.file().unwrap_or(""),
110 record.line().unwrap_or(0),
111 message
112 ))
113 })
114}
115
116pub fn configure_opinionated_test_logging() {
118 let _ = log_format_simple(fern::Dispatch::new())
121 .level(log_level_from_env_var().unwrap_or(LevelFilter::Debug))
122 .chain(fern::Output::call(|record| println!("{}", record.args())))
123 .apply();
124}
125
126#[cfg(test)]
127mod tests {
128 use crate::utils::logs::log_level_from_str;
129 use log::LevelFilter;
130
131 #[test]
132 pub fn test_log_level_from_str() {
133 assert_eq!(log_level_from_str("trace"), LevelFilter::Trace);
134 assert_eq!(log_level_from_str("debug"), LevelFilter::Debug);
135 assert_eq!(log_level_from_str("info"), LevelFilter::Info);
136 assert_eq!(log_level_from_str("warn"), LevelFilter::Warn);
137 assert_eq!(log_level_from_str("error"), LevelFilter::Error);
138 assert_eq!(log_level_from_str("off"), LevelFilter::Off);
139 }
140}