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 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 GlobalLoggerStatic {}
118unsafe impl Sync for GlobalLoggerStatic {}
119
120pub fn setup_log(builder: Builder) -> Result<(), ()> {
126 if let Ok(true) = GLOBAL_LOGGER.try_setup(&builder) {
127 let logger = GLOBAL_LOGGER.get_logger();
128 if let Err(e) = log::set_logger(logger) {
130 eprintln!("log::set_logger return error: {:?}", e);
131 return Err(());
132 }
133 log::set_max_level(builder.get_max_level());
134 if builder.continue_when_panic {
136 std::panic::set_hook(Box::new(panic_no_exit_hook));
137 } else {
138 std::panic::set_hook(Box::new(panic_and_exit_hook));
139 }
140 let signals = builder.rotation_signals.clone();
141 if signals.len() > 0 {
142 if false == logger.signal_listener.swap(true, Ordering::SeqCst) {
143 thread::spawn(move || {
144 GLOBAL_LOGGER.get_logger().listener_for_signal(signals);
145 });
146 }
147 }
148 }
149 Ok(())
150}
151
152struct GlobalLogger {
154 config_checksum: AtomicU64,
156 inner: Option<LoggerInner>,
159 signal_listener: AtomicBool,
160}
161
162enum LoggerInner {
163 Once(Vec<LogSink>),
164 Dyn(ArcSwap<Vec<LogSink>>),
166}
167
168#[inline(always)]
169fn panic_or_error() {
170 #[cfg(debug_assertions)]
171 {
172 panic!("GlobalLogger cannot be initialized twice on dynamic==false");
173 }
174 #[cfg(not(debug_assertions))]
175 {
176 eprintln!("GlobalLogger cannot be initialized twice on dynamic==false");
177 }
178}
179
180impl LoggerInner {
181 #[allow(dead_code)]
182 fn set(&self, sinks: Vec<LogSink>) {
183 match &self {
184 Self::Once(_) => {
185 panic_or_error();
186 }
187 Self::Dyn(d) => {
188 d.store(Arc::new(sinks));
189 }
190 }
191 }
192}
193
194impl GlobalLogger {
195 fn listener_for_signal(&self, signals: Vec<i32>) {
196 println!("signal_listener started");
197 let mut signals = Signals::new(&signals).unwrap();
198 for __sig in signals.forever() {
199 let _ = self.reopen();
200 }
201 println!("signal_listener exit");
202 }
203
204 fn open(&self) -> std::io::Result<()> {
206 if let Some(inner) = self.inner.as_ref() {
207 match &inner {
208 LoggerInner::Once(inner) => {
209 for sink in inner.iter() {
210 sink.open()?;
211 }
212 }
213 LoggerInner::Dyn(inner) => {
214 let sinks = inner.load();
215 for sink in sinks.iter() {
216 sink.open()?;
217 }
218 }
219 }
220 }
221 println!("log sinks opened");
222 Ok(())
223 }
224
225 pub fn reopen(&self) -> std::io::Result<()> {
227 if let Some(inner) = self.inner.as_ref() {
228 match &inner {
229 LoggerInner::Once(inner) => {
230 for sink in inner.iter() {
231 sink.reopen()?;
232 }
233 }
234 LoggerInner::Dyn(inner) => {
235 let sinks = inner.load();
236 for sink in sinks.iter() {
237 sink.reopen()?;
238 }
239 }
240 }
241 }
242 println!("log sinks re-opened");
243 Ok(())
244 }
245
246 fn check_the_same(&self, builder: &Builder) -> Option<bool> {
248 if self.inner.is_some() {
249 return Some(self.config_checksum.load(Ordering::Acquire) == builder.cal_checksum());
250 }
251 None
252 }
253
254 fn reinit(&self, builder: &Builder) -> Result<(), ()> {
256 let sinks = builder.build_sinks()?;
257 if let Some(inner) = self.inner.as_ref() {
258 inner.set(sinks);
259 self.config_checksum.store(builder.cal_checksum(), Ordering::Release);
260 } else {
261 unreachable!();
262 }
263 Ok(())
264 }
265
266 #[allow(dead_code)]
267 fn init(&mut self, builder: &Builder) -> Result<(), ()> {
268 let sinks = builder.build_sinks()?;
269 assert!(self.inner.is_none());
270 if builder.dynamic {
271 self.inner.replace(LoggerInner::Dyn(ArcSwap::new(Arc::new(sinks))));
272 } else {
273 self.inner.replace(LoggerInner::Once(sinks));
274 }
275 self.config_checksum.store(builder.cal_checksum(), Ordering::Release);
276 Ok(())
277 }
278}
279
280impl log::Log for GlobalLogger {
281 #[inline(always)]
282 fn enabled(&self, _m: &log::Metadata) -> bool {
283 true
284 }
285
286 #[inline(always)]
287 fn log(&self, r: &log::Record) {
288 let now = Timer::new();
289 if let Some(inner) = self.inner.as_ref() {
290 match &inner {
291 LoggerInner::Once(inner) => {
292 for sink in inner.iter() {
293 sink.log(&now, r);
294 }
295 }
296 LoggerInner::Dyn(inner) => {
297 let sinks = inner.load();
298 for sink in sinks.iter() {
299 sink.log(&now, r);
300 }
301 }
302 }
303 }
304 }
305
306 fn flush(&self) {
314 if let Some(inner) = self.inner.as_ref() {
315 match &inner {
316 LoggerInner::Once(inner) => {
317 for sink in inner.iter() {
318 sink.flush();
319 }
320 }
321 LoggerInner::Dyn(inner) => {
322 let sinks = inner.load();
323 for sink in sinks.iter() {
324 sink.flush();
325 }
326 }
327 }
328 }
329 }
330}
331
332static GLOBAL_LOGGER: GlobalLoggerStatic = GlobalLoggerStatic::new();
333
334#[doc(hidden)]
336pub fn log_panic(info: &std::panic::PanicHookInfo) {
337 let bt = Backtrace::new();
338 let mut record = log::Record::builder();
339 record.level(log::Level::Error);
340 if let Some(loc) = info.location() {
341 record.file(Some(loc.file())).line(Some(loc.line()));
342 }
343 log::logger().log(&record.args(format_args!("panic occur: {}\ntrace: {:?}", info, bt)).build());
344 eprint!("panic occur: {} at {:?}\ntrace: {:?}", info, info.location(), bt);
345}
346
347#[inline(always)]
348fn panic_and_exit_hook(info: &std::panic::PanicHookInfo) {
349 log_panic(info);
350 log::logger().flush();
351 let msg = format!("{}", info).to_string();
352 std::panic::resume_unwind(Box::new(msg));
353}
354
355#[inline(always)]
356fn panic_no_exit_hook(info: &std::panic::PanicHookInfo) {
357 log_panic(info);
358 eprint!("not debug version, so don't exit process");
359 log::logger().flush();
360}