1use std::{
5 ffi::{c_char, CString},
6 io,
7 sync::RwLock,
8};
9
10static mut LOADING_LOGGER: std::sync::RwLock<Option<FFGLLogger>> = RwLock::new(None);
11#[doc(hidden)]
13pub type FFGLLogger = unsafe extern "C" fn(*const c_char) -> ();
14
15struct FFGLWriter;
16
17impl io::Write for FFGLWriter {
18 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
19 let str = String::from_utf8_lossy(buf);
20
21 if let Some(logger) = unsafe { *LOADING_LOGGER.read().unwrap() } {
22 let str = CString::new(str.as_bytes()).expect("Failed to convert to CString");
23 unsafe { logger(str.as_ptr()) };
24 } else {
25 eprintln!("{}", str);
26 }
27
28 Ok(buf.len())
29 }
30
31 fn flush(&mut self) -> io::Result<()> {
32 Ok(())
33 }
34}
35
36pub(crate) fn try_init_default_subscriber() -> Result<(), tracing_subscriber::util::TryInitError> {
37 let env_filter = tracing_subscriber::EnvFilter::builder()
38 .with_default_directive(LevelFilter::INFO.into())
39 .from_env_lossy();
40
41 tracing_subscriber::fmt()
43 .with_writer(|| FFGLWriter)
44 .without_time()
45 .with_file(true)
46 .with_line_number(true)
47 .with_env_filter(env_filter)
48 .finish()
49 .try_init()
50}
51
52pub fn init_default_subscriber() {
55 if let Err(err) = try_init_default_subscriber() {
56 tracing::debug!("Failed to initialize logger: {}", err);
57 }
58}
59
60#[doc(hidden)]
62pub fn init_logger(logger: FFGLLogger) {
63 unsafe { *LOADING_LOGGER.write().unwrap() = Some(logger) };
64
65 std::panic::set_hook(Box::new(|cause| {
66 tracing::error!("{}", cause);
67 }));
68}
69
70use tracing_subscriber::{filter::LevelFilter, util::SubscriberInitExt};