mm_client_common/
logging.rs

1// Copyright 2024 Colin Marc <hi@colinmarc.com>
2//
3// SPDX-License-Identifier: MIT
4
5use std::sync::{Arc, OnceLock};
6
7#[derive(uniffi::Enum)]
8pub enum LogLevel {
9    None,
10    Trace,
11    Debug,
12    Info,
13    Warn,
14    Error,
15}
16
17impl From<log::Level> for LogLevel {
18    fn from(value: log::Level) -> Self {
19        match value {
20            log::Level::Trace => LogLevel::Trace,
21            log::Level::Debug => LogLevel::Debug,
22            log::Level::Info => LogLevel::Info,
23            log::Level::Warn => LogLevel::Warn,
24            log::Level::Error => LogLevel::Error,
25        }
26    }
27}
28
29/// An interface for receiving logs from this library.
30#[uniffi::export(with_foreign)]
31pub trait LogDelegate: Send + Sync + std::fmt::Debug {
32    fn log(&self, level: LogLevel, target: String, msg: String);
33}
34
35struct LogWrapper(Arc<dyn LogDelegate>);
36
37impl log::Log for LogWrapper {
38    fn enabled(&self, metadata: &log::Metadata) -> bool {
39        metadata.level() <= log::max_level()
40    }
41
42    fn log(&self, record: &log::Record) {
43        if self.enabled(record.metadata()) {
44            LogDelegate::log(
45                &*self.0,
46                record.level().into(),
47                record.target().to_owned(),
48                record.args().to_string(),
49            )
50        }
51    }
52
53    fn flush(&self) {}
54}
55
56/// Set the minimum log level.
57#[uniffi::export]
58fn set_log_level(level: LogLevel) {
59    let filter = match level {
60        LogLevel::None => log::LevelFilter::Off,
61        LogLevel::Trace => log::LevelFilter::Trace,
62        LogLevel::Debug => log::LevelFilter::Debug,
63        LogLevel::Info => log::LevelFilter::Info,
64        LogLevel::Warn => log::LevelFilter::Warn,
65        LogLevel::Error => log::LevelFilter::Error,
66    };
67
68    log::set_max_level(filter);
69}
70
71/// Set the global logger.
72#[uniffi::export]
73fn set_logger(logger: Arc<dyn LogDelegate>) {
74    // This has to accept an Arc to be exportable by uniffi, however awkward
75    // that may be.
76    static LOGGER: OnceLock<LogWrapper> = OnceLock::new();
77
78    let logger = LOGGER.get_or_init(|| LogWrapper(logger));
79    log::set_logger(logger).expect("failed to set logger")
80}