1use crate::{buf_file_impl::LogSinkBufFile, console_impl::LogSinkConsole, file_impl::LogSinkFile};
2use crate::{config::Builder, time::Timer};
3use arc_swap::ArcSwap;
4use backtrace::Backtrace;
5use signal_hook::iterator::Signals;
6use std::cell::UnsafeCell;
7use std::mem::transmute;
8use std::sync::{
9 atomic::{AtomicBool, AtomicU64, Ordering},
10 Arc,
11};
12use std::thread;
13
14#[enum_dispatch]
15pub(crate) trait LogSinkTrait {
16 fn open(&self) -> std::io::Result<()>;
17
18 fn reopen(&self) -> std::io::Result<()>;
19
20 fn log(&self, now: &Timer, r: &log::Record);
21
22 fn flush(&self);
23}
24
25#[enum_dispatch(LogSinkTrait)]
26pub enum LogSink {
27 File(LogSinkFile),
28 BufFile(LogSinkBufFile),
29 Console(LogSinkConsole),
30 #[cfg(feature = "syslog")]
31 Syslog(crate::syslog::LogSinkSyslog),
32 #[cfg(feature = "ringfile")]
33 RingFile(crate::ring::LogSinkRingFile),
34}
35
36struct GlobalLoggerConainer {
37 logger: UnsafeCell<GlobalLogger>,
38 lock: AtomicBool,
39}
40
41struct GlobalLoggerGuard<'a>(&'a GlobalLoggerConainer);
42
43impl Drop for GlobalLoggerGuard<'_> {
44 fn drop(&mut self) {
45 self.0.unlock();
46 }
47}
48
49impl GlobalLoggerConainer {
50 const fn new() -> Self {
51 Self {
52 logger: UnsafeCell::new(GlobalLogger {
53 config_checksum: AtomicU64::new(0),
54 inner: None,
55 signal_listener: AtomicBool::new(false),
56 }),
57 lock: AtomicBool::new(false),
58 }
59 }
60
61 fn get_logger_mut(&self) -> &mut GlobalLogger {
62 unsafe { transmute(self.logger.get()) }
63 }
64
65 fn get_logger(&self) -> &GlobalLogger {
66 unsafe { transmute(self.logger.get()) }
67 }
68
69 fn lock<'a>(&'a self) -> GlobalLoggerGuard<'a> {
70 while self
71 .lock
72 .compare_exchange_weak(false, true, Ordering::SeqCst, Ordering::Relaxed)
73 .is_err()
74 {
75 std::thread::yield_now();
77 }
78 GlobalLoggerGuard(self)
79 }
80
81 fn unlock(&self) {
82 self.lock.store(false, Ordering::SeqCst);
83 }
84
85 fn try_setup(&self, builder: &Builder) -> Result<bool, ()> {
87 let _guard = self.lock();
88 let res = { self.get_logger().check_the_same(builder) };
89 match res {
90 Some(true) => {
91 if let Err(e) = self.get_logger().open() {
92 eprintln!("failed to open log sink: {:?}", e);
93 return Err(());
94 }
95 return Ok(false);
96 }
97 Some(false) => {
98 if !builder.dynamic {
99 panic_or_error();
100 return Err(());
101 }
102 let res = self.get_logger().reinit(builder);
103 res?;
104 log::set_max_level(builder.get_max_level());
106 return Ok(false);
107 }
108 None => {
109 let res = { self.get_logger_mut().init(builder) };
110 res?;
111 return Ok(true);
112 }
113 }
114 }
115}
116
117unsafe impl Send for GlobalLoggerConainer {}
118unsafe impl Sync for GlobalLoggerConainer {}
119
120pub fn setup_log(builder: Builder) -> Result<(), ()> {
122 if let Ok(true) = GLOBAL_LOGGER.try_setup(&builder) {
123 let logger = GLOBAL_LOGGER.get_logger();
124 if let Err(e) = log::set_logger(logger) {
126 eprintln!("log::set_logger return error: {:?}", e);
127 return Err(());
128 }
129 log::set_max_level(builder.get_max_level());
130 if builder.continue_when_panic {
132 std::panic::set_hook(Box::new(panic_no_exit_hook));
133 } else {
134 std::panic::set_hook(Box::new(panic_and_exit_hook));
135 }
136 let signals = builder.rotation_signals.clone();
137 if signals.len() > 0 {
138 if false == logger.signal_listener.swap(true, Ordering::SeqCst) {
139 thread::spawn(move || {
140 GLOBAL_LOGGER.get_logger().listener_for_signal(signals);
141 });
142 }
143 }
144 }
145 Ok(())
146}
147
148struct GlobalLogger {
150 config_checksum: AtomicU64,
152 inner: Option<LoggerInner>,
155 signal_listener: AtomicBool,
156}
157
158enum LoggerInner {
159 Once(Vec<LogSink>),
160 Dyn(ArcSwap<Vec<LogSink>>),
162}
163
164#[inline(always)]
165fn panic_or_error() {
166 #[cfg(debug_assertions)]
167 {
168 panic!("GlobalLogger cannot be initialized twice on dynamic==false");
169 }
170 #[cfg(not(debug_assertions))]
171 {
172 eprintln!("GlobalLogger cannot be initialized twice on dynamic==false");
173 }
174}
175
176impl LoggerInner {
177 #[allow(dead_code)]
178 fn set(&self, sinks: Vec<LogSink>) {
179 match &self {
180 Self::Once(_) => {
181 panic_or_error();
182 }
183 Self::Dyn(d) => {
184 d.store(Arc::new(sinks));
185 }
186 }
187 }
188}
189
190impl GlobalLogger {
191 fn listener_for_signal(&self, signals: Vec<i32>) {
192 println!("signal_listener started");
193 let mut signals = Signals::new(&signals).unwrap();
194 for __sig in signals.forever() {
195 let _ = self.reopen();
196 }
197 println!("signal_listener exit");
198 }
199
200 fn open(&self) -> std::io::Result<()> {
202 if let Some(inner) = self.inner.as_ref() {
203 match &inner {
204 LoggerInner::Once(inner) => {
205 for sink in inner.iter() {
206 sink.open()?;
207 }
208 }
209 LoggerInner::Dyn(inner) => {
210 let sinks = inner.load();
211 for sink in sinks.iter() {
212 sink.open()?;
213 }
214 }
215 }
216 }
217 println!("log sinks opened");
218 Ok(())
219 }
220
221 pub fn reopen(&self) -> std::io::Result<()> {
223 if let Some(inner) = self.inner.as_ref() {
224 match &inner {
225 LoggerInner::Once(inner) => {
226 for sink in inner.iter() {
227 sink.reopen()?;
228 }
229 }
230 LoggerInner::Dyn(inner) => {
231 let sinks = inner.load();
232 for sink in sinks.iter() {
233 sink.reopen()?;
234 }
235 }
236 }
237 }
238 println!("log sinks re-opened");
239 Ok(())
240 }
241
242 fn check_the_same(&self, builder: &Builder) -> Option<bool> {
244 if self.inner.is_some() {
245 return Some(self.config_checksum.load(Ordering::Acquire) == builder.cal_checksum());
246 }
247 None
248 }
249
250 fn reinit(&self, builder: &Builder) -> Result<(), ()> {
252 let sinks = builder.build_sinks()?;
253 if let Some(inner) = self.inner.as_ref() {
254 inner.set(sinks);
255 self.config_checksum.store(builder.cal_checksum(), Ordering::Release);
256 } else {
257 unreachable!();
258 }
259 Ok(())
260 }
261
262 #[allow(dead_code)]
263 fn init(&mut self, builder: &Builder) -> Result<(), ()> {
264 let sinks = builder.build_sinks()?;
265 assert!(self.inner.is_none());
266 if builder.dynamic {
267 self.inner.replace(LoggerInner::Dyn(ArcSwap::new(Arc::new(sinks))));
268 } else {
269 self.inner.replace(LoggerInner::Once(sinks));
270 }
271 self.config_checksum.store(builder.cal_checksum(), Ordering::Release);
272 Ok(())
273 }
274}
275
276impl log::Log for GlobalLogger {
277 #[inline(always)]
278 fn enabled(&self, _m: &log::Metadata) -> bool {
279 true
280 }
281
282 #[inline(always)]
283 fn log(&self, r: &log::Record) {
284 let now = Timer::new();
285 if let Some(inner) = self.inner.as_ref() {
286 match &inner {
287 LoggerInner::Once(inner) => {
288 for sink in inner.iter() {
289 sink.log(&now, r);
290 }
291 }
292 LoggerInner::Dyn(inner) => {
293 let sinks = inner.load();
294 for sink in sinks.iter() {
295 sink.log(&now, r);
296 }
297 }
298 }
299 }
300 }
301
302 fn flush(&self) {
310 if let Some(inner) = self.inner.as_ref() {
311 match &inner {
312 LoggerInner::Once(inner) => {
313 for sink in inner.iter() {
314 sink.flush();
315 }
316 }
317 LoggerInner::Dyn(inner) => {
318 let sinks = inner.load();
319 for sink in sinks.iter() {
320 sink.flush();
321 }
322 }
323 }
324 }
325 }
326}
327
328static GLOBAL_LOGGER: GlobalLoggerConainer = GlobalLoggerConainer::new();
329
330#[doc(hidden)]
332pub fn log_panic(info: &std::panic::PanicHookInfo) {
333 let bt = Backtrace::new();
334 let mut record = log::Record::builder();
335 record.level(log::Level::Error);
336 if let Some(loc) = info.location() {
337 record.file(Some(loc.file())).line(Some(loc.line()));
338 }
339 log::logger().log(&record.args(format_args!("panic occur: {}\ntrace: {:?}", info, bt)).build());
340 eprint!("panic occur: {} at {:?}\ntrace: {:?}", info, info.location(), bt);
341}
342
343#[inline(always)]
344fn panic_and_exit_hook(info: &std::panic::PanicHookInfo) {
345 log_panic(info);
346 log::logger().flush();
347 let msg = format!("{}", info).to_string();
348 std::panic::resume_unwind(Box::new(msg));
349}
350
351#[inline(always)]
352fn panic_no_exit_hook(info: &std::panic::PanicHookInfo) {
353 log_panic(info);
354 eprint!("not debug version, so don't exit process");
355 log::logger().flush();
356}