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