ferroui_base/logging/
logger.rs1use std::cell::{Cell, RefCell};
2use std::rc::Rc;
3use std::sync::atomic::{AtomicBool, Ordering};
4use std::sync::{Arc, PoisonError, RwLock};
5
6use super::parametrized_logger::SinkHandle;
7use super::{ILogSink, LogEventLevel, ParametrizedLogger};
8
9static SINK: RwLock<Option<Arc<dyn ILogSink + Send + Sync>>> = RwLock::new(None);
10static HAS_SINK: AtomicBool = AtomicBool::new(false);
11
12crate::ferro_thread_local! {
13 static THREAD_SINK: RefCell<Option<Rc<dyn ILogSink>>> = const { RefCell::new(None) };
14 static HAS_THREAD_SINK: Cell<bool> = const { Cell::new(false) };
15}
16
17pub struct Logger;
25
26impl Logger {
27 pub fn sink() -> Option<Arc<dyn ILogSink + Send + Sync>> {
29 if !HAS_SINK.load(Ordering::Acquire) {
30 return None;
31 }
32 SINK.read().unwrap_or_else(PoisonError::into_inner).clone()
33 }
34
35 pub fn set_sink(sink: Option<Arc<dyn ILogSink + Send + Sync>>) {
37 let previous = {
38 let mut slot = SINK.write().unwrap_or_else(PoisonError::into_inner);
39 HAS_SINK.store(sink.is_some(), Ordering::Release);
40 std::mem::replace(&mut *slot, sink)
41 };
42 drop(previous);
43 }
44
45 pub fn thread_sink() -> Option<Rc<dyn ILogSink>> {
47 if !HAS_THREAD_SINK.try_with(Cell::get).unwrap_or(false) {
48 return None;
49 }
50 THREAD_SINK.try_with(|sink| sink.borrow().clone()).ok().flatten()
51 }
52
53 pub fn set_thread_sink(sink: Option<Rc<dyn ILogSink>>) -> Option<Rc<dyn ILogSink>> {
56 HAS_THREAD_SINK.with(|has| has.set(sink.is_some()));
57 THREAD_SINK.with(|slot| std::mem::replace(&mut *slot.borrow_mut(), sink))
58 }
59
60 fn current_sink() -> Option<SinkHandle> {
61 if let Some(sink) = Self::thread_sink() {
62 return Some(SinkHandle::Thread(sink));
63 }
64 Self::sink().map(SinkHandle::Global)
65 }
66
67 pub fn is_enabled(level: LogEventLevel, area: &str) -> bool {
69 match Self::current_sink() {
70 Some(sink) => sink.get().is_enabled(level, area),
71 None => false,
72 }
73 }
74
75 pub fn try_get(level: LogEventLevel, area: &'static str) -> Option<ParametrizedLogger> {
77 let sink = Self::current_sink()?;
78 if !sink.get().is_enabled(level, area) {
79 return None;
80 }
81
82 Some(ParametrizedLogger::from_handle(sink, level, area))
83 }
84}