Skip to content

Instantly share code, notes, and snippets.

@Limeth
Created April 18, 2020 17:34
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Limeth/370c4e742fdc2a4760233a77b5883c94 to your computer and use it in GitHub Desktop.
Save Limeth/370c4e742fdc2a4760233a77b5883c94 to your computer and use it in GitHub Desktop.
use obs_wrapper::obs_sys::{
log_handler_t, base_get_log_handler, base_set_log_handler, __va_list_tag,
LOG_ERROR, LOG_WARNING, LOG_INFO, LOG_DEBUG,
};
use std::os::raw::{c_int, c_char, c_void};
use std::sync::atomic::{self, AtomicBool};
pub type RedirectLogCallback = Box<dyn Fn(c_int, *const c_char, *mut __va_list_tag)>;
#[repr(C)]
#[derive(Clone, Copy, Eq, PartialEq)]
pub enum LogLevel {
Error = LOG_ERROR as isize,
Warning = LOG_WARNING as isize,
Info = LOG_INFO as isize,
Debug = LOG_DEBUG as isize,
}
static LOG_HANDLER_LOCK: AtomicBool = AtomicBool::new(false);
unsafe extern "C" fn global_redirect_log_handler(
lvl: c_int,
msg: *const c_char,
args: *mut __va_list_tag,
p: *mut c_void,
) {
let callback = Box::from_raw(p as *mut RedirectLogCallback);
(callback)(lvl, msg, args);
std::mem::forget(callback);
}
pub struct LogCaptureHandler {
handler_previous: log_handler_t,
param_previous: *mut c_void,
callback_ptr: *mut RedirectLogCallback,
}
impl LogCaptureHandler {
pub fn new(min_log_level: LogLevel) -> Option<Self> {
if LOG_HANDLER_LOCK.compare_and_swap(false, true, atomic::Ordering::SeqCst) {
return None;
}
let mut handler_previous: log_handler_t = None;
let mut param_previous = std::ptr::null_mut();
let handler_previous_ptr: *mut log_handler_t = &mut handler_previous as *mut _;
let param_previous_ptr: *mut *mut c_void = &mut param_previous as *mut _;
unsafe {
base_get_log_handler(handler_previous_ptr, param_previous_ptr);
}
let callback_ptr = Box::into_raw(Box::new(Box::new(move |log_level, format, args| {
if let Some(handler_previous) = handler_previous.clone() {
if log_level <= min_log_level as i32 {
const SIZE: usize = 4096;
let mut formatted = [0 as c_char; SIZE];
unsafe {
libc::snprintf(&mut formatted[0] as *mut _, SIZE, format, args);
}
}
unsafe {
(handler_previous)(log_level, format, args, param_previous);
}
}
}) as RedirectLogCallback));
unsafe {
base_set_log_handler(Some(global_redirect_log_handler), callback_ptr as *mut _);
}
Some(Self {
handler_previous,
param_previous,
callback_ptr,
})
}
}
impl Drop for LogCaptureHandler {
fn drop(&mut self) {
unsafe {
base_set_log_handler(self.handler_previous, self.param_previous);
std::mem::drop(Box::from_raw(self.callback_ptr as *mut RedirectLogCallback));
}
LOG_HANDLER_LOCK.store(false, atomic::Ordering::SeqCst);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment