1use super::{msg::LogMessage, position, LogLevel, Setting};
2use chrono::FixedOffset;
3#[cfg(not(feature = "async"))]
4use std::fs::{self, File};
5#[cfg(not(feature = "async"))]
6use std::io::Write;
7#[cfg(feature = "async")]
8use tokio::fs::{self, File};
9#[cfg(feature = "async")]
10use tokio::io::AsyncWriteExt;
11
12#[derive(Debug)]
14pub struct Logger {
15 file: Option<File>,
17 current_index: usize,
19 used_length: usize,
21 current_file_prefix: String,
23 init: bool,
25 setting: Setting,
27}
28
29impl Logger {
30 pub(crate) fn new() -> Self {
32 let setting = Setting {
33 ..Default::default()
34 };
35
36 let mut buffer = Self {
37 file: None,
38 current_index: 0,
39 used_length: 0,
40 init: false,
41 current_file_prefix: format!(
42 "{}",
43 chrono::Utc::now()
44 .with_timezone(&FixedOffset::east_opt(setting.time_zone * 3600).unwrap())
45 .format(&setting.file_time_format)
46 ),
47 setting,
48 };
49 buffer.check_dir();
50 buffer.current_index = buffer.get_index_not_async(&buffer.current_file_prefix);
51 buffer
52 }
53
54 fn get_path(&self, time_prefix: &str, index: usize) -> String {
56 format!("{}/{}_{}.log", self.setting.dir_path, time_prefix, index)
57 }
58
59 pub(crate) fn disable(&mut self) {
61 self.setting.disabled = true;
62 }
63
64 pub(crate) fn enable(&mut self) {
66 self.setting.disabled = false;
67 }
68
69 fn get_index_not_async(&self, time_prefix: &str) -> usize {
72 let mut count = 0;
73 loop {
74 let path = self.get_path(time_prefix, count);
75 if let Ok(_) = std::fs::File::open(path) {
77 count += 1
78 } else {
79 return count;
80 }
81 }
82 }
83
84 fn check_dir(&self) {
86 if !std::path::Path::new(&self.setting.dir_path).exists() {
87 std::fs::create_dir(&self.setting.dir_path).expect("Failed to create directory");
88 }
89 }
90}
91
92#[cfg(feature = "async")]
93impl Logger {
94 pub(crate) async fn init(&mut self, setting: Setting) {
96 if self.init {
97 let position = position!().to_string();
98 self.warn("Log writer had been initialized!", position)
99 .await;
100 return;
101 }
102
103 self.file = None;
104 self.used_length = 0;
105
106 self.setting = setting;
107
108 self.init = true;
109 self.current_file_prefix = format!(
110 "{}",
111 chrono::Utc::now()
112 .with_timezone(&FixedOffset::east_opt(self.setting.time_zone * 3600).unwrap())
113 .format("%Y-%m-%d")
114 );
115 self.current_index = self.get_index(&self.current_file_prefix).await;
116 }
117
118 pub(crate) async fn clear_dir(&mut self) {
120 fs::remove_dir_all(&self.setting.dir_path)
121 .await
122 .expect("Cannot remove the dir.");
123 fs::create_dir(&self.setting.dir_path)
124 .await
125 .expect("Cannot create the dir.");
126 self.current_index = 0;
127 self.used_length = 0;
128 self.file = None;
129 }
130
131 async fn write(&mut self, msg: &LogMessage) {
133 if self.setting.disabled {
135 return;
136 }
137
138 for i in msg.split_enter() {
139 if self.file.is_none() {
140 self.file = Some(self.get_file().await);
141 }
142
143 let time_prefix = format!(
146 "{}",
147 chrono::Utc::now()
148 .with_timezone(&FixedOffset::east_opt(self.setting.time_zone * 3600).unwrap())
149 .format("%Y-%m-%d")
150 );
151 if self.current_file_prefix != time_prefix {
152 self.current_file_prefix = time_prefix;
153 self.current_index = self.get_index(&self.current_file_prefix).await;
154 self.used_length = 0;
155 self.file = Some(self.get_file().await);
156 };
157
158 if self.setting.print_out
161 && self.setting.terminal_print_level.get_level() <= i.get_level()
162 {
163 println!("{}", i.print())
164 };
165
166 if self.setting.file_record_level.get_level() <= i.get_level() {
169 self.file
170 .as_mut()
171 .unwrap()
172 .write_all((i.print() + "\n").as_bytes())
173 .await
174 .expect("Cannot write into the log file.");
175 self.used_length += 1;
176 };
177 }
178
179 if self.setting.single_length != 0 && self.used_length >= self.setting.single_length {
181 self.current_index += 1;
182 self.used_length = 0;
183 self.file = None;
184 }
185 }
186
187 pub async fn record(&mut self, log_level: LogLevel, message: &str, position: String) {
189 if !self.init {
190 self.init = true
191 }
192 let mut msg = LogMessage::new(
193 log_level,
194 message.to_string(),
195 self.setting.time_zone,
196 position,
197 );
198 msg.time.detailed_display = self.setting.time_detailed_display;
199 self.write(&msg).await;
200 }
201
202 pub async fn info(&mut self, message: &str, position: String) {
204 self.record(LogLevel::Info, message, position).await;
205 }
206
207 pub async fn debug(&mut self, message: &str, position: String) {
209 self.record(LogLevel::Debug, message, position).await;
210 }
211
212 pub async fn warn(&mut self, message: &str, position: String) {
214 self.record(LogLevel::Warn, message, position).await;
215 }
216
217 pub async fn error(&mut self, message: &str, position: String) {
219 self.record(LogLevel::Error, message, position).await;
220 }
221
222 pub async fn trace(&mut self, message: &str, position: String) {
224 self.record(LogLevel::Trace, message, position).await;
225 }
226
227 async fn get_file(&self) -> File {
229 let path = self.get_path(&self.current_file_prefix, self.current_index);
230 File::options()
232 .read(true)
233 .write(true)
234 .create_new(true)
235 .open(path)
236 .await
237 .expect("Cannot create the log file.")
238 }
239
240 async fn get_index(&self, time_prefix: &str) -> usize {
243 let mut count = 0;
244 loop {
245 let path = self.get_path(time_prefix, count);
246 if let Ok(_) = File::open(path).await {
248 count += 1
249 } else {
250 return count;
251 }
252 }
253 }
254}
255
256#[cfg(not(feature = "async"))]
257impl Logger {
258 pub(crate) fn init(&mut self, setting: Setting) {
260 if self.init {
261 let position = position!().to_string();
262 self.warn("Log writer had been initialized!", position);
263 return;
264 }
265
266 self.file = None;
267 self.used_length = 0;
268
269 self.setting = setting;
270
271 self.init = true;
272 self.current_file_prefix = format!(
273 "{}",
274 chrono::Utc::now()
275 .with_timezone(&FixedOffset::east_opt(self.setting.time_zone * 3600).unwrap())
276 .format("%Y-%m-%d")
277 );
278 self.current_index = self.get_index(&self.current_file_prefix);
279 }
280
281 pub(crate) fn clear_dir(&mut self) {
283 fs::remove_dir_all(&self.setting.dir_path).expect("Cannot remove the dir.");
284 fs::create_dir(&self.setting.dir_path).expect("Cannot create the dir.");
285 self.current_index = 0;
286 self.used_length = 0;
287 self.file = None;
288 self.current_file_prefix = format!(
289 "{}",
290 chrono::Utc::now()
291 .with_timezone(&FixedOffset::east_opt(self.setting.time_zone * 3600).unwrap())
292 .format(&self.setting.file_time_format)
293 );
294 }
295
296 fn write(&mut self, msg: &LogMessage) {
298 if self.setting.disabled {
299 return;
300 }
301
302 if self.file.is_none() {
303 self.file = Some(self.get_file());
304 }
305
306 for i in msg.split_enter() {
307 let time_prefix = format!(
310 "{}",
311 chrono::Utc::now()
312 .with_timezone(&FixedOffset::east_opt(self.setting.time_zone * 3600).unwrap())
313 .format("%Y-%m-%d")
314 );
315 if self.current_file_prefix != time_prefix {
316 self.current_file_prefix = time_prefix;
317 self.current_index = self.get_index(&self.current_file_prefix);
318 self.used_length = 0;
319 self.file = Some(self.get_file());
320 };
321
322 if self.setting.print_out
325 && self.setting.terminal_print_level.get_level() <= i.get_level()
326 {
327 println!("{}", i.print())
328 };
329
330 if self.setting.file_record_level.get_level() <= i.get_level() {
333 self.file
334 .as_mut()
335 .unwrap()
336 .write_all((i.print() + "\n").as_bytes())
337 .expect("Cannot write into the log file.");
338 self.used_length += 1;
339 };
340 }
341
342 if self.setting.single_length != 0 && self.used_length >= self.setting.single_length {
343 self.current_index += 1;
344 self.used_length = 0;
345 self.file = None;
346 }
347 }
348
349 pub fn record(&mut self, log_level: LogLevel, message: &str, position: String) {
351 if !self.init {
352 self.init = true
353 }
354 let mut msg = LogMessage::new(
355 log_level,
356 message.to_string(),
357 self.setting.time_zone,
358 position,
359 );
360 msg.time.detailed_display = self.setting.time_detailed_display;
361 self.write(&msg);
362 }
363
364 pub fn info(&mut self, message: &str, position: String) {
366 self.record(LogLevel::Info, message, position);
367 }
368
369 pub fn debug(&mut self, message: &str, position: String) {
371 self.record(LogLevel::Debug, message, position);
372 }
373
374 pub fn warn(&mut self, message: &str, position: String) {
376 self.record(LogLevel::Warn, message, position);
377 }
378
379 pub fn error(&mut self, message: &str, position: String) {
381 self.record(LogLevel::Error, message, position);
382 }
383
384 pub fn trace(&mut self, message: &str, position: String) {
386 self.record(LogLevel::Trace, message, position);
387 }
388
389 fn get_index(&self, time_prefix: &str) -> usize {
392 let mut count = 0;
393 loop {
394 let path = self.get_path(time_prefix, count);
395 if let Ok(_) = File::open(path) {
397 count += 1
398 } else {
399 return count;
400 }
401 }
402 }
403
404 fn get_file(&self) -> File {
406 let path = self.get_path(&self.current_file_prefix, self.current_index);
407 File::options()
409 .read(true)
410 .write(true)
411 .create_new(true)
412 .open(path)
413 .expect("Cannot create the log file.")
414 }
415}
416
417unsafe impl Send for Logger {}