falco_plugin 0.5.1

High level bindings for the Falco plugin API
Documentation
use falco_plugin_api::{
    ss_plugin_log_severity, ss_plugin_log_severity_SS_PLUGIN_LOG_SEV_DEBUG,
    ss_plugin_log_severity_SS_PLUGIN_LOG_SEV_ERROR, ss_plugin_log_severity_SS_PLUGIN_LOG_SEV_INFO,
    ss_plugin_log_severity_SS_PLUGIN_LOG_SEV_TRACE,
    ss_plugin_log_severity_SS_PLUGIN_LOG_SEV_WARNING, ss_plugin_owner_t,
};
use log::{Level, Log, Metadata, Record};
use std::ffi::{c_char, CString};

#[cfg(debug_assertions)]
use std::borrow::Cow;
use std::sync::RwLock;

pub(super) struct FalcoPluginLoggerImpl {
    pub(super) owner: *mut ss_plugin_owner_t,
    pub(super) logger_fn: unsafe extern "C-unwind" fn(
        o: *mut ss_plugin_owner_t,
        component: *const c_char,
        msg: *const c_char,
        sev: ss_plugin_log_severity,
    ),
}
unsafe impl Send for FalcoPluginLoggerImpl {}
unsafe impl Sync for FalcoPluginLoggerImpl {}

pub(super) struct FalcoPluginLogger {
    pub(super) inner: RwLock<Option<FalcoPluginLoggerImpl>>,
}

impl Log for FalcoPluginLogger {
    fn enabled(&self, _metadata: &Metadata) -> bool {
        true
    }

    fn log(&self, record: &Record) {
        let severity = match record.level() {
            Level::Error => ss_plugin_log_severity_SS_PLUGIN_LOG_SEV_ERROR,
            Level::Warn => ss_plugin_log_severity_SS_PLUGIN_LOG_SEV_WARNING,
            Level::Info => ss_plugin_log_severity_SS_PLUGIN_LOG_SEV_INFO,
            Level::Debug => ss_plugin_log_severity_SS_PLUGIN_LOG_SEV_DEBUG,
            Level::Trace => ss_plugin_log_severity_SS_PLUGIN_LOG_SEV_TRACE,
        };

        #[cfg(not(debug_assertions))]
        let msg = format!("[{}] {}", record.level(), record.args());

        #[cfg(debug_assertions)]
        let msg = {
            let loc = record
                .file()
                .zip(record.line())
                .map(|(f, l)| Cow::Owned(format!("{f}:{l}")))
                .unwrap_or_else(|| Cow::Borrowed(record.target()));
            format!("{}[{}] {}", loc, record.level(), record.args())
        };

        let logger_impl = self.inner.read().unwrap();
        if let Some(ref logger_impl) = *logger_impl {
            if let Ok(msg) = CString::new(msg) {
                unsafe {
                    (logger_impl.logger_fn)(
                        logger_impl.owner,
                        std::ptr::null(),
                        msg.as_ptr(),
                        severity,
                    )
                }
            }
        } else {
            eprintln!("{msg}")
        }
    }

    fn flush(&self) {}
}

pub(crate) static FALCO_LOGGER: FalcoPluginLogger = FalcoPluginLogger {
    inner: RwLock::new(None),
};