Skip to main content

matrix_sdk_crypto_ffi/
logger.rs

1use std::{
2    io::{Result, Write},
3    sync::{Arc, Mutex},
4};
5
6use tracing_core::{Level, Metadata};
7use tracing_subscriber::{EnvFilter, fmt::MakeWriter};
8
9/// Trait that can be used to forward Rust logs over FFI to a language specific
10/// logger.
11#[matrix_sdk_ffi_macros::export(callback_interface)]
12pub trait Logger: Send {
13    /// Called every time the Rust side wants to post a debug log line.
14    fn log_debug(&self, log_line: String);
15    /// Called every time the Rust side wants to post an error log line.
16    fn log_error(&self, log_line: String);
17    /// Called every time the Rust side wants to post an info log line.
18    fn log_info(&self, log_line: String);
19    /// Called every time the Rust side wants to post a trace log line.
20    fn log_trace(&self, log_line: String);
21    /// Called every time the Rust side wants to post a warn log line.
22    fn log_warn(&self, log_line: String);
23}
24
25impl Write for LoggerWrapper {
26    fn write(&mut self, buf: &[u8]) -> Result<usize> {
27        let data = String::from_utf8_lossy(buf).to_string();
28        let lock = self.inner.lock().unwrap();
29
30        match self.level {
31            Level::DEBUG => lock.log_debug(data),
32            Level::ERROR => lock.log_error(data),
33            Level::INFO => lock.log_info(data),
34            Level::TRACE => lock.log_trace(data),
35            Level::WARN => lock.log_warn(data),
36        }
37
38        Ok(buf.len())
39    }
40
41    fn flush(&mut self) -> Result<()> {
42        Ok(())
43    }
44}
45
46impl MakeWriter<'_> for LoggerWrapper {
47    type Writer = LoggerWrapper;
48
49    fn make_writer(&self) -> Self::Writer {
50        self.clone()
51    }
52
53    fn make_writer_for(&self, meta: &Metadata<'_>) -> Self::Writer {
54        LoggerWrapper { inner: self.inner.clone(), level: *meta.level() }
55    }
56}
57
58#[derive(Clone)]
59pub struct LoggerWrapper {
60    inner: Arc<Mutex<Box<dyn Logger>>>,
61    level: Level,
62}
63
64/// Set the logger that should be used to forward Rust logs over FFI.
65#[matrix_sdk_ffi_macros::export]
66pub fn set_logger(logger: Box<dyn Logger>) {
67    let logger = LoggerWrapper { inner: Arc::new(Mutex::new(logger)), level: Level::DEBUG };
68
69    let filter = EnvFilter::from_default_env()
70        .add_directive(
71            "matrix_sdk_crypto=trace".parse().expect("Can't parse logging filter directive"),
72        )
73        .add_directive(
74            "matrix_sdk_sqlite=debug".parse().expect("Can't parse logging filter directive"),
75        );
76
77    let _ = tracing_subscriber::fmt()
78        .with_writer(logger)
79        .with_env_filter(filter)
80        .with_ansi(false)
81        .without_time()
82        .try_init();
83}