1use std::path::{Path, PathBuf};
2
3use mold_core::LoggingConfig;
4use tracing_appender::non_blocking::WorkerGuard;
5use tracing_subscriber::prelude::*;
6use tracing_subscriber::EnvFilter;
7
8pub struct LogGuard {
10 _file_guard: Option<WorkerGuard>,
11}
12
13pub fn init_tracing(
15 log_file: bool,
16 json: bool,
17 config: &LoggingConfig,
18 default_level: &str,
19 log_dir: PathBuf,
20) -> LogGuard {
21 let filter_str = resolve_filter(config, default_level);
22 let file_enabled = log_file || config.file;
23
24 let mut file_guard: Option<WorkerGuard> = None;
25
26 if file_enabled {
27 let _ = std::fs::create_dir_all(&log_dir);
28 cleanup_old_logs(&log_dir, config.max_days);
29 let appender = tracing_appender::rolling::RollingFileAppender::builder()
30 .rotation(tracing_appender::rolling::Rotation::DAILY)
31 .filename_prefix("mold-server")
32 .filename_suffix("log")
33 .build(&log_dir)
34 .expect("failed to create log file appender");
35 let (non_blocking, guard) = tracing_appender::non_blocking(appender);
36 file_guard = Some(guard);
37
38 let stderr_filter = make_filter(&filter_str, default_level);
39 let file_filter = make_filter(&filter_str, default_level);
40
41 let stderr_layer = tracing_subscriber::fmt::layer().with_writer(std::io::stderr);
42 let file_layer = tracing_subscriber::fmt::layer()
43 .with_writer(non_blocking)
44 .with_ansi(false);
45
46 tracing_subscriber::registry()
47 .with(stderr_layer.with_filter(stderr_filter))
48 .with(file_layer.with_filter(file_filter))
49 .init();
50 } else if json {
51 let filter = make_filter(&filter_str, default_level);
52 tracing_subscriber::fmt()
53 .with_env_filter(filter)
54 .with_writer(std::io::stderr)
55 .json()
56 .init();
57 } else {
58 let filter = make_filter(&filter_str, default_level);
59 tracing_subscriber::fmt()
60 .with_env_filter(filter)
61 .with_writer(std::io::stderr)
62 .init();
63 }
64
65 LogGuard {
66 _file_guard: file_guard,
67 }
68}
69
70pub fn init_tracing_file_only(
75 config: &LoggingConfig,
76 default_level: &str,
77 log_dir: PathBuf,
78) -> LogGuard {
79 let filter_str = resolve_filter(config, default_level);
80
81 let _ = std::fs::create_dir_all(&log_dir);
82 cleanup_old_logs(&log_dir, config.max_days);
83 let appender = tracing_appender::rolling::RollingFileAppender::builder()
84 .rotation(tracing_appender::rolling::Rotation::DAILY)
85 .filename_prefix("mold-tui")
86 .filename_suffix("log")
87 .build(&log_dir)
88 .expect("failed to create log file appender");
89 let (non_blocking, guard) = tracing_appender::non_blocking(appender);
90
91 let filter = make_filter(&filter_str, default_level);
92 tracing_subscriber::fmt()
93 .with_env_filter(filter)
94 .with_writer(non_blocking)
95 .with_ansi(false)
96 .init();
97
98 LogGuard {
99 _file_guard: Some(guard),
100 }
101}
102
103fn resolve_filter(config: &LoggingConfig, default_level: &str) -> String {
104 std::env::var("MOLD_LOG").unwrap_or_else(|_| {
105 if config.level.is_empty() {
106 default_level.to_string()
107 } else {
108 config.level.clone()
109 }
110 })
111}
112
113fn make_filter(filter_str: &str, default_level: &str) -> EnvFilter {
114 EnvFilter::try_new(filter_str).unwrap_or_else(|_| EnvFilter::new(default_level))
115}
116
117fn cleanup_old_logs(log_dir: &Path, max_days: u32) {
119 let now = std::time::SystemTime::now();
120 let max_age = std::time::Duration::from_secs(max_days as u64 * 86400);
121
122 let entries = match std::fs::read_dir(log_dir) {
123 Ok(e) => e,
124 Err(_) => return,
125 };
126
127 for entry in entries.filter_map(|e| e.ok()) {
128 let path = entry.path();
129 if !path.is_file() {
130 continue;
131 }
132
133 let filename = path
134 .file_name()
135 .and_then(|f| f.to_str())
136 .unwrap_or_default();
137
138 let is_mold_log = filename.starts_with("mold-server.") || filename.starts_with("mold-tui.");
140 if !is_mold_log {
141 continue;
142 }
143
144 if let Ok(metadata) = path.metadata() {
145 if let Ok(modified) = metadata.modified() {
146 if let Ok(age) = now.duration_since(modified) {
147 if age > max_age {
148 let _ = std::fs::remove_file(&path);
149 }
150 }
151 }
152 }
153 }
154}