clamber_core/tracing_logs/
mod.rs1use crate::error::{ClamberError, Result};
2use std::fs;
3use tracing::metadata::LevelFilter;
4use tracing_appender::non_blocking::WorkerGuard;
5use tracing_appender::rolling;
6use tracing_subscriber::filter::filter_fn;
7use tracing_subscriber::fmt::time::ChronoUtc;
8use tracing_subscriber::layer::SubscriberExt;
9use tracing_subscriber::util::SubscriberInitExt;
10use tracing_subscriber::{Layer, fmt};
11
12#[derive(Debug, Clone)]
14pub struct LogConfig {
15 pub time_format: String,
17 pub enable_ansi: bool,
19 pub show_target: bool,
21 pub show_thread_ids: bool,
23 pub compact_format: bool,
25 pub console_level: LevelFilter,
27 pub file_level: LevelFilter,
29}
30
31impl Default for LogConfig {
32 fn default() -> Self {
33 Self {
34 time_format: "%Y-%m-%d %H:%M:%S".to_string(),
35 enable_ansi: true,
36 show_target: false,
37 show_thread_ids: false,
38 compact_format: true,
39 console_level: LevelFilter::INFO,
40 file_level: LevelFilter::INFO,
41 }
42 }
43}
44
45impl LogConfig {
46 pub fn new() -> Self {
48 Self::default()
49 }
50
51 pub fn time_format(mut self, format: impl Into<String>) -> Self {
53 self.time_format = format.into();
54 self
55 }
56
57 pub fn ansi(mut self, enable: bool) -> Self {
59 self.enable_ansi = enable;
60 self
61 }
62
63 pub fn target(mut self, show: bool) -> Self {
65 self.show_target = show;
66 self
67 }
68
69 pub fn thread_ids(mut self, show: bool) -> Self {
71 self.show_thread_ids = show;
72 self
73 }
74
75 pub fn compact(mut self, enable: bool) -> Self {
77 self.compact_format = enable;
78 self
79 }
80
81 pub fn console_level(mut self, level: LevelFilter) -> Self {
83 self.console_level = level;
84 self
85 }
86
87 pub fn file_level(mut self, level: LevelFilter) -> Self {
89 self.file_level = level;
90 self
91 }
92}
93
94pub fn logger_start_with_config(
156 service_name: &str,
157 path: Option<String>,
158 config: LogConfig,
159) -> Result<(WorkerGuard, WorkerGuard)> {
160 let log_dir = match path {
161 Some(p) => format!("logs/{}", p),
162 None => format!("logs"),
163 };
164
165 fs::create_dir_all(&log_dir).map_err(|_| ClamberError::DirectoryCreationError {
166 path: log_dir.clone(),
167 })?;
168
169 let info_file = rolling::daily(&log_dir, format!("{}-info.log", service_name));
170 let error_file = rolling::daily(&log_dir, format!("{}-error.log", service_name));
171
172 let (info_writer, info_guard) = tracing_appender::non_blocking(info_file);
173 let (error_writer, error_guard) = tracing_appender::non_blocking(error_file);
174
175 let timer = ChronoUtc::new(config.time_format.clone());
177
178 if config.compact_format {
180 let info_layer = fmt::layer()
182 .compact()
183 .with_writer(info_writer)
184 .with_ansi(false)
185 .with_level(true)
186 .with_target(config.show_target)
187 .with_thread_ids(config.show_thread_ids)
188 .with_timer(timer.clone())
189 .with_filter(filter_fn(move |metadata| {
190 metadata.level() == &tracing::Level::INFO
191 }));
192
193 let error_layer = fmt::layer()
194 .compact()
195 .with_writer(error_writer)
196 .with_ansi(false)
197 .with_level(true)
198 .with_target(config.show_target)
199 .with_thread_ids(config.show_thread_ids)
200 .with_timer(timer.clone())
201 .with_filter(LevelFilter::ERROR);
202
203 let console_layer = fmt::layer()
204 .compact()
205 .with_ansi(config.enable_ansi)
206 .with_level(true)
207 .with_target(config.show_target)
208 .with_thread_ids(config.show_thread_ids)
209 .with_timer(timer)
210 .with_filter(config.console_level);
211
212 tracing_subscriber::registry()
213 .with(info_layer)
214 .with(error_layer)
215 .with(console_layer)
216 .init();
217 } else {
218 let info_layer = fmt::layer()
220 .with_writer(info_writer)
221 .with_ansi(false)
222 .with_level(true)
223 .with_target(config.show_target)
224 .with_thread_ids(config.show_thread_ids)
225 .with_timer(timer.clone())
226 .with_filter(filter_fn(move |metadata| {
227 metadata.level() == &tracing::Level::INFO
228 }));
229
230 let error_layer = fmt::layer()
231 .with_writer(error_writer)
232 .with_ansi(false)
233 .with_level(true)
234 .with_target(config.show_target)
235 .with_thread_ids(config.show_thread_ids)
236 .with_timer(timer.clone())
237 .with_filter(LevelFilter::ERROR);
238
239 let console_layer = fmt::layer()
240 .with_ansi(config.enable_ansi)
241 .with_level(true)
242 .with_target(config.show_target)
243 .with_thread_ids(config.show_thread_ids)
244 .with_timer(timer)
245 .with_filter(config.console_level);
246
247 tracing_subscriber::registry()
248 .with(info_layer)
249 .with(error_layer)
250 .with(console_layer)
251 .init();
252 }
253
254 Ok((info_guard, error_guard))
255}