use serde::{Deserialize, Serialize}; use std::sync::Arc; use tauri::{AppHandle, Emitter}; use tracing::{Level, Subscriber}; use tracing_subscriber::layer::{Context, Layer}; #[derive(Debug, Clone, Serialize, Deserialize)] pub struct DebugLogEvent { pub level: String, pub message: String, } #[derive(Clone)] pub struct TauriLogLayer { app: Arc, } impl TauriLogLayer { pub fn new(app: AppHandle) -> Self { Self { app: Arc::new(app), } } } impl Layer for TauriLogLayer where S: Subscriber, { fn on_event( &self, event: &tracing::Event<'_>, _ctx: Context<'_, S>, ) { let metadata = event.metadata(); let level = match *metadata.level() { Level::ERROR => "error", Level::WARN => "warn", Level::INFO => "info", Level::DEBUG => "debug", Level::TRACE => "debug", }; // Extract message from the event struct MessageVisitor { message: String, } impl tracing::field::Visit for MessageVisitor { fn record_debug(&mut self, field: &tracing::field::Field, value: &dyn std::fmt::Debug) { if field.name() == "message" { self.message = format!("{:?}", value); } } } let mut visitor = MessageVisitor { message: String::new(), }; event.record(&mut visitor); // If we couldn't extract a message, try to format the whole event if visitor.message.is_empty() { visitor.message = metadata.name().to_string(); } // Strip quotes from the message let message = visitor.message.trim_matches('"').to_string(); let log_event = DebugLogEvent { level: level.to_string(), message, }; // Emit to frontend let _ = self.app.emit("debug:log", log_event); } }