sqlite_plugin/
logger.rs

1use alloc::ffi::CString;
2use core::ffi::{c_char, c_int};
3
4use crate::vars;
5
6type Sqlite3Log = unsafe extern "C" fn(iErrCode: c_int, arg2: *const c_char, ...);
7
8#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
9pub enum SqliteLogLevel {
10    Error = 1,
11    Warn,
12    Notice,
13}
14
15impl SqliteLogLevel {
16    fn into_err_code(self) -> c_int {
17        match self {
18            Self::Notice => vars::SQLITE_NOTICE,
19            Self::Warn => vars::SQLITE_WARNING,
20            Self::Error => vars::SQLITE_INTERNAL,
21        }
22    }
23}
24
25#[derive(Clone, Copy)]
26pub struct SqliteLogger {
27    log: Sqlite3Log,
28}
29
30impl SqliteLogger {
31    pub(crate) fn new(log: Sqlite3Log) -> Self {
32        Self { log }
33    }
34
35    /// Log bytes to the `SQLite3` log handle.
36    /// This function will write each line separately to `SQLite3`.
37    /// Note that `SQLite3` silently truncates log lines larger than roughly
38    /// 230 bytes by default.
39    pub fn log(&self, level: SqliteLogLevel, buf: &[u8]) {
40        let code = level.into_err_code();
41        for line in buf.split(|b| *b == b'\n') {
42            // skip if line only contains whitespace
43            if line.iter().all(|b| b.is_ascii_whitespace()) {
44                continue;
45            }
46
47            let z_format = CString::new(line).unwrap();
48            unsafe { (self.log)(code, z_format.as_ptr()) }
49        }
50    }
51}