use std::panic::catch_unwind;
static INIT_LOGGING: std::sync::Once = std::sync::Once::new();
pub(crate) fn maybe_init_logging() {
INIT_LOGGING.call_once_force(|state| {
if state.is_poisoned() {
return;
}
set_logger_impl(LoggerType::default());
});
}
#[derive(Copy, Clone, Debug)]
pub enum LoggerType {
None,
Stdio,
#[cfg(feature = "log")]
Log,
Custom {
info: unsafe extern "C" fn(*const ::libc::c_char),
error: unsafe extern "C" fn(*const ::libc::c_char),
},
}
impl Default for LoggerType {
#[cfg(feature = "log")]
fn default() -> LoggerType {
LoggerType::Log
}
#[cfg(not(feature = "log"))]
fn default() -> LoggerType {
LoggerType::Stdio
}
}
pub fn set_logger(logger: LoggerType) {
if !INIT_LOGGING.is_completed() {
INIT_LOGGING.call_once(|| {});
}
set_logger_impl(logger);
}
fn set_logger_impl(logger: LoggerType) {
let info_fn = match logger {
LoggerType::None => silent_handler,
LoggerType::Stdio => stdout_handler,
#[cfg(feature = "log")]
LoggerType::Log => info_handler,
LoggerType::Custom { info, .. } => info,
};
let error_fn = match logger {
LoggerType::None => silent_handler,
LoggerType::Stdio => stderr_handler,
#[cfg(feature = "log")]
LoggerType::Log => error_handler,
LoggerType::Custom { error, .. } => error,
};
unsafe {
jack_sys::jack_set_error_function(Some(error_fn));
jack_sys::jack_set_info_function(Some(info_fn));
}
}
#[cfg(feature = "log")]
unsafe extern "C" fn error_handler(msg: *const libc::c_char) {
let res = catch_unwind(|| match std::ffi::CStr::from_ptr(msg).to_str() {
Ok(msg) => log::error!("{}", msg),
Err(err) => log::error!("failed to log to JACK error: {:?}", err),
});
if let Err(err) = res {
eprintln!("{err:?}");
std::mem::forget(err);
}
}
#[cfg(feature = "log")]
unsafe extern "C" fn info_handler(msg: *const libc::c_char) {
let res = catch_unwind(|| match std::ffi::CStr::from_ptr(msg).to_str() {
Ok(msg) => log::info!("{}", msg),
Err(err) => log::error!("failed to log to JACK info: {:?}", err),
});
if let Err(err) = res {
eprintln!("{err:?}");
std::mem::forget(err);
}
}
unsafe extern "C" fn stderr_handler(msg: *const libc::c_char) {
let res = catch_unwind(|| match std::ffi::CStr::from_ptr(msg).to_str() {
Ok(msg) => eprintln!("{}", msg),
Err(err) => eprintln!("failed to log to JACK error: {:?}", err),
});
if let Err(err) = res {
eprintln!("{err:?}");
std::mem::forget(err);
}
}
unsafe extern "C" fn stdout_handler(msg: *const libc::c_char) {
let res = catch_unwind(|| match std::ffi::CStr::from_ptr(msg).to_str() {
Ok(msg) => println!("{}", msg),
Err(err) => println!("failed to log to JACK info: {:?}", err),
});
if let Err(err) = res {
eprintln!("{err:?}");
std::mem::forget(err);
}
}
unsafe extern "C" fn silent_handler(_msg: *const libc::c_char) {}