Expand description
§Tauri Plugin Tracing
A Tauri plugin that integrates the tracing crate for structured logging
in Tauri applications. This plugin bridges logging between the Rust backend
and JavaScript frontend, providing call stack information.
§Features
colored: Enables colored terminal output using ANSI escape codesspecta: Enables TypeScript type generation via thespectacrateflamegraph: Enables flamegraph/flamechart profiling support (wall-clock span timing)profiling: Enables CPU profiling viatauri-plugin-profiling
§Usage
By default, this plugin does not set up a global tracing subscriber,
following the convention that libraries should not set globals. You compose
your own subscriber using WebviewLayer to forward logs to the frontend:
let tracing_builder = Builder::new()
.with_max_level(LevelFilter::DEBUG)
.with_target("hyper", LevelFilter::WARN);
let filter = tracing_builder.build_filter();
tauri::Builder::default()
.plugin(tracing_builder.build())
.setup(move |app| {
Registry::default()
.with(fmt::layer())
.with(WebviewLayer::new(app.handle().clone()))
.with(filter)
.init();
Ok(())
});
// .run(tauri::generate_context!("examples/default-subscriber/src-tauri/tauri.conf.json"))§Quick Start
For simple applications, use Builder::with_default_subscriber() to let
the plugin handle all tracing setup:
tauri::Builder::default()
.plugin(
Builder::new()
.with_max_level(LevelFilter::DEBUG)
.with_default_subscriber() // Let plugin set up tracing
.build(),
);
// .run(tauri::generate_context!("examples/default-subscriber/src-tauri/tauri.conf.json"))§File Logging
For simple file logging, use Builder::with_file_logging():
Builder::new()
.with_max_level(LevelFilter::DEBUG)
.with_file_logging()
.with_default_subscriber()
.build::<tauri::Wry>();For custom subscribers, use tracing_appender directly (re-exported by this crate):
let tracing_builder = Builder::new().with_max_level(LevelFilter::DEBUG);
let filter = tracing_builder.build_filter();
tauri::Builder::default()
.plugin(tracing_builder.build())
.setup(move |app| {
let log_dir = app.path().app_log_dir()?;
let file_appender = tracing_appender::rolling::daily(&log_dir, "app");
let (non_blocking, _guard) = tracing_appender::non_blocking(file_appender);
// Store _guard in Tauri state to keep file logging active
Registry::default()
.with(fmt::layer())
.with(fmt::layer().with_ansi(false).with_writer(non_blocking))
.with(WebviewLayer::new(app.handle().clone()))
.with(filter)
.init();
Ok(())
});
// .run(tauri::generate_context!("examples/default-subscriber/src-tauri/tauri.conf.json"))Log files rotate daily and are written to:
- macOS:
~/Library/Logs/{bundle_identifier}/app.YYYY-MM-DD.log - Linux:
~/.local/share/{bundle_identifier}/logs/app.YYYY-MM-DD.log - Windows:
%LOCALAPPDATA%/{bundle_identifier}/logs/app.YYYY-MM-DD.log
§Early Initialization
For maximum control, initialize tracing before creating the Tauri app. This
pattern uses tracing_subscriber::registry() with init()
and passes a minimal Builder to the plugin:
use tauri_plugin_tracing::{Builder, StripAnsiWriter, tracing_appender};
use tracing::Level;
use tracing_subscriber::filter::Targets;
use tracing_subscriber::layer::SubscriberExt;
use tracing_subscriber::util::SubscriberInitExt;
use tracing_subscriber::{fmt, registry};
fn setup_logger() -> Builder {
let log_dir = std::env::temp_dir().join("my-app");
let _ = std::fs::create_dir_all(&log_dir);
let file_appender = tracing_appender::rolling::daily(&log_dir, "app");
let (non_blocking, guard) = tracing_appender::non_blocking(file_appender);
std::mem::forget(guard); // Keep file logging active for app lifetime
let targets = Targets::new()
.with_default(Level::DEBUG)
.with_target("hyper", Level::WARN)
.with_target("reqwest", Level::WARN);
registry()
.with(fmt::layer().with_ansi(true))
.with(fmt::layer().with_writer(StripAnsiWriter::new(non_blocking)).with_ansi(false))
.with(targets)
.init();
// Return minimal builder - logging is already configured
Builder::new()
}
fn main() {
let builder = setup_logger();
tauri::Builder::default()
.plugin(builder.build());
// .run(tauri::generate_context!("examples/default-subscriber/src-tauri/tauri.conf.json"))
}This approach is useful when you need logging available before Tauri starts, or when you want full control over the subscriber configuration.
§Flamegraph Profiling
The flamegraph feature enables performance profiling with flamegraph/flamechart
visualizations.
§With Default Subscriber
Builder::new()
.with_max_level(LevelFilter::DEBUG)
.with_flamegraph()
.with_default_subscriber()
.build::<tauri::Wry>();§With Custom Subscriber
Use [create_flame_layer()] to add flamegraph profiling to a custom subscriber:
use tauri_plugin_tracing::{Builder, WebviewLayer, LevelFilter, create_flame_layer};
use tracing_subscriber::{Registry, layer::SubscriberExt, util::SubscriberInitExt, fmt};
fn main() {
let tracing_builder = Builder::new().with_max_level(LevelFilter::DEBUG);
let filter = tracing_builder.build_filter();
tauri::Builder::default()
.plugin(tracing_builder.build())
.setup(move |app| {
let flame_layer = create_flame_layer(app.handle())?;
Registry::default()
.with(flame_layer) // Must be first - typed for Registry
.with(fmt::layer())
.with(WebviewLayer::new(app.handle().clone()))
.with(filter)
.init();
Ok(())
})
.run(tauri::generate_context!("examples/default-subscriber/src-tauri/tauri.conf.json"))
.expect("error while running tauri application");
}§Early Initialization with Flamegraph
Use [create_flame_layer_with_path()] and [FlameExt] to initialize tracing
before Tauri starts while still enabling frontend flamegraph generation:
use tauri_plugin_tracing::{Builder, create_flame_layer_with_path, FlameExt};
use tracing_subscriber::{registry, layer::SubscriberExt, util::SubscriberInitExt, fmt};
fn main() {
let log_dir = std::env::temp_dir().join("my-app");
std::fs::create_dir_all(&log_dir).unwrap();
// Create flame layer before Tauri starts
let (flame_layer, flame_guard) = create_flame_layer_with_path(
&log_dir.join("profile.folded")
).unwrap();
// Initialize tracing early
registry()
.with(flame_layer) // Must be first - typed for Registry
.with(fmt::layer())
.init();
// Now start Tauri and register the guard
tauri::Builder::default()
.plugin(Builder::new().build())
.setup(move |app| {
// Register the guard so JS can generate flamegraphs
app.handle().register_flamegraph(flame_guard)?;
Ok(())
})
.run(tauri::generate_context!("examples/default-subscriber/src-tauri/tauri.conf.json"))
.expect("error while running tauri application");
}Then generate visualizations from JavaScript:
import { generateFlamegraph, generateFlamechart } from '@fltsci/tauri-plugin-tracing';
// Generate a flamegraph (collapses identical stack frames)
const flamegraphPath = await generateFlamegraph();
// Generate a flamechart (preserves event ordering)
const flamechartPath = await generateFlamechart();§CPU Profiling
The profiling feature enables sampling-based CPU profiling via
tauri-plugin-profiling.
Unlike flamegraph profiling (which measures wall-clock time including I/O waits),
CPU profiling measures actual CPU cycles spent executing code.
Use [TracedProfilingExt] for automatic span creation and logging:
use tauri::Manager;
use tauri_plugin_tracing::{Builder, LevelFilter, TracedProfilingExt, init_profiling};
tauri::Builder::default()
.plugin(Builder::new().with_max_level(LevelFilter::DEBUG).build())
.plugin(init_profiling())
.setup(|app| {
// Start CPU profiling with automatic span + logging
app.start_cpu_profile_traced()?;
// ... do CPU-intensive work ...
// Stop - automatically logs results (samples, duration, path)
let result = app.stop_cpu_profile_traced()?;
Ok(())
})
.run(tauri::generate_context!("examples/default-subscriber/src-tauri/tauri.conf.json"))
.expect("error while running tauri application");Or use the base ProfilingExt trait directly without tracing integration.
From JavaScript (import from the profiling package directly):
import { startCpuProfile, stopCpuProfile } from '@fltsci/tauri-plugin-profiling';
await startCpuProfile({ frequency: 100 });
// ... do work ...
const result = await stopCpuProfile();
console.log('CPU flamegraph:', result.flamegraphPath);§JavaScript API
import { trace, debug, info, warn, error } from '@fltsci/tauri-plugin-tracing';
info('Application started');
debug('Debug information', { key: 'value' });
error('Something went wrong');Re-exports§
pub use tracing;pub use tracing_appender;pub use tracing_subscriber;
Structs§
- Builder
- Builder for configuring and creating the tracing plugin.
- Call
Stack - A parsed JavaScript call stack.
- Call
Stack Line - A single line from a JavaScript call stack.
- Format
Options - Configuration options for log output formatting.
- Level
Filter - Re-export of
tracing_subscriber::filter::LevelFilterfor configuring log levels. A filter comparable to a verbosityLevel. - LogMessage
- A log message consisting of one or more string parts.
- MaxFile
Size - Maximum file size for log rotation.
- Record
Payload - Payload for a log record, used when emitting events to the webview.
- Strip
Ansi Writer - A writer wrapper that strips ANSI escape codes from all output.
- Strip
Ansi Writer Guard - A writer handle returned by the
MakeWriterimplementation. - Webview
Layer - A tracing layer that emits log events to the webview via Tauri events.
Enums§
- Error
- Errors that can occur when using the tracing plugin.
- LogFormat
- Log output format style.
- LogLevel
- An enum representing the available verbosity levels of the logger.
- Rotation
- Time-based rotation period for log files.
- Rotation
Strategy - Retention policy for rotated log files.
- Target
- Specifies a log output destination.
- Timezone
Strategy - Timezone strategy for log timestamps.
Functions§
Type Aliases§
- Boxed
Layer - A boxed tracing layer that can be added to the default subscriber.
- Filter
Fn - A boxed filter function for metadata-based log filtering.
- Result
- A specialized
Resulttype for tracing plugin operations.