matrix_sdk_crypto_ffi/
logger.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
use std::{
    io::{Result, Write},
    sync::{Arc, Mutex},
};

use tracing_subscriber::{fmt::MakeWriter, EnvFilter};

/// Trait that can be used to forward Rust logs over FFI to a language specific
/// logger.
#[matrix_sdk_ffi_macros::export(callback_interface)]
pub trait Logger: Send {
    /// Called every time the Rust side wants to post a log line.
    fn log(&self, log_line: String);
    // TODO add support for different log levels, do this by adding more methods
    // to the trait.
}

impl Write for LoggerWrapper {
    fn write(&mut self, buf: &[u8]) -> Result<usize> {
        let data = String::from_utf8_lossy(buf).to_string();
        self.inner.lock().unwrap().log(data);

        Ok(buf.len())
    }

    fn flush(&mut self) -> Result<()> {
        Ok(())
    }
}

impl MakeWriter<'_> for LoggerWrapper {
    type Writer = LoggerWrapper;

    fn make_writer(&self) -> Self::Writer {
        self.clone()
    }
}

#[derive(Clone)]
pub struct LoggerWrapper {
    inner: Arc<Mutex<Box<dyn Logger>>>,
}

/// Set the logger that should be used to forward Rust logs over FFI.
#[matrix_sdk_ffi_macros::export]
pub fn set_logger(logger: Box<dyn Logger>) {
    let logger = LoggerWrapper { inner: Arc::new(Mutex::new(logger)) };

    let filter = EnvFilter::from_default_env()
        .add_directive(
            "matrix_sdk_crypto=trace".parse().expect("Can't parse logging filter directive"),
        )
        .add_directive(
            "matrix_sdk_sqlite=debug".parse().expect("Can't parse logging filter directive"),
        );

    let _ = tracing_subscriber::fmt()
        .with_writer(logger)
        .with_env_filter(filter)
        .with_ansi(false)
        .without_time()
        .try_init();
}