1use crate::{
2 config::Builder, console_impl::LoggerSinkConsole, file_impl::LoggerSinkFile, time::Timer,
3};
4use arc_swap::ArcSwap;
5use backtrace::Backtrace;
6use lazy_static::lazy_static;
7use log::*;
8use parking_lot::Mutex;
9use signal_hook::iterator::Signals;
10use std::mem::transmute;
11use std::sync::{
12 Arc,
13 atomic::{AtomicBool, Ordering},
14};
15use std::thread;
16
17#[enum_dispatch]
18pub(crate) trait LoggerSinkTrait {
19 fn reopen(&self) -> std::io::Result<()>;
20
21 fn log(&self, now: &Timer, r: &Record);
22}
23
24#[enum_dispatch(LoggerSinkTrait)]
25pub enum LoggerSink {
26 File(LoggerSinkFile),
27 Console(LoggerSinkConsole),
28}
29
30struct GlobalLogger {
32 config_checksum: u64,
34 inner: Option<LoggerInner>,
37 signal_listener: AtomicBool,
38}
39
40enum LoggerInner {
41 Once(Vec<LoggerSink>),
42 Dyn(ArcSwap<Vec<LoggerSink>>),
44}
45
46#[inline(always)]
47fn panic_or_error() {
48 #[cfg(debug_assertions)]
49 {
50 panic!("GlobalLogger cannot be initialized twice on dynamic==false");
51 }
52 #[cfg(not(debug_assertions))]
53 {
54 eprintln!("GlobalLogger cannot be initialized twice on dynamic==false");
55 }
56}
57
58impl LoggerInner {
59 #[allow(dead_code)]
60 fn set(&self, sinks: Vec<LoggerSink>) {
61 match &self {
62 Self::Once(_) => {
63 panic_or_error();
64 }
65 Self::Dyn(d) => {
66 d.store(Arc::new(sinks));
67 }
68 }
69 }
70}
71
72impl GlobalLogger {
73 pub fn reopen(&mut self) -> std::io::Result<()> {
74 if let Some(inner) = self.inner.as_ref() {
75 match &inner {
76 LoggerInner::Once(inner) => {
77 for sink in inner.iter() {
78 sink.reopen()?;
79 }
80 }
81 LoggerInner::Dyn(inner) => {
82 let sinks = inner.load();
83 for sink in sinks.iter() {
84 sink.reopen()?;
85 }
86 }
87 }
88 }
89 println!("log sinks re-opened");
90 Ok(())
91 }
92
93 #[allow(dead_code)]
94 fn init(&mut self, builder: &Builder) -> std::io::Result<bool> {
95 let new_checksum = builder.cal_checksum();
96 if self.inner.is_some() {
97 if self.config_checksum == new_checksum {
98 self.reopen()?;
100 return Ok(true);
101 }
102 if !builder.dynamic {
103 panic_or_error();
104 return Ok(false);
105 }
106 }
107 let mut sinks = Vec::new();
108 for config in &builder.sinks {
109 let logger_sink = config.build();
110 logger_sink.reopen()?;
111 sinks.push(logger_sink);
112 }
113
114 if let Some(inner) = self.inner.as_ref() {
115 inner.set(sinks);
116 } else {
117 if builder.dynamic {
118 self.inner.replace(LoggerInner::Dyn(ArcSwap::new(Arc::new(sinks))));
119 } else {
120 self.inner.replace(LoggerInner::Once(sinks));
121 }
122 }
123 self.config_checksum = new_checksum;
124
125 let _ = unsafe { set_logger(transmute::<&Self, &'static Self>(self)) };
126
127 if builder.continue_when_panic {
129 std::panic::set_hook(Box::new(panic_no_exit_hook));
130 } else {
131 std::panic::set_hook(Box::new(panic_and_exit_hook));
132 }
133 Ok(true)
134 }
135}
136
137impl Log for GlobalLogger {
138 #[inline(always)]
139 fn enabled(&self, _m: &Metadata) -> bool {
140 true
141 }
142
143 #[inline(always)]
144 fn log(&self, r: &Record) {
145 let now = Timer::new();
146 if let Some(inner) = self.inner.as_ref() {
147 match &inner {
148 LoggerInner::Once(inner) => {
149 for sink in inner.iter() {
150 sink.log(&now, r);
151 }
152 }
153 LoggerInner::Dyn(inner) => {
154 let sinks = inner.load();
155 for sink in sinks.iter() {
156 sink.log(&now, r);
157 }
158 }
159 }
160 }
161 }
162
163 fn flush(&self) {}
164}
165
166lazy_static! {
167 static ref GLOBAL_LOGGER: Mutex<GlobalLogger> = Mutex::new(GlobalLogger {
170 config_checksum: 0,
171 inner: None ,
172 signal_listener: AtomicBool::new(false),
173 });
174}
175
176#[doc(hidden)]
178pub fn log_panic(info: &std::panic::PanicHookInfo) {
179 let bt = Backtrace::new();
180 let mut record = log::Record::builder();
181 record.level(log::Level::Error);
182 if let Some(loc) = info.location() {
183 record.file(Some(loc.file())).line(Some(loc.line()));
184 }
185 log::logger().log(&record.args(format_args!("panic occur: {}\ntrace: {:?}", info, bt)).build());
186 eprint!("panic occur: {} at {:?}\ntrace: {:?}", info, info.location(), bt);
187}
188
189#[inline(always)]
190fn panic_and_exit_hook(info: &std::panic::PanicHookInfo) {
191 log_panic(info);
192 let msg = format!("{}", info).to_string();
193 std::panic::resume_unwind(Box::new(msg));
194}
195
196#[inline(always)]
197fn panic_no_exit_hook(info: &std::panic::PanicHookInfo) {
198 log_panic(info);
199 eprint!("not debug version, so don't exit process");
200}
201
202fn signal_listener(signals: Vec<i32>) {
203 let started;
204 {
205 let global_logger = GLOBAL_LOGGER.lock();
206 started = global_logger.signal_listener.swap(true, Ordering::SeqCst);
207 }
208 if started {
209 eprintln!("signal listener already started");
211 return;
212 }
213 thread::spawn(move || {
214 let mut signals = Signals::new(&signals).unwrap();
215 for __sig in signals.forever() {
216 {
217 let mut global_logger = GLOBAL_LOGGER.lock();
218 let _ = global_logger.reopen();
219 }
220 }
221 });
222}
223
224pub fn setup_log(builder: Builder) -> Result<(), ()> {
226 {
227 let mut global_logger = GLOBAL_LOGGER.lock();
228
229 match global_logger.init(&builder) {
230 Err(e) => {
231 println!("Initialize logger failed: {:?}", e);
232 return Err(());
233 }
234 Ok(false) => return Err(()),
235 Ok(true) => {}
236 }
237 set_max_level(builder.get_max_level());
238 }
239 let signals = builder.rotation_signals.clone();
240 if signals.len() > 0 {
241 signal_listener(signals);
242 }
243 Ok(())
244}