tauri_plugin_tracing/
commands.rs

1//! Tauri command handlers for the tracing plugin.
2
3use crate::callstack::{CallStack, CallStackLine};
4use crate::layer::{LogLevel, LogMessage};
5use tauri::Runtime;
6use tracing::Level;
7
8#[cfg(feature = "flamegraph")]
9use tauri::AppHandle;
10
11#[tauri::command]
12#[tracing::instrument(skip_all, fields(w = %CallStackLine::from(webview_window.label())))]
13pub fn log<R: Runtime>(
14    webview_window: tauri::WebviewWindow<R>,
15    level: LogLevel,
16    message: LogMessage,
17    call_stack: Option<&str>,
18) {
19    let stack = CallStack::from(call_stack);
20    let loc = match level {
21        LogLevel::Trace => stack.location(),
22        LogLevel::Debug => stack.path(),
23        LogLevel::Info => stack.file_name(),
24        LogLevel::Warn => stack.path(),
25        LogLevel::Error => stack.location(),
26    };
27    macro_rules! emit_event {
28        ($level:expr) => {
29            tracing::event!(
30                target: "",
31                $level,
32                %message,
33                "" = %loc,
34            )
35        };
36    }
37    match level {
38        LogLevel::Trace => emit_event!(Level::TRACE),
39        LogLevel::Debug => emit_event!(Level::DEBUG),
40        LogLevel::Info => emit_event!(Level::INFO),
41        LogLevel::Warn => emit_event!(Level::WARN),
42        LogLevel::Error => emit_event!(Level::ERROR),
43    }
44}
45
46/// Generates a flamegraph SVG from the recorded profiling data.
47///
48/// Returns the path to the generated SVG file.
49#[cfg(feature = "flamegraph")]
50#[tauri::command]
51pub fn generate_flamegraph<R: Runtime>(app: AppHandle<R>) -> crate::Result<String> {
52    use crate::flamegraph::{FlameState, generate_flamegraph_svg};
53    use tauri::Manager;
54
55    let state = app.state::<FlameState>();
56    let path_lock = state
57        .folded_path
58        .lock()
59        .map_err(|e| crate::Error::LockPoisoned(e.to_string()))?;
60
61    let folded_path = path_lock
62        .as_ref()
63        .ok_or_else(|| crate::Error::Io(std::io::Error::other("No profiling data available")))?;
64
65    // Flush the guard to ensure all data is written
66    {
67        let mut guard_lock = state
68            .guard
69            .lock()
70            .map_err(|e| crate::Error::LockPoisoned(e.to_string()))?;
71        if let Some(guard) = guard_lock.take() {
72            drop(guard);
73        }
74    }
75
76    let svg_path = generate_flamegraph_svg(folded_path)?;
77    Ok(svg_path.to_string_lossy().to_string())
78}
79
80/// Generates a flamechart SVG from the recorded profiling data.
81///
82/// Unlike flamegraphs, flamecharts preserve the exact ordering of events.
83/// Returns the path to the generated SVG file.
84#[cfg(feature = "flamegraph")]
85#[tauri::command]
86pub fn generate_flamechart<R: Runtime>(app: AppHandle<R>) -> crate::Result<String> {
87    use crate::flamegraph::{FlameState, generate_flamechart_svg};
88    use tauri::Manager;
89
90    let state = app.state::<FlameState>();
91    let path_lock = state
92        .folded_path
93        .lock()
94        .map_err(|e| crate::Error::LockPoisoned(e.to_string()))?;
95
96    let folded_path = path_lock
97        .as_ref()
98        .ok_or_else(|| crate::Error::Io(std::io::Error::other("No profiling data available")))?;
99
100    // Flush the guard to ensure all data is written
101    {
102        let mut guard_lock = state
103            .guard
104            .lock()
105            .map_err(|e| crate::Error::LockPoisoned(e.to_string()))?;
106        if let Some(guard) = guard_lock.take() {
107            drop(guard);
108        }
109    }
110
111    let svg_path = generate_flamechart_svg(folded_path)?;
112    Ok(svg_path.to_string_lossy().to_string())
113}