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 let wr_th = thread::spawn(move ||{
42 let mut w = w;
43 loop {
44 w.fetch_logs();
45
46 if w.is_terminate() {
47 break;
49 }
50 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 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 poster.set_terminate(true);
77 break;
78 }
79
80 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 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}