bitwarden_uniffi/
log_callback.rs1use std::sync::Arc;
2
3use tracing_subscriber::{Layer, layer::Context};
4
5use crate::LogLevel;
6
7#[uniffi::export(with_foreign)]
10pub trait LogCallback: Send + Sync {
11 fn on_log(&self, level: LogLevel, target: String, message: String) -> crate::Result<()>;
22}
23
24pub(crate) struct CallbackLayer {
26 callback: Arc<dyn LogCallback>,
27}
28impl CallbackLayer {
29 pub(crate) fn new(callback: Arc<dyn LogCallback>) -> Self {
30 Self { callback }
31 }
32}
33impl<S> Layer<S> for CallbackLayer
34where
35 S: tracing::Subscriber,
36{
37 fn on_event(&self, event: &tracing::Event<'_>, _ctx: Context<'_, S>) {
38 let metadata = event.metadata();
39 let level = metadata.level().into();
40 let target = metadata.target().to_string();
41
42 let mut message = String::new();
43 let writer = tracing_subscriber::fmt::format::Writer::new(&mut message);
44 let mut visitor = tracing_subscriber::fmt::format::DefaultVisitor::new(writer, false);
45 event.record(&mut visitor);
46
47 let _ = self.callback.on_log(level, target, message);
49 }
50}
51
52#[cfg(test)]
53mod tests {
54 use std::sync::{Arc, Mutex};
55
56 use super::*;
57
58 struct TestLogCallback {
59 logs: Arc<Mutex<Vec<(LogLevel, String, String)>>>,
60 }
61
62 impl LogCallback for TestLogCallback {
63 fn on_log(&self, level: LogLevel, target: String, message: String) -> crate::Result<()> {
64 self.logs.lock().unwrap().push((level, target, message));
65 Ok(())
66 }
67 }
68
69 #[test]
70 fn test_trait_can_be_implemented() {
71 let _callback: Arc<dyn LogCallback> = Arc::new(TestLogCallback {
72 logs: Arc::new(Mutex::new(Vec::new())),
73 });
74 }
75
76 #[test]
77 fn test_callback_layer_forwards_events() {
78 let logs = Arc::new(Mutex::new(Vec::new()));
80 let callback = Arc::new(TestLogCallback { logs: logs.clone() });
81 let _layer = CallbackLayer::new(callback);
82
83 assert!(logs.lock().unwrap().is_empty());
86 }
87}