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