1use crate::flash_trace;
2use crate::timer::get_unix_nano;
3use crate::rolling_file::{
4 RollingFileWriter,
5 RollingConfig,
6 RollingPeriod,
7 set_initial_log_file_path,
8};
9use chrono;
12use core_affinity;
13use crossbeam_channel::{unbounded, Sender};
14use once_cell::sync::Lazy;
15use std::path::PathBuf;
16use std::{
17 sync::{
18 atomic::{AtomicBool, AtomicI32, AtomicUsize, Ordering, AtomicU64},
19 Mutex,
20 },
21 thread,
22};
23
24pub static LOG_MESSAGE_BUFFER_SIZE: Lazy<AtomicUsize> = Lazy::new(|| AtomicUsize::new(0));
25pub static LOG_MESSAGE_FLUSH_INTERVAL: Lazy<AtomicU64> = Lazy::new(|| AtomicU64::new(0));
27pub static INCLUDE_UNIXNANO: Lazy<AtomicBool> = Lazy::new(|| AtomicBool::new(false));
30pub static MAX_LOG_LEVEL: Lazy<AtomicUsize> = Lazy::new(|| AtomicUsize::new(LogLevel::NIL.as_usize()));
31pub static TIMEZONE: Lazy<AtomicI32> = Lazy::new(|| AtomicI32::new(TimeZone::Local as i32));
32pub static CONSOLE_REPORT: Lazy<AtomicBool> = Lazy::new(|| AtomicBool::new(false));
33pub static FILE_REPORT: Lazy<AtomicBool> = Lazy::new(|| AtomicBool::new(false));
34pub static LOGGER_HANDLER: Lazy<Mutex<Option<thread::JoinHandle<()>>>> =Lazy::new(|| Mutex::new(None));
35pub static LOGGER_CORE: Lazy<AtomicI32> = Lazy::new(|| AtomicI32::new(-1)); pub static LOG_SENDER: Lazy<Sender<LogMessage>> = Lazy::new(|| {
38 let (sender, receiver) = unbounded();
39
40 let mut message_queue: Vec<String> = Vec::with_capacity(LOG_MESSAGE_BUFFER_SIZE.load(Ordering::SeqCst).max(10));
41 let mut last_flush_time = get_unix_nano();
42
43 let mut msg_buffer_size = LOG_MESSAGE_BUFFER_SIZE.load(Ordering::SeqCst);
44 let mut msg_flush_interval = LOG_MESSAGE_FLUSH_INTERVAL.load(Ordering::SeqCst);
45 let mut file_report = FILE_REPORT.load(Ordering::Relaxed);
46 let mut console_report = CONSOLE_REPORT.load(Ordering::Relaxed);
47
48 let affinity_core = LOGGER_CORE.load(Ordering::SeqCst);
49
50 *LOGGER_HANDLER.lock().expect("Logger hander lock") = Some(thread::spawn(move || {
51 let mut rolling_writer: Option<RollingFileWriter> = None;
52 while let Ok(msg) = receiver.recv() {
53 match msg {
54 LogMessage::LazyMessage(lazy_message) => {
55 let message = lazy_message.eval();
56 let current_timestamp = get_unix_nano();
57 message_queue.push(message);
58
59 if msg_buffer_size == 0 || msg_flush_interval == 0 || (message_queue.len() >= msg_buffer_size) || (current_timestamp >= msg_flush_interval + last_flush_time) {
60 let output = message_queue.join("");
61
62 if file_report {
63 if let Some(ref mut writer) = rolling_writer {
64 writer.write_all(output.as_bytes()).unwrap();
65 }
66 }
67
68 if console_report { println!("{}", output); }
69
70 message_queue.clear();
71
72 last_flush_time = current_timestamp;
73 }
74 }
75 LogMessage::FlushingMessage(lazy_message) => {
76 let message = lazy_message.eval();
77 message_queue.push(message);
78
79 let output = message_queue.join("");
80 if file_report {
81 if let Some(ref mut writer) = rolling_writer {
82 writer.write_all(output.as_bytes()).unwrap();
83 }
84 }
85 if console_report {
86 println!("{}", output);
87 }
88
89 message_queue.clear();
90 last_flush_time = get_unix_nano();
91 }
92 LogMessage::StaticString(message) => {
93 let buffer_size = message_queue.len();
94 let timestamp = get_unix_nano();
95 message_queue.push(message.to_string());
96
97 if (buffer_size + message.len() >= msg_buffer_size)
98 || (timestamp >= msg_flush_interval + last_flush_time)
99 {
100 let output = message_queue.join("");
101 if file_report {
102 if let Some(ref mut writer) = rolling_writer {
103 writer.write_all(output.as_bytes()).unwrap();
104 }
105 }
106
107 if console_report {
108 println!("{}", output);
109 }
110 }
111 }
112 LogMessage::SetFile(config) => {
113 if let Some(ref mut writer) = rolling_writer {
114 writer.flush().expect("Failed to flush log file writer");
115 let _ = writer.sync_all();
116 } else {
117 let writer = RollingFileWriter::new(config).expect("Failed to create RollingFileWriter");
118 rolling_writer = Some(writer);
119 }
120 }
121 LogMessage::Flush => {
122 let output = message_queue.join("");
123 if file_report {
124 if let Some(ref mut writer) = rolling_writer {
125 writer.write_all(output.as_bytes()).unwrap();
126 writer.flush().expect("Failed to flush log file writer");
127 let _ = writer.sync_all();
128 }
129 }
130 if console_report {
131 println!("{}", output);
132 }
133 message_queue.clear();
134 last_flush_time = get_unix_nano();
135 }
136 LogMessage::SetCore => {
137 let available_core_ids = core_affinity::get_core_ids().expect("Failed to get available core IDs");
138 let core_id = if affinity_core == -1 {
139 available_core_ids.first().cloned()
140 } else {
141 let core_id = core_affinity::CoreId { id: affinity_core as usize };
142 if available_core_ids.contains(&core_id) {
143 Some(core_id)
144 } else {
145 available_core_ids.first().cloned()
146 }
147 };
148
149 if let Some(core_id) = core_id {
150 core_affinity::set_for_current(core_id);
151 }
152 }
153 LogMessage::Close => {
154 let output = message_queue.join("");
155 if file_report {
156 if let Some(ref mut writer) = rolling_writer {
157 writer.write_all(output.as_bytes()).unwrap();
158 writer.flush().expect("Failed to flush log file writer in Close");
159 let _ = writer.sync_all();
160 }
161 }
162 if console_report {
163 println!("{}", output);
164 }
165 break;
166 }
167 LogMessage::SetConfig => {
168 msg_buffer_size = LOG_MESSAGE_BUFFER_SIZE.load(Ordering::Relaxed);
169 msg_flush_interval = LOG_MESSAGE_FLUSH_INTERVAL.load(Ordering::Relaxed);
170 file_report = FILE_REPORT.load(Ordering::Relaxed);
171 console_report = CONSOLE_REPORT.load(Ordering::Relaxed);
172 }
173 }
174 }
175 }));
176 sender
177});
178
179pub enum TimeZone {
180 Local,
181 Seoul,
182 Japan,
183 NewYork,
184}
185
186impl TimeZone {
187 #[inline]
188 pub fn as_offset_hour(&self) -> i32 {
189 match self {
190 TimeZone::Local => {
191 let local = chrono::Local::now();
192 let offset = local.offset().local_minus_utc() / 3600;
193 offset
194 }
195 TimeZone::Seoul => 9,
196 TimeZone::Japan => 9,
197 TimeZone::NewYork => -4,
198 }
199 }
200}
201
202#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
203pub enum LogLevel {
204 NIL = 0,
205 Error = 1,
206 Warn = 2,
207 Info = 3,
208 Debug = 4,
209 Trace = 5,
210}
211
212impl LogLevel {
213 #[inline]
214 pub fn as_usize(&self) -> usize {
215 match self {
216 LogLevel::NIL => 0,
217 LogLevel::Error => 1,
218 LogLevel::Warn => 2,
219 LogLevel::Info => 3,
220 LogLevel::Debug => 4,
221 LogLevel::Trace => 5,
222 }
223 }
224
225 #[inline]
226 pub fn from_usize(level: usize) -> Result<LogLevel, &'static str> {
227 match level {
228 0 => Ok(LogLevel::NIL),
229 1 => Ok(LogLevel::Error),
230 2 => Ok(LogLevel::Warn),
231 3 => Ok(LogLevel::Info),
232 4 => Ok(LogLevel::Debug),
233 5 => Ok(LogLevel::Trace),
234 _ => {
235 Err("Invalid log level")
236 }
237 }
238 }
239}
240
241impl std::fmt::Display for LogLevel {
242 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
243 match self {
244 LogLevel::NIL => write!(f, "Nil"),
245 LogLevel::Trace => write!(f, "Trace"),
246 LogLevel::Debug => write!(f, "Debug"),
247 LogLevel::Info => write!(f, "Info"),
248 LogLevel::Error => write!(f, "Error"),
249 LogLevel::Warn => write!(f, "Warn"),
250 }
251 }
252}
253
254#[deprecated(since = "0.2.0", note = "Use flashlog::flash_trace! instead")]
255#[macro_export]
256macro_rules! trace {
257 ($($arg:tt)*) => {{
258 $crate::log_fn_json!($crate::LogLevel::Trace, "not given", text = format!($($arg)*));
259 }};
260}
261
262
263#[deprecated(since = "0.2.0", note = "Use flashlog::flash_debug! instead")]
264#[macro_export]
265macro_rules! debug {
266 ($($arg:tt)*) => {{
267 $crate::log_fn_json!($crate::LogLevel::Debug, "not given", text = format!($($arg)*));
268 }};
269}
270
271#[deprecated(since = "0.2.0", note = "Use flashlog::flash_info! instead")]
272#[macro_export]
273macro_rules! info {
274 ($($arg:tt)*) => {{
275 $crate::log_fn_json!($crate::LogLevel::Info, "not given", text = format!($($arg)*));
276 }};
277}
278
279#[deprecated(since = "0.2.0", note = "Use flashlog::flash_warn! instead")]
280#[macro_export]
281macro_rules! warn {
282 ($($arg:tt)*) => {{
283 $crate::log_fn_json!($crate::LogLevel::Warn, "not given", text = format!($($arg)*));
284 }};
285}
286
287#[deprecated(since = "0.2.0", note = "Use flashlog::flash_error! instead")]
288#[macro_export]
289macro_rules! error {
290 ($($arg:tt)*) => {{
291 $crate::log_fn_json!($crate::LogLevel::Error, "not given", text = format!($($arg)*));
292 }};
293}
294
295#[deprecated(since = "0.2.0", note = "Use flashlog::flash_trace! instead")]
297#[macro_export]
298macro_rules! log_trace {
299 ($topic:expr, $($key:ident=$value:expr),+ $(,)?) => {{
300 $crate::log_fn_json!($crate::LogLevel::Trace, $topic, $($key=$value),+);
301 }};
302
303 ($topic:expr, $struct:expr) => {{
304 $crate::log_fn_json!($crate::LogLevel::Trace, $topic, $struct);
305 }};
306}
307
308#[deprecated(since = "0.2.0", note = "Use flashlog::flash_debug! instead")]
309#[macro_export]
310macro_rules! log_debug {
311 ($topic:expr, $($key:ident=$value:expr),+ $(,)?) => {{
312 $crate::log_fn_json!($crate::LogLevel::Debug, $topic, $($key=$value),+);
313 }};
314 ($topic:expr, $struct:expr) => {{
315 $crate::log_fn_json!($crate::LogLevel::Debug, $topic, $struct);
316 }};
317}
318
319#[deprecated(since = "0.2.0", note = "Use flashlog::flash_info! instead")]
320#[macro_export]
321macro_rules! log_info {
322 ($topic:expr, $($key:ident=$value:expr),+ $(,)?) => {{
323 $crate::log_fn_json!($crate::LogLevel::Info, $topic, $($key=$value),+);
324 }};
325 ($topic:expr, $struct:expr) => {{
326 $crate::log_fn_json!($crate::LogLevel::Info, $topic, $struct);
327 }};
328}
329
330
331#[deprecated(since = "0.2.0", note = "Use flashlog::flash_warn! instead")]
332#[macro_export]
333macro_rules! log_warn {
334 ($topic:expr, $($key:ident=$value:expr),+ $(,)?) => {{
335 $crate::log_fn_json!($crate::LogLevel::Warn, $topic, $($key=$value),+);
336 }};
337 ($topic:expr, $struct:expr) => {{
338 $crate::log_fn_json!($crate::LogLevel::Warn, $topic, $struct);
339 }};
340}
341
342
343#[deprecated(since = "0.2.0", note = "Use flashlog::flash_error! instead")]
344#[macro_export]
345macro_rules! log_error {
346 ($topic:expr, $($key:ident=$value:expr),+ $(,)?) => {{
347 $crate::log_fn_json!($crate::LogLevel::Error, $topic, $($key=$value),+);
348 }};
349 ($topic:expr, $struct:expr) => {{
350 $crate::log_fn_json!($crate::LogLevel::Error, $topic, $struct);
351 }};
352}
353
354#[macro_export]
355macro_rules! log_fn_json {
356 ($level:expr, $topic:expr, $($key:ident=$value:expr),+ $(,)?) => {{
357 if $level <= $crate::LogLevel::from_usize($crate::MAX_LOG_LEVEL.load(std::sync::atomic::Ordering::Relaxed)).expect("Invalid log level") {
358 let unixnano = $crate::get_unix_nano();
359 let include_unixnano = $crate::logger::INCLUDE_UNIXNANO.load(std::sync::atomic::Ordering::Relaxed);
360 $(
362 #[allow(non_snake_case)]
363 let $key = $value.clone();
364 )*
365 let func = move || {
366 let json_obj = $crate::serde_json::json!({
367 $(
368 stringify!($key): $key,
369 )+
370 });
371 let timezone = $crate::TIMEZONE.load(std::sync::atomic::Ordering::Relaxed);
372 let (date, time) = $crate::convert_unix_nano_to_date_and_time(unixnano, timezone);
373 let json_msg = match include_unixnano {
374 false => $crate::serde_json::json!({
375 "date": date,
376 "time": time,
377 "offset": timezone,
378 "level": $level.to_string(),
379 "src": format!("{}:{}", file!(), line!()),
380 "topic": $topic,
381 "data": json_obj,
382 }),
383 true => $crate::serde_json::json!({
384 "date": date,
385 "time": time,
386 "offset": timezone,
387 "level": $level.to_string(),
388 "src": format!("{}:{}", file!(), line!()),
389 "topic": $topic,
390 "data": json_obj,
391 "unixnano": unixnano,
392 }),
393 };
394
395 json_msg.to_string() + "\n"
396 };
397
398 $crate::LOG_SENDER.try_send($crate::LogMessage::LazyMessage($crate::LazyMessage::new(func))).unwrap();
399 }
400 }};
401
402 ($level:expr, $topic:expr, $struct:expr) => {{
404 if $level <= $crate::LogLevel::from_usize($crate::LOG_LEVEL.load(std::sync::atomic::Ordering::Relaxed)).expect("Invalid log level") {
405 let unixnano = $crate::get_unix_nano();
406 let include_unixnano = $crate::logger::INCLUDE_UNIXNANO.load(std::sync::atomic::Ordering::Relaxed);
407 #[allow(non_snake_case)]
408 let struct_clone = $struct.clone();
409 let func = move || {
410 let json_obj = $crate::serde_json::to_value(struct_clone).unwrap_or_else(|e| {
411 $crate::serde_json::json!({ "error": format!("serialization error: {}", e) })
412 });
413 let timezone = $crate::TIMEZONE.load(std::sync::atomic::Ordering::Relaxed);
414 let (date, time) = $crate::convert_unix_nano_to_date_and_time(unixnano, timezone);
415 let json_msg = match include_unixnano {
416 false => $crate::serde_json::json!({
417 "date": date,
418 "time": time,
419 "offset": timezone,
420 "level": $level.to_string(),
421 "src": format!("{}:{}", file!(), line!()),
422 "topic": $topic,
423 "data": json_obj,
424 }),
425 true => $crate::serde_json::json!({
426 "date": date,
427 "time": time,
428 "offset": timezone,
429 "level": $level.to_string(),
430 "src": format!("{}:{}", file!(), line!()),
431 "topic": $topic,
432 "data": json_obj,
433 "unixnano": unixnano,
434 }),
435 };
436
437 json_msg.to_string() + "\n"
438 };
439
440 $crate::LOG_SENDER.try_send($crate::LogMessage::LazyMessage($crate::LazyMessage::new(func))).unwrap();
441 }
442 }};
443}
444
445#[deprecated(since = "0.2.0", note = "Use flashlog::flush! instead")]
446#[macro_export]
447macro_rules! flushing_log_info {
448 ($topic:expr, $($key:ident=$value:expr),+ $(,)?) => {{
449 $crate::flushing_log_fn_json!($crate::LogLevel::Info, $topic, $($key=$value),+);
450 }};
451 ($topic:expr, $struct:expr) => {{
452 $crate::flushing_log_fn_json!($crate::LogLevel::Info, $topic, $struct);
453 }};
454}
455
456#[deprecated(since = "0.2.0", note = "Use flashlog::flush! instead")]
457#[macro_export]
458macro_rules! flushing_log_debug {
459 ($topic:expr, $($key:ident=$value:expr),+ $(,)?) => {{
460 $crate::flushing_log_fn_json!($crate::LogLevel::Debug, $topic, $($key=$value),+);
461 }};
462 ($topic:expr, $struct:expr) => {{
463 $crate::flushing_log_fn_json!($crate::LogLevel::Debug, $topic, $struct);
464 }};
465}
466
467#[deprecated(since = "0.2.0", note = "Use flashlog::flush! instead")]
468#[macro_export]
469macro_rules! flushing_log_error {
470 ($topic:expr, $($key:ident=$value:expr),+ $(,)?) => {{
471 $crate::flushing_log_fn_json!($crate::LogLevel::Error, $topic, $($key=$value),+);
472 }};
473 ($topic:expr, $struct:expr) => {{
474 $crate::flushing_log_fn_json!($crate::LogLevel::Error, $topic, $struct);
475 }};
476}
477
478#[deprecated(since = "0.2.0", note = "Use flashlog::flush! instead")]
479#[macro_export]
480macro_rules! flushing_log_trace {
481 ($topic:expr, $($key:ident=$value:expr),+ $(,)?) => {{
482 $crate::flushing_log_fn_json!($crate::LogLevel::Trace, $topic, $($key=$value),+);
483 }};
484 ($topic:expr, $struct:expr) => {{
485 $crate::flushing_log_fn_json!($crate::LogLevel::Trace, $topic, $struct);
486 }};
487}
488
489#[macro_export]
490macro_rules! flushing_log_fn_json {
491 ($level:expr, $topic:expr, $($key:ident=$value:expr),+ $(,)?) => {{
492 if $level <= $crate::LogLevel::from_usize($crate::MAX_LOG_LEVEL.load(std::sync::atomic::Ordering::Relaxed)).expect("Invalid log level") {
493 let unixnano = $crate::get_unix_nano();
494 let include_unixnano = $crate::logger::INCLUDE_UNIXNANO.load(std::sync::atomic::Ordering::Relaxed);
495 let func = move || {
496 let json_obj = $crate::serde_json::json!({
497 $(
498 stringify!($key): $value,
499 )+
500 });
501 let timezone = $crate::TIMEZONE.load(std::sync::atomic::Ordering::Relaxed);
502 let (date, time) = $crate::convert_unix_nano_to_date_and_time(unixnano, timezone);
503 let json_msg = match include_unixnano {
504 true => $crate::serde_json::json!({
505 "date": date,
506 "time": time,
507 "offset": timezone,
508 "level": $level.to_string(),
509 "src": format!("{}:{}", file!(), line!()),
510 "topic": $topic,
511 "data": json_obj,
512 "unixnano": unixnano,
513 }),
514 false => $crate::serde_json::json!({
515 "date": date,
516 "time": time,
517 "offset": timezone,
518 "level": $level.to_string(),
519 "src": format!("{}:{}", file!(), line!()),
520 "topic": $topic,
521 "data": json_obj,
522 }),
523 };
524 json_msg.to_string() + "\n"
525 };
526
527 $crate::LOG_SENDER.try_send($crate::LogMessage::FlushingMessage($crate::LazyMessage::new(func))).unwrap();
528 }
529 }};
530
531 ($level:expr, $topic:expr, $struct:expr) => {{
533 if $level <= $crate::LogLevel::from_usize($crate::LOG_LEVEL.load(std::sync::atomic::Ordering::Relaxed)).unwrap() {
534 let unixnano = $crate::get_unix_nano();
535 let include_unixnano = $crate::logger::INCLUDE_UNIXNANO.load(std::sync::atomic::Ordering::Relaxed);
536 let func = move || {
537 let json_obj = $crate::serde_json::to_value($struct).unwrap_or_else(|e| {
538 $crate::serde_json::json!({ "error": format!("serialization error: {}", e) })
539 });
540 let timezone = $crate::TIMEZONE.load(std::sync::atomic::Ordering::Relaxed);
541 let (date, time) = $crate::convert_unix_nano_to_date_and_time(timestamp, timezone);
542 match include_unixnano {
543 true => {
544 let json_msg = $crate::serde_json::json!({
545 "date": date,
546 "time": time,
547 "offset": timezone,
548 "level": $level.to_string(),
549 "src": format!("{}:{}", file!(), line!()),
550 "topic": $topic,
551 "data": json_obj,
552 "unixnano": unixnano,
553 });
554 json_msg.to_string() + "\n"
555 }
556 false => {
557 let json_msg = $crate::serde_json::json!({
558 "date": date,
559 "time": time,
560 "offset": timezone,
561 "level": $level.to_string(),
562 "src": format!("{}:{}", file!(), line!()),
563 "topic": $topic,
564 "data": json_obj,
565 });
566 json_msg.to_string() + "\n"
567 }
568 }
569 };
570 $crate::LOG_SENDER.try_send($crate::LogMessage::FlushingMessage($crate::LazyMessage::new(func))).unwrap();
571 }
572 }};
573}
574
575pub struct LoggerGuard;
576
577impl Drop for LoggerGuard {
578 fn drop(&mut self) {
579 flash_trace!("LoggerGuard"; "LoggerGuard is dropped");
580 Logger::finalize();
581 }
582}
583
584pub struct Logger {
585 file_config: Option<RollingConfig>,
586}
587
588
589#[derive(Debug)]
590pub enum LoggerError {
591 UnsetFile,
592}
593
594impl std::fmt::Display for LoggerError {
595 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
596 match self {
597 LoggerError::UnsetFile => write!(f, "File config is not set. Use with_file first"),
598 }
599 }
600}
601
602impl std::error::Error for LoggerError {}
603
604impl Logger {
605 pub fn finalize() {
606 let _ = LOG_SENDER.try_send(LogMessage::Close);
607 if let Some(handler) = LOGGER_HANDLER.lock().expect("Failed to lock LOGGER_HANDLER").take() {
608 let _ = handler.join();
609 }
610 }
611
612 pub fn initialize() -> Logger {
613 let _ = get_unix_nano();
614 LOG_MESSAGE_BUFFER_SIZE.store(1_000_000, Ordering::Relaxed);
615 LOG_MESSAGE_FLUSH_INTERVAL.store(1_000_000, Ordering::Relaxed);
616 Logger { file_config: None }
617 }
618
619 pub fn with_file(mut self, file_path: &str, file_name: &str) -> Result<Logger, std::io::Error> {
620 std::fs::create_dir_all(file_path)?;
621
622 let config = RollingConfig {
623 base_path: PathBuf::from(file_path),
624 file_name_prefix: file_name.to_string(),
625 roll_period: Some(RollingPeriod::Daily),
626 max_roll_files: Some(10),
627 compress: false,
628 initial_file_path: None,
629 };
630
631 self.file_config = Some(config);
632 FILE_REPORT.store(true, Ordering::SeqCst);
633
634 Ok(self)
635 }
636
637 pub fn with_compress(mut self, compress: bool) -> Result<Logger, LoggerError> {
638 if let Some(ref mut config) = self.file_config {
639 config.compress = compress;
640 Ok(self)
641 } else {
642 Err(LoggerError::UnsetFile)
643 }
644 }
645
646 pub fn with_logger_core(self, core: i32) -> Logger {
647 LOGGER_CORE.store(core, Ordering::SeqCst);
648 self
649 }
650
651 pub fn with_roll_period(mut self, period: RollingPeriod) -> Result<Logger, LoggerError> {
652 if let Some(ref mut config) = self.file_config {
653 config.roll_period = Some(period);
654 Ok(self)
655 } else {
656 Err(LoggerError::UnsetFile)
657 }
658 }
659
660 pub fn include_unixnano(self, include: bool) -> Logger {
661 INCLUDE_UNIXNANO.store(include, Ordering::Relaxed);
662 self
663 }
664
665 pub fn with_max_roll_files(mut self, max_roll_files: usize) -> Result<Logger, LoggerError> {
666 if let Some(ref mut config) = self.file_config {
667 config.max_roll_files = Some(max_roll_files);
668 Ok(self)
669 } else {
670 Err(LoggerError::UnsetFile)
671 }
672 }
673
674 pub fn with_console_report(self, console_report: bool) -> Logger {
675 CONSOLE_REPORT.store(console_report, Ordering::Relaxed);
676 self
677 }
678
679 pub fn with_msg_buffer_size(self, size: usize) -> Logger {
680 LOG_MESSAGE_BUFFER_SIZE.store(size, Ordering::Relaxed);
681 self
682 }
683
684 pub fn with_msg_flush_interval(self, interval: u64) -> Logger {
685 LOG_MESSAGE_FLUSH_INTERVAL.store(interval, Ordering::Relaxed);
686 self
687 }
688
689 #[deprecated(since = "0.3.0", note = "it is recommended to use compile time filter options and use flash_xxxx_ct! instead")]
690 pub fn with_max_log_level(self, level: LogLevel) -> Logger {
691 MAX_LOG_LEVEL.store(level.as_usize(), Ordering::Relaxed);
692 self
693 }
694
695 pub fn with_timezone(self, timezone: TimeZone) -> Logger {
696 TIMEZONE.store(timezone.as_offset_hour(), Ordering::Relaxed);
697 self
698 }
699
700 pub fn launch(self) -> LoggerGuard {
701 let rolling_config = self.file_config.clone();
702 let _ = LOG_SENDER.send(LogMessage::SetCore);
703 let _ = LOG_SENDER.send(LogMessage::SetConfig);
704 if let Some(mut config) = rolling_config {
705 let file_path = set_initial_log_file_path(&config.base_path, &config.file_name_prefix);
706 config.initial_file_path = Some(file_path);
707 let _ = LOG_SENDER.send(LogMessage::SetFile(config));
708 }
709 LoggerGuard {}
710 }
711}
712
713pub enum LogMessage {
714 LazyMessage(LazyMessage),
715 FlushingMessage(LazyMessage),
716 StaticString(&'static str),
717 SetFile(RollingConfig),
718 Flush,
719 SetCore,
720 SetConfig,
721 Close,
722}
723
724pub struct LazyMessage {
725 data: Box<dyn (FnOnce() -> String) + Send + 'static>,
726}
727
728impl LazyMessage {
729 pub fn new<F>(data: F) -> LazyMessage
730 where
731 F: (FnOnce() -> String) + Send + 'static,
732 {
733 LazyMessage {
734 data: Box::new(data),
735 }
736 }
737
738 pub fn eval(self) -> String {
739 (self.data)()
740 }
741}