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 lazy_static::lazy_static;
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 LogSinkTrait {
17 fn open(&self) -> std::io::Result<()>;
18
19 fn reopen(&self) -> std::io::Result<()>;
20
21 fn log(&self, now: &Timer, r: &log::Record);
22
23 fn flush(&self);
24}
25
26#[enum_dispatch(LogSinkTrait)]
27pub enum LogSink {
28 File(LogSinkFile),
29 BufFile(LogSinkBufFile),
30 Console(LogSinkConsole),
31 #[cfg(feature = "syslog")]
32 Syslog(crate::syslog::LogSinkSyslog),
33 #[cfg(feature = "ringfile")]
34 RingFile(crate::ring::LogSinkRingFile),
35}
36
37struct GlobalLogger {
39 config_checksum: u64,
41 inner: Option<LoggerInner>,
44 signal_listener: AtomicBool,
45}
46
47enum LoggerInner {
48 Once(Vec<LogSink>),
49 Dyn(ArcSwap<Vec<LogSink>>),
51}
52
53#[inline(always)]
54fn panic_or_error() {
55 #[cfg(debug_assertions)]
56 {
57 panic!("GlobalLogger cannot be initialized twice on dynamic==false");
58 }
59 #[cfg(not(debug_assertions))]
60 {
61 eprintln!("GlobalLogger cannot be initialized twice on dynamic==false");
62 }
63}
64
65impl LoggerInner {
66 #[allow(dead_code)]
67 fn set(&self, sinks: Vec<LogSink>) {
68 match &self {
69 Self::Once(_) => {
70 panic_or_error();
71 }
72 Self::Dyn(d) => {
73 d.store(Arc::new(sinks));
74 }
75 }
76 }
77}
78
79impl GlobalLogger {
80 fn open(&mut self) -> std::io::Result<()> {
81 if let Some(inner) = self.inner.as_ref() {
82 match &inner {
83 LoggerInner::Once(inner) => {
84 for sink in inner.iter() {
85 sink.open()?;
86 }
87 }
88 LoggerInner::Dyn(inner) => {
89 let sinks = inner.load();
90 for sink in sinks.iter() {
91 sink.open()?;
92 }
93 }
94 }
95 }
96 println!("log sinks opened");
97 Ok(())
98 }
99
100 pub fn reopen(&mut self) -> std::io::Result<()> {
101 if let Some(inner) = self.inner.as_ref() {
102 match &inner {
103 LoggerInner::Once(inner) => {
104 for sink in inner.iter() {
105 sink.reopen()?;
106 }
107 }
108 LoggerInner::Dyn(inner) => {
109 let sinks = inner.load();
110 for sink in sinks.iter() {
111 sink.reopen()?;
112 }
113 }
114 }
115 }
116 println!("log sinks re-opened");
117 Ok(())
118 }
119
120 #[allow(dead_code)]
121 fn init(&mut self, builder: &Builder) -> std::io::Result<bool> {
122 let new_checksum = builder.cal_checksum();
123 if self.inner.is_some() {
124 if self.config_checksum == new_checksum {
125 self.open()?;
127 return Ok(true);
128 }
129 if !builder.dynamic {
130 panic_or_error();
131 return Ok(false);
132 }
133 }
134 let mut sinks = Vec::new();
135 for config in &builder.sinks {
136 let logger_sink = config.build();
137 logger_sink.open()?;
138 sinks.push(logger_sink);
139 }
140
141 if let Some(inner) = self.inner.as_ref() {
142 inner.set(sinks);
143 } else {
144 if builder.dynamic {
145 self.inner.replace(LoggerInner::Dyn(ArcSwap::new(Arc::new(sinks))));
146 } else {
147 self.inner.replace(LoggerInner::Once(sinks));
148 }
149 }
150 self.config_checksum = new_checksum;
151
152 let _ = unsafe { log::set_logger(transmute::<&Self, &'static Self>(self)) };
153
154 if builder.continue_when_panic {
156 std::panic::set_hook(Box::new(panic_no_exit_hook));
157 } else {
158 std::panic::set_hook(Box::new(panic_and_exit_hook));
159 }
160 Ok(true)
161 }
162}
163
164impl log::Log for GlobalLogger {
165 #[inline(always)]
166 fn enabled(&self, _m: &log::Metadata) -> bool {
167 true
168 }
169
170 #[inline(always)]
171 fn log(&self, r: &log::Record) {
172 let now = Timer::new();
173 if let Some(inner) = self.inner.as_ref() {
174 match &inner {
175 LoggerInner::Once(inner) => {
176 for sink in inner.iter() {
177 sink.log(&now, r);
178 }
179 }
180 LoggerInner::Dyn(inner) => {
181 let sinks = inner.load();
182 for sink in sinks.iter() {
183 sink.log(&now, r);
184 }
185 }
186 }
187 }
188 }
189
190 fn flush(&self) {
198 if let Some(inner) = self.inner.as_ref() {
199 match &inner {
200 LoggerInner::Once(inner) => {
201 for sink in inner.iter() {
202 sink.flush();
203 }
204 }
205 LoggerInner::Dyn(inner) => {
206 let sinks = inner.load();
207 for sink in sinks.iter() {
208 sink.flush();
209 }
210 }
211 }
212 }
213 }
214}
215
216lazy_static! {
217 static ref GLOBAL_LOGGER: Mutex<GlobalLogger> = Mutex::new(GlobalLogger {
220 config_checksum: 0,
221 inner: None ,
222 signal_listener: AtomicBool::new(false),
223 });
224}
225
226#[doc(hidden)]
228pub fn log_panic(info: &std::panic::PanicHookInfo) {
229 let bt = Backtrace::new();
230 let mut record = log::Record::builder();
231 record.level(log::Level::Error);
232 if let Some(loc) = info.location() {
233 record.file(Some(loc.file())).line(Some(loc.line()));
234 }
235 log::logger().log(&record.args(format_args!("panic occur: {}\ntrace: {:?}", info, bt)).build());
236 eprint!("panic occur: {} at {:?}\ntrace: {:?}", info, info.location(), bt);
237}
238
239#[inline(always)]
240fn panic_and_exit_hook(info: &std::panic::PanicHookInfo) {
241 log_panic(info);
242 log::logger().flush();
243 let msg = format!("{}", info).to_string();
244 std::panic::resume_unwind(Box::new(msg));
245}
246
247#[inline(always)]
248fn panic_no_exit_hook(info: &std::panic::PanicHookInfo) {
249 log_panic(info);
250 eprint!("not debug version, so don't exit process");
251 log::logger().flush();
252}
253
254fn signal_listener(signals: Vec<i32>) {
255 let started;
256 {
257 let global_logger = GLOBAL_LOGGER.lock();
258 started = global_logger.signal_listener.swap(true, Ordering::SeqCst);
259 }
260 if started {
261 eprintln!("signal listener already started");
263 return;
264 }
265 thread::spawn(move || {
266 let mut signals = Signals::new(&signals).unwrap();
267 for __sig in signals.forever() {
268 {
269 let mut global_logger = GLOBAL_LOGGER.lock();
270 let _ = global_logger.reopen();
271 }
272 }
273 });
274}
275
276pub fn setup_log(builder: Builder) -> Result<(), ()> {
278 {
279 let mut global_logger = GLOBAL_LOGGER.lock();
280
281 match global_logger.init(&builder) {
282 Err(e) => {
283 println!("Initialize logger failed: {:?}", e);
284 return Err(());
285 }
286 Ok(false) => return Err(()),
287 Ok(true) => {}
288 }
289 log::set_max_level(builder.get_max_level());
290 }
291 let signals = builder.rotation_signals.clone();
292 if signals.len() > 0 {
293 signal_listener(signals);
294 }
295 Ok(())
296}