1use std::sync::OnceLock;
2use tracing::Level;
3use tracing_subscriber::{
4 EnvFilter,
5 fmt::{self, format::FmtSpan},
6 layer::{Layer, SubscriberExt},
7 util::SubscriberInitExt,
8};
9
10static LOG_GUARD: OnceLock<Vec<tracing_appender::non_blocking::WorkerGuard>> = OnceLock::new();
11
12fn parse_log_level(level_str: &str) -> Level {
13 match level_str.to_lowercase().as_str() {
14 "debug" => Level::DEBUG,
15 "info" | "notice" => Level::INFO,
16 "warn" => Level::WARN,
17 "error" => Level::ERROR,
18 _ => Level::INFO,
19 }
20}
21
22pub fn init_logging(
23 log_level: &str,
24 console_log_level: &str,
25 log_file: Option<&str>,
26 log_backup_count: usize,
27) {
28 let file_level = parse_log_level(log_level);
29 let console_level = parse_log_level(console_log_level);
30
31 let enable_file_logging = log_file.is_some_and(|f| f != "-");
32
33 if enable_file_logging {
34 let path = log_file.unwrap();
35 let p = std::path::Path::new(path);
36 let dir = p
37 .parent()
38 .map(|d| d.to_string_lossy().to_string())
39 .unwrap_or_else(|| ".".to_string());
40 let stem = p
41 .file_name()
42 .map(|n| n.to_string_lossy().to_string())
43 .unwrap_or_else(|| "aria2.log".to_string());
44
45 use tracing_appender::non_blocking;
46 use tracing_appender::rolling::Rotation;
47 let file_appender = tracing_appender::rolling::Builder::new()
48 .rotation(Rotation::DAILY)
49 .filename_prefix(&stem)
50 .max_log_files(log_backup_count)
51 .build(&dir)
52 .unwrap_or_else(|_| tracing_appender::rolling::daily(&dir, &stem));
53 let (non_blocking, guard) = non_blocking(file_appender);
54 let _ = LOG_GUARD.set(vec![guard]);
55
56 let file_filter = EnvFilter::from_default_env()
57 .add_directive(file_level.into())
58 .add_directive("hyper=warn".parse().unwrap())
59 .add_directive("reqwest=warn".parse().unwrap());
60
61 let console_filter = EnvFilter::from_default_env()
62 .add_directive(console_level.into())
63 .add_directive("hyper=warn".parse().unwrap())
64 .add_directive("reqwest=warn".parse().unwrap());
65
66 let console_layer = fmt::layer()
67 .with_span_events(FmtSpan::CLOSE)
68 .with_target(false)
69 .with_filter(console_filter);
70
71 let file_layer = fmt::Layer::new()
72 .with_span_events(FmtSpan::CLOSE)
73 .with_target(false)
74 .with_writer(non_blocking)
75 .with_filter(file_filter);
76
77 let _ = tracing_subscriber::registry()
78 .with(console_layer)
79 .with(file_layer)
80 .try_init();
81 } else {
82 let env_filter = EnvFilter::from_default_env()
83 .add_directive(console_level.into())
84 .add_directive("hyper=warn".parse().unwrap())
85 .add_directive("reqwest=warn".parse().unwrap());
86
87 let _ = tracing_subscriber::registry()
88 .with(env_filter)
89 .with(
90 fmt::layer()
91 .with_span_events(FmtSpan::CLOSE)
92 .with_target(false),
93 )
94 .try_init();
95 }
96
97 tracing::info!("Log system initialization complete");
98}