Skip to main content

flashlog/
logger.rs

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};
9//
10//use anyhow::{anyhow, Ok, Result};
11use 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));
25//2_000_000; // string length
26pub static LOG_MESSAGE_FLUSH_INTERVAL: Lazy<AtomicU64> = Lazy::new(|| AtomicU64::new(0));
27//2_000_000_000; // 2 second
28
29pub 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)); // -1 means that setting affinity to any remaining core
36
37pub 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//---------
296#[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            //
361            $(
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    // In case of structs
403    ($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    // In case of structs
532    ($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}