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