Created
April 18, 2020 17:34
-
-
Save Limeth/370c4e742fdc2a4760233a77b5883c94 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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