Skip to main content

libobs_wrapper\logger/
mod.rs

1//! This module is used to provide a logger trait, which can be used to implement custom logging
2//! for the libobs console output.
3
4mod console;
5mod file;
6pub use console::ConsoleLogger;
7pub use file::FileLogger;
8
9use std::{fmt::Debug, os::raw::c_void, sync::Mutex};
10
11use lazy_static::lazy_static;
12use num_traits::FromPrimitive;
13use vsprintf::vsprintf;
14
15use crate::enums::ObsLogLevel;
16
17lazy_static! {
18    /// We are using this as global variable because there can only be one obs context
19    pub(crate) static ref LOGGER: Mutex<Box<dyn ObsLogger>> = Mutex::new(Box::new(ConsoleLogger::new()));
20}
21
22/// # Safety
23/// This function is unsafe because it is called from C code.
24pub(crate) unsafe extern "C" fn extern_log_callback<V>(
25    log_level: i32,
26    msg: *const i8,
27    args: *mut V,
28    _params: *mut c_void,
29) {
30    let Some(level) = ObsLogLevel::from_i32(log_level) else {
31        eprintln!("Couldn't find log level {}", log_level);
32        return;
33    };
34
35    let Ok(formatted) = vsprintf(msg, args) else {
36        eprintln!("Failed to format log message");
37        return;
38    };
39
40    let mut logger = LOGGER
41        .lock()
42        .unwrap_or_else(|poisoned| poisoned.into_inner());
43    logger.log(level, formatted);
44}
45
46pub trait ObsLogger
47where
48    Self: Send + Debug,
49{
50    fn log(&mut self, level: ObsLogLevel, msg: String);
51}
52
53pub(crate) fn internal_log_global(level: ObsLogLevel, msg: String) {
54    let mut logger = LOGGER
55        .lock()
56        .unwrap_or_else(|poisoned| poisoned.into_inner());
57    logger.log(level, msg);
58}