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 GlobalLoggerStatic {
37 logger: UnsafeCell<GlobalLogger>,
38 lock: AtomicBool,
39}
40
41struct GlobalLoggerGuard<'a>(&'a GlobalLoggerStatic);
42
43impl Drop for GlobalLoggerGuard<'_> {
44 fn drop(&mut self) {
45 self.0.unlock();
46 }
47}
48
49impl GlobalLoggerStatic {
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 #[inline(always)]
62 fn get_logger_mut(&self) -> &mut GlobalLogger {
63 unsafe { transmute(self.logger.get()) }
64 }
65
66 #[inline(always)]
67 fn get_logger(&self) -> &GlobalLogger {
68 unsafe { transmute(self.logger.get()) }
69 }
70
71 #[inline]
72 fn lock<'a>(&'a self) -> GlobalLoggerGuard<'a> {
73 while self
74 .lock
75 .compare_exchange_weak(false, true, Ordering::Acquire, Ordering::Relaxed)
76 .is_err()
77 {
78 std::thread::yield_now();
80 }
81 GlobalLoggerGuard(self)
82 }
83
84 fn unlock(&self) {
85 self.lock.store(false, Ordering::SeqCst);
86 }
87
88 fn try_setup(&self, builder: &Builder) -> Result<bool, ()> {
90 let _guard = self.lock();
91 let res = { self.get_logger().check_the_same(builder) };
92 match res {
93 Some(true) => {
94 if let Err(e) = self.get_logger().open() {
95 eprintln!("failed to open log sink: {:?}", e);
96 return Err(());
97 }
98 return Ok(false);
99 }
100 Some(false) => {
101 if !builder.dynamic {
102 panic_or_error();
103 return Err(());
104 }
105 let res = self.get_logger().reinit(builder);
106 res?;
107 log::set_max_level(builder.get_max_level());
109 return Ok(false);
110 }
111 None => {
112 let res = { self.get_logger_mut().init(builder) };
113 res?;
114 return Ok(true);
115 }
116 }
117 }
118}
119
120unsafe impl Send for GlobalLoggerStatic {}
121unsafe impl Sync for GlobalLoggerStatic {}
122
123pub fn setup_log(builder: Builder) -> Result<(), ()> {
129 if let Ok(true) = GLOBAL_LOGGER.try_setup(&builder) {
130 let logger = GLOBAL_LOGGER.get_logger();
131 if let Err(e) = log::set_logger(logger) {
133 eprintln!("log::set_logger return error: {:?}", e);
134 return Err(());
135 }
136 log::set_max_level(builder.get_max_level());
137 if builder.continue_when_panic {
139 std::panic::set_hook(Box::new(panic_no_exit_hook));
140 } else {
141 std::panic::set_hook(Box::new(panic_and_exit_hook));
142 }
143 let signals = builder.rotation_signals.clone();
144 if signals.len() > 0 {
145 if false == logger.signal_listener.swap(true, Ordering::SeqCst) {
146 thread::spawn(move || {
147 GLOBAL_LOGGER.get_logger().listener_for_signal(signals);
148 });
149 }
150 }
151 }
152 Ok(())
153}
154
155struct GlobalLogger {
157 config_checksum: AtomicU64,
159 inner: Option<LoggerInner>,
162 signal_listener: AtomicBool,
163}
164
165enum LoggerInner {
166 Once(Vec<LogSink>),
167 Dyn(ArcSwap<Vec<LogSink>>),
169}
170
171#[inline(always)]
172fn panic_or_error() {
173 #[cfg(debug_assertions)]
174 {
175 panic!("GlobalLogger cannot be initialized twice on dynamic==false");
176 }
177 #[cfg(not(debug_assertions))]
178 {
179 eprintln!("GlobalLogger cannot be initialized twice on dynamic==false");
180 }
181}
182
183impl LoggerInner {
184 #[allow(dead_code)]
185 fn set(&self, sinks: Vec<LogSink>) {
186 match &self {
187 Self::Once(_) => {
188 panic_or_error();
189 }
190 Self::Dyn(d) => {
191 d.store(Arc::new(sinks));
192 }
193 }
194 }
195}
196
197impl GlobalLogger {
198 fn listener_for_signal(&self, signals: Vec<i32>) {
199 println!("signal_listener started");
200 let mut signals = Signals::new(&signals).unwrap();
201 for __sig in signals.forever() {
202 let _ = self.reopen();
203 }
204 println!("signal_listener exit");
205 }
206
207 fn open(&self) -> std::io::Result<()> {
209 if let Some(inner) = self.inner.as_ref() {
210 match &inner {
211 LoggerInner::Once(inner) => {
212 for sink in inner.iter() {
213 sink.open()?;
214 }
215 }
216 LoggerInner::Dyn(inner) => {
217 let sinks = inner.load();
218 for sink in sinks.iter() {
219 sink.open()?;
220 }
221 }
222 }
223 }
224 println!("log sinks opened");
225 Ok(())
226 }
227
228 pub fn reopen(&self) -> std::io::Result<()> {
230 if let Some(inner) = self.inner.as_ref() {
231 match &inner {
232 LoggerInner::Once(inner) => {
233 for sink in inner.iter() {
234 sink.reopen()?;
235 }
236 }
237 LoggerInner::Dyn(inner) => {
238 let sinks = inner.load();
239 for sink in sinks.iter() {
240 sink.reopen()?;
241 }
242 }
243 }
244 }
245 println!("log sinks re-opened");
246 Ok(())
247 }
248
249 #[inline]
251 fn check_the_same(&self, builder: &Builder) -> Option<bool> {
252 if self.inner.is_some() {
253 return Some(self.config_checksum.load(Ordering::Acquire) == builder.cal_checksum());
254 }
255 None
256 }
257
258 fn reinit(&self, builder: &Builder) -> Result<(), ()> {
260 let sinks = builder.build_sinks()?;
261 if let Some(inner) = self.inner.as_ref() {
262 inner.set(sinks);
263 self.config_checksum.store(builder.cal_checksum(), Ordering::Release);
264 } else {
265 unreachable!();
266 }
267 Ok(())
268 }
269
270 fn init(&mut self, builder: &Builder) -> Result<(), ()> {
271 let sinks = builder.build_sinks()?;
272 assert!(self.inner.is_none());
273 if builder.dynamic {
274 self.inner.replace(LoggerInner::Dyn(ArcSwap::new(Arc::new(sinks))));
275 } else {
276 self.inner.replace(LoggerInner::Once(sinks));
277 }
278 self.config_checksum.store(builder.cal_checksum(), Ordering::Release);
279 Ok(())
280 }
281}
282
283impl log::Log for GlobalLogger {
284 #[inline(always)]
285 fn enabled(&self, _m: &log::Metadata) -> bool {
286 true
287 }
288
289 #[inline(always)]
290 fn log(&self, r: &log::Record) {
291 let now = Timer::new();
292 if let Some(inner) = self.inner.as_ref() {
293 match &inner {
294 LoggerInner::Once(inner) => {
295 for sink in inner.iter() {
296 sink.log(&now, r);
297 }
298 }
299 LoggerInner::Dyn(inner) => {
300 let sinks = inner.load();
301 for sink in sinks.iter() {
302 sink.log(&now, r);
303 }
304 }
305 }
306 }
307 }
308
309 fn flush(&self) {
317 if let Some(inner) = self.inner.as_ref() {
318 match &inner {
319 LoggerInner::Once(inner) => {
320 for sink in inner.iter() {
321 sink.flush();
322 }
323 }
324 LoggerInner::Dyn(inner) => {
325 let sinks = inner.load();
326 for sink in sinks.iter() {
327 sink.flush();
328 }
329 }
330 }
331 }
332 }
333}
334
335static GLOBAL_LOGGER: GlobalLoggerStatic = GlobalLoggerStatic::new();
336
337#[doc(hidden)]
339pub fn log_panic(info: &std::panic::PanicHookInfo) {
340 let bt = Backtrace::new();
341 let mut record = log::Record::builder();
342 record.level(log::Level::Error);
343 if let Some(loc) = info.location() {
344 record.file(Some(loc.file())).line(Some(loc.line()));
345 }
346 log::logger().log(&record.args(format_args!("panic occur: {}\ntrace: {:?}", info, bt)).build());
347 eprint!("panic occur: {} at {:?}\ntrace: {:?}", info, info.location(), bt);
348}
349
350#[inline(always)]
351fn panic_and_exit_hook(info: &std::panic::PanicHookInfo) {
352 log_panic(info);
353 log::logger().flush();
354 let msg = format!("{}", info).to_string();
355 std::panic::resume_unwind(Box::new(msg));
356}
357
358#[inline(always)]
359fn panic_no_exit_hook(info: &std::panic::PanicHookInfo) {
360 log_panic(info);
361 eprint!("not debug version, so don't exit process");
362 log::logger().flush();
363}