memflow_ffi/
log.rs

1use log::{Level, LevelFilter};
2use memflow::cglue::IntError;
3use memflow::error::Error;
4use memflow::plugins::Inventory;
5use std::num::NonZeroI32;
6
7use std::ffi::CStr;
8use std::os::raw::c_char;
9
10/// Initialize logging with selected logging level.
11#[no_mangle]
12pub extern "C" fn log_init(level_filter: LevelFilter) {
13    simplelog::TermLogger::init(
14        level_filter,
15        simplelog::Config::default(),
16        simplelog::TerminalMode::Stdout,
17        simplelog::ColorChoice::Auto,
18    )
19    .unwrap();
20}
21
22// TODO: add variadic functions when this is being stabilized, see https://github.com/rust-lang/rust/issues/44930
23
24/// Logs a error message via log::error!
25///
26/// # Safety
27///
28/// The provided string must be a valid null-terminated char array.
29#[no_mangle]
30pub unsafe extern "C" fn log_error(s: *const c_char) {
31    if !s.is_null() {
32        let c_str = CStr::from_ptr(s);
33        if let Ok(r_str) = c_str.to_str() {
34            log::error!("{}", r_str);
35        }
36    }
37}
38
39/// Logs a warning message via log::warn!
40///
41/// # Safety
42///
43/// The provided string must be a valid null-terminated char array.
44#[no_mangle]
45pub unsafe extern "C" fn log_warn(s: *const c_char) {
46    if !s.is_null() {
47        let c_str = CStr::from_ptr(s);
48        if let Ok(r_str) = c_str.to_str() {
49            log::warn!("{}", r_str);
50        }
51    }
52}
53
54/// Logs a info message via log::info!
55///
56/// # Safety
57///
58/// The provided string must be a valid null-terminated char array.
59#[no_mangle]
60pub unsafe extern "C" fn log_info(s: *const c_char) {
61    if !s.is_null() {
62        let c_str = CStr::from_ptr(s);
63        if let Ok(r_str) = c_str.to_str() {
64            log::info!("{}", r_str);
65        }
66    }
67}
68
69/// Logs a debug message via log::debug!
70///
71/// # Safety
72///
73/// The provided string must be a valid null-terminated char array.
74#[no_mangle]
75pub unsafe extern "C" fn log_debug(s: *const c_char) {
76    if !s.is_null() {
77        let c_str = CStr::from_ptr(s);
78        if let Ok(r_str) = c_str.to_str() {
79            log::debug!("{}", r_str);
80        }
81    }
82}
83
84/// Logs a trace message via log::trace!
85///
86/// # Safety
87///
88/// The provided string must be a valid null-terminated char array.
89#[no_mangle]
90pub unsafe extern "C" fn log_trace(s: *const c_char) {
91    if !s.is_null() {
92        let c_str = CStr::from_ptr(s);
93        if let Ok(r_str) = c_str.to_str() {
94            log::trace!("{}", r_str);
95        }
96    }
97}
98
99/// Logs an error code with custom log level.
100#[no_mangle]
101pub extern "C" fn log_errorcode(level: Level, error: i32) {
102    if let Some(error) = NonZeroI32::new(error) {
103        log::log!(level, "{}", <Error as IntError>::from_int_err(error));
104    }
105}
106
107/// Logs an error with debug log level.
108#[no_mangle]
109pub extern "C" fn log_debug_errorcode(error: i32) {
110    log_errorcode(Level::Debug, error)
111}
112
113/// Sets new maximum log level.
114///
115/// If `inventory` is supplied, the log level is also updated within all plugin instances. However,
116/// if it is not supplied, plugins will not have their log levels updated, potentially leading to
117/// lower performance, or less logging than expected.
118#[no_mangle]
119pub extern "C" fn log_set_max_level(level_filter: LevelFilter, inventory: Option<&Inventory>) {
120    if let Some(inventory) = inventory {
121        inventory.set_max_log_level(level_filter);
122    } else {
123        log::set_max_level(level_filter);
124    }
125}