matrix_sdk_crypto_ffi/
logger.rs

1use std::{
2    io::{Result, Write},
3    sync::{Arc, Mutex},
4};
5
6use tracing_subscriber::{fmt::MakeWriter, EnvFilter};
7
8/// Trait that can be used to forward Rust logs over FFI to a language specific
9/// logger.
10#[matrix_sdk_ffi_macros::export(callback_interface)]
11pub trait Logger: Send {
12    /// Called every time the Rust side wants to post a log line.
13    fn log(&self, log_line: String);
14    // TODO add support for different log levels, do this by adding more methods
15    // to the trait.
16}
17
18impl Write for LoggerWrapper {
19    fn write(&mut self, buf: &[u8]) -> Result<usize> {
20        let data = String::from_utf8_lossy(buf).to_string();
21        self.inner.lock().unwrap().log(data);
22
23        Ok(buf.len())
24    }
25
26    fn flush(&mut self) -> Result<()> {
27        Ok(())
28    }
29}
30
31impl MakeWriter<'_> for LoggerWrapper {
32    type Writer = LoggerWrapper;
33
34    fn make_writer(&self) -> Self::Writer {
35        self.clone()
36    }
37}
38
39#[derive(Clone)]
40pub struct LoggerWrapper {
41    inner: Arc<Mutex<Box<dyn Logger>>>,
42}
43
44/// Set the logger that should be used to forward Rust logs over FFI.
45#[matrix_sdk_ffi_macros::export]
46pub fn set_logger(logger: Box<dyn Logger>) {
47    let logger = LoggerWrapper { inner: Arc::new(Mutex::new(logger)) };
48
49    let filter = EnvFilter::from_default_env()
50        .add_directive(
51            "matrix_sdk_crypto=trace".parse().expect("Can't parse logging filter directive"),
52        )
53        .add_directive(
54            "matrix_sdk_sqlite=debug".parse().expect("Can't parse logging filter directive"),
55        );
56
57    let _ = tracing_subscriber::fmt()
58        .with_writer(logger)
59        .with_env_filter(filter)
60        .with_ansi(false)
61        .without_time()
62        .try_init();
63}