1use crate::build::get_target_directory;
2
3use indenter::indented;
4
5use std::fmt::Write;
6use std::path::PathBuf;
7use std::sync::Arc;
8use std::{fs::create_dir_all, path::Path};
9use tracing_subscriber::layer::SubscriberExt;
10
11#[derive(Clone, Debug)]
12pub struct LoggingConfig {
13 pub level: tracing::Level,
14 pub logging_enabled: bool,
15 pub logger_name: String,
16 pub log_path: Option<PathBuf>,
17 pub _tracing_guard: Option<Arc<tracing::subscriber::DefaultGuard>>,
18 pub build_log: bool,
19}
20
21impl Default for LoggingConfig {
22 fn default() -> Self {
23 Self {
24 level: tracing::Level::INFO,
25 logging_enabled: true,
26 logger_name: "llm_interface".to_string(),
27 log_path: None,
28 _tracing_guard: None,
29 build_log: false,
30 }
31 }
32}
33
34impl LoggingConfig {
35 pub fn new() -> Self {
36 Default::default()
37 }
38
39 pub fn load_logger(&mut self) -> crate::Result<()> {
40 self._tracing_guard = if self.logging_enabled {
41 Some(Arc::new(self.create_logger()?))
42 } else {
43 None
44 };
45
46 Ok(())
47 }
48
49 fn create_logger(&mut self) -> crate::Result<tracing::subscriber::DefaultGuard> {
50 let log_dir = if let Some(log_path) = &self.log_path {
51 log_path.clone()
52 } else {
53 let target_dir = get_target_directory()?;
54 if self.build_log {
55 target_dir.join("llm_devices_build_logs")
56 } else {
57 target_dir
58 .parent()
59 .map(Path::to_path_buf)
60 .ok_or_else(|| anyhow::anyhow!("Failed to get parent directory"))?
61 .join("llm_logs")
62 }
63 };
64
65 if !Path::new(&log_dir).exists() {
66 create_dir_all(&log_dir).expect("Failed to create log directory");
67 }
68
69 let file_appender = tracing_appender::rolling::RollingFileAppender::builder()
70 .rotation(tracing_appender::rolling::Rotation::HOURLY)
71 .max_log_files(6)
72 .filename_prefix(&self.logger_name)
73 .filename_suffix("log")
74 .build(log_dir)
75 .unwrap();
76
77 let filter = tracing_subscriber::EnvFilter::builder()
78 .with_default_directive(self.level.into())
79 .parse_lossy("");
80
81 let file_layer = tracing_subscriber::fmt::layer()
82 .pretty()
83 .with_ansi(false) .with_writer(file_appender);
85
86 let terminal_layer = tracing_subscriber::fmt::layer()
87 .compact()
88 .with_ansi(false) .with_writer(std::io::stdout);
90
91 let subscriber = tracing_subscriber::registry()
92 .with(filter)
93 .with(file_layer)
94 .with(terminal_layer);
95
96 Ok(tracing::subscriber::set_default(subscriber))
97 }
98}
99
100#[allow(dead_code)]
101pub trait LoggingConfigTrait {
102 fn logging_config_mut(&mut self) -> &mut LoggingConfig;
103
104 fn logging_enabled(mut self, enabled: bool) -> Self
114 where
115 Self: Sized,
116 {
117 self.logging_config_mut().logging_enabled = enabled;
118 self
119 }
120
121 fn logger_name<S: Into<String>>(mut self, logger_name: S) -> Self
136 where
137 Self: Sized,
138 {
139 self.logging_config_mut().logger_name = logger_name.into();
140 self
141 }
142
143 fn log_path<P: AsRef<Path>>(mut self, path: P) -> Self
157 where
158 Self: Sized,
159 {
160 self.logging_config_mut().log_path = Some(path.as_ref().to_path_buf());
161 self
162 }
163
164 fn log_level_trace(mut self) -> Self
171 where
172 Self: Sized,
173 {
174 self.logging_config_mut().level = tracing::Level::TRACE;
175 self
176 }
177
178 fn log_level_debug(mut self) -> Self
187 where
188 Self: Sized,
189 {
190 self.logging_config_mut().level = tracing::Level::DEBUG;
191 self
192 }
193
194 fn log_level_info(mut self) -> Self
201 where
202 Self: Sized,
203 {
204 self.logging_config_mut().level = tracing::Level::INFO;
205 self
206 }
207
208 fn log_level_warn(mut self) -> Self
215 where
216 Self: Sized,
217 {
218 self.logging_config_mut().level = tracing::Level::WARN;
219 self
220 }
221
222 fn log_level_error(mut self) -> Self
230 where
231 Self: Sized,
232 {
233 self.logging_config_mut().level = tracing::Level::ERROR;
234 self
235 }
236}
237
238pub fn i_ln(f: &mut std::fmt::Formatter<'_>, arg: std::fmt::Arguments<'_>) -> std::fmt::Result {
239 write!(indented(f), "{}", arg)?;
240 Ok(())
241}
242
243pub fn i_nln(f: &mut std::fmt::Formatter<'_>, arg: std::fmt::Arguments<'_>) -> std::fmt::Result {
244 writeln!(indented(f), "{}", arg)?;
245 Ok(())
246}
247
248pub fn i_lns(
249 f: &mut std::fmt::Formatter<'_>,
250 args: &[std::fmt::Arguments<'_>],
251) -> std::fmt::Result {
252 for arg in args {
253 write!(indented(f), "{}", arg)?;
254 }
255 Ok(())
256}
257
258pub fn i_nlns(
259 f: &mut std::fmt::Formatter<'_>,
260 args: &[std::fmt::Arguments<'_>],
261) -> std::fmt::Result {
262 for arg in args {
263 writeln!(indented(f), "{}", arg)?;
264 }
265 Ok(())
266}