hp_log/
logger.rs

1use crate::writer::Writer;
2use crate::event::Event;
3use crate::config::Config;
4use crate::appender::{FileAppender, ConsoleAppender};
5
6use std::thread;
7use std::sync::{mpsc, Mutex};
8
9pub enum EventType {
10    Log(Event),
11    Terminate,
12}
13
14lazy_static! {
15    pub static ref LOGGER_OBJ : Logger = Logger::init();
16}
17
18#[allow(unused)]
19pub struct Logger {
20    wr_th: Mutex<Option<thread::JoinHandle<()>>>,
21    fmt_th: Mutex<Option<thread::JoinHandle<()>>>,
22    poster: Mutex<mpsc::Sender<EventType>>,
23}
24
25impl Logger {
26    pub fn init() -> Self {
27        let mut w = Writer::new();
28        let poster = w.get_poster();
29
30        let console_conf = Config::instance().console_conf();
31        if console_conf.switch {
32            w.add_appender(Box::new(ConsoleAppender::new(console_conf)));
33        }
34
35        let file_conf = Config::instance().file_conf();
36        if file_conf.switch {
37            w.add_appender(Box::new(FileAppender::new(file_conf, Config::instance().file_temp_buf(), Config::instance().file_log_dir())));
38        }
39
40        // init writer thread
41        let wr_th = thread::spawn(move ||{
42            let mut w = w;
43            loop {
44                w.fetch_logs();
45
46                if w.is_terminate() {
47                    //println!("writer thread exit!!");
48                    break;
49                }
50                // release cpu every frame 
51                // todo : to be more intelligent
52                //thread::sleep(Duration::from_micros(1u64));
53                thread::yield_now();
54            }
55        });
56
57        let (tx, rx) = mpsc::channel();
58        let fmt_th = thread::spawn(move || {
59            let mut is_stop: bool = false;
60            loop {
61                for msg in rx.iter() {
62                    // todo : handle msg 
63                    match msg {
64                        EventType::Log(log) => {
65                            poster.insert_log(log.to_logic());
66                        },
67                        EventType::Terminate => {
68                            is_stop = true;
69                            break;
70                        },
71                    }
72                }
73
74                if is_stop {
75                    //println!("farmat thread exit!!");
76                    poster.set_terminate(true);
77                    break;
78                }
79
80                // release cpu every frame 
81                // todo : to be more intelligent
82                //thread::sleep(Duration::from_micros(1u64));
83                thread::yield_now();
84            }
85        });
86
87        Self {
88            wr_th: Mutex::new(Some(wr_th)),
89            fmt_th: Mutex::new(Some(fmt_th)),
90            poster: Mutex::new(tx),
91        }
92    }    
93
94    pub fn get_poster(&self) -> mpsc::Sender<EventType> {
95        self.poster.lock().unwrap().clone()
96    }
97
98    pub fn close() {
99        //println!("logger closing");
100        if let Err(e) = LOGGER_OBJ.get_poster().send(EventType::Terminate) {
101            panic!("can not send terminate info to log threads! error: {}", e.to_string());
102        }
103        if let Some(w_th) = LOGGER_OBJ.wr_th.lock().expect("get write thread failed").take() {
104            w_th.join().expect("Couldn't join on the associated thread");
105        }
106        if let Some(fmt_th) = LOGGER_OBJ.fmt_th.lock().expect("get format thread failed").take() {
107            fmt_th.join().expect("Couldn't join on the associated thread");
108        }
109    }
110    
111}
112
113pub trait SendEvent {
114    fn send_event(&self, e: Event);
115}
116
117#[allow(unused)]
118impl SendEvent for mpsc::Sender<EventType> {
119    fn send_event(&self, e: Event) {
120        self.send(EventType::Log(e));
121    }
122}
123
124pub struct ThreadLocalLogger {
125    sender: mpsc::Sender<EventType>,
126    thread_tag: String,
127} 
128
129impl ThreadLocalLogger {
130    pub fn new() -> Self {
131        let tid: u64 = unsafe { std::mem::transmute(thread::current().id()) };
132        let thread_tag = match thread::current().name() {
133            Some(ref name) => format!("{}:[{}]", name.to_string(), tid),
134            None => format!("thread:[{}]", tid),
135        };
136
137        Self {
138            sender: LOGGER_OBJ.get_poster(),
139            thread_tag, 
140        }
141    }
142
143    pub fn get_thread_tag(&self) -> String {
144        self.thread_tag.clone()
145    }
146
147    pub fn get_sender(&self) -> &mpsc::Sender<EventType> {
148        &self.sender
149    }
150
151}
152
153impl Default for ThreadLocalLogger {
154    fn default() -> Self {
155        Self::new()
156    }
157}