Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changes/shorten-readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"tracing": patch
"tracing-js": patch
---

Shorten README, link to docs.rs for details.
355 changes: 20 additions & 335 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,52 +1,16 @@
# Tauri Plugin Tracing

A Tauri plugin that integrates the Rust `tracing` crate for structured logging, bridging logs between your Rust backend and JavaScript frontend.

## Why tauri-plugin-tracing?

This plugin provides everything `tauri-plugin-log` offers, plus advanced capabilities from the `tracing` ecosystem.

### Feature Comparison

| Feature | tauri-plugin-log | tauri-plugin-tracing |
|---------|------------------|----------------------|
| Log levels (trace/debug/info/warn/error) | ✓ | ✓ |
| Console output (stdout/stderr) | ✓ | ✓ |
| File logging with rotation | ✓ | ✓ |
| Forward logs to webview | ✓ | ✓ |
| Per-module filtering | ✓ | ✓ |
| Colored output | ✓ | ✓ |
| Custom log formats | ✓ | ✓ |
| Size-based rotation | ✓ | ✓ |
| **Structured span context** | | ✓ |
| **Custom tracing layers** | | ✓ |
| **OpenTelemetry integration** | | ✓ |
| **Span timing visualization** | | ✓ |
| **Early initialization** | | ✓ |

### Additional Features

- **Structured Spans**: Track execution context across async boundaries with `tracing` spans
- **Custom Layers**: Add OpenTelemetry, Sentry, or any `tracing-subscriber` layer
- **Span Timing Visualization**: Generate flamegraphs/flamecharts showing span durations and call hierarchy
- **Early Initialization**: Set up logging before Tauri starts for complete startup tracing
- **ANSI Stripping**: `StripAnsiWriter` removes color codes when writing to files
Integrate Rust's `tracing` crate with your Tauri app. Bridge logs between Rust and JavaScript with support for file rotation, custom layers, and span visualization.

## Installation

### Rust

```toml
[dependencies]
tauri-plugin-tracing = "0.2"
```

### JavaScript

```bash
npm install @fltsci/tauri-plugin-tracing
# or
pnpm add @fltsci/tauri-plugin-tracing
```

## Quick Start
Expand All @@ -68,318 +32,39 @@ fn main() {
```

```typescript
import { info, debug, error, attachConsole } from '@fltsci/tauri-plugin-tracing';

// Forward Rust logs to browser console
await attachConsole();
import { info, attachConsole } from '@fltsci/tauri-plugin-tracing';

// Log from JavaScript
info('Application started');
debug('Debug details', { user: 'alice' });
error('Something went wrong');
await attachConsole(); // See Rust logs in browser console
info('Hello from JS'); // Send JS logs to Rust
```

## Features

### Cargo Features

- **`colored`** - ANSI color output in terminal
- **`specta`** - TypeScript type generation
- **`flamegraph`** - Span timing visualization with flamegraph/flamechart SVG generation

### Log Targets

Configure where logs are written:

```rust
use tauri_plugin_tracing::{Builder, Target};

Builder::new()
.targets([
Target::Stdout,
Target::Webview,
Target::LogDir { file_name: None },
])
.with_default_subscriber()
.build()
```

- **Stdout** / **Stderr** - Terminal output
- **Webview** - Forward to JavaScript via events
- **LogDir** - Platform log directory (`~/Library/Logs/` on macOS)
- **Folder** - Custom directory

### File Logging

```rust
Builder::new()
.with_file_logging() // Enable file logging
.with_rotation(Rotation::Daily) // Rotate daily
.with_rotation_strategy(RotationStrategy::KeepSome(7)) // Keep 7 files
.with_max_file_size(MaxFileSize::mb(10)) // Rotate at 10 MB
.with_default_subscriber()
.build()
```

### Per-Module Filtering

```rust
Builder::new()
.with_max_level(LevelFilter::INFO)
.with_target("my_app::database", LevelFilter::DEBUG)
.with_target("hyper", LevelFilter::WARN)
.with_default_subscriber()
.build()
```

### Custom Formatting

```rust
use tauri_plugin_tracing::{Builder, LogFormat};

Builder::new()
.with_format(LogFormat::Compact) // or Full, Pretty
.with_file(true)
.with_line_number(true)
.with_thread_ids(true)
.with_default_subscriber()
.build()
```

### Custom Tracing Layers

```rust
use tracing_subscriber::Layer;

let otel_layer = tracing_opentelemetry::layer().boxed();

Builder::new()
.with_layer(otel_layer)
.with_default_subscriber()
.build()
```

### Span Timing Visualization

Requires the `flamegraph` feature.

> **Note:** This captures span durations (wall-clock time), not CPU time. It's useful for
> understanding call hierarchy and finding latency bottlenecks, but not for CPU profiling.
> For CPU profiling, use Instruments (macOS), `perf` (Linux), or `samply`.

**With default subscriber:**

```rust
Builder::new()
.with_flamegraph()
.with_default_subscriber()
.build()
```

**With custom subscriber:**

```rust
use tauri_plugin_tracing::{Builder, WebviewLayer, LevelFilter, create_flame_layer};
use tracing_subscriber::{Registry, layer::SubscriberExt, util::SubscriberInitExt, fmt};

let builder = Builder::new().with_max_level(LevelFilter::DEBUG);
let filter = builder.build_filter();

tauri::Builder::default()
.plugin(builder.build())
.setup(move |app| {
let flame_layer = create_flame_layer(app.handle())?;

Registry::default()
.with(fmt::layer())
.with(WebviewLayer::new(app.handle().clone()))
.with(flame_layer)
.with(filter)
.init();
Ok(())
})
.run(tauri::generate_context!())
.expect("error while running tauri application");
```

**Early initialization (before Tauri starts):**

```rust
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(fmt::layer())
.with(flame_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!())
.expect("error while running tauri application");
}
```

**Generate visualizations from JavaScript:**

```typescript
import { generateFlamegraph, generateFlamechart } from '@fltsci/tauri-plugin-tracing';

// Generate a flamegraph (collapses identical stack frames, shows cumulative time)
const flamegraphPath = await generateFlamegraph();

// Generate a flamechart (preserves chronological ordering)
const flamechartPath = await generateFlamechart();
```

## Custom Subscriber Setup

For advanced use cases, compose your own subscriber:

```rust
use tauri_plugin_tracing::{Builder, WebviewLayer, LevelFilter};
use tracing_subscriber::{Registry, layer::SubscriberExt, util::SubscriberInitExt, fmt};

let builder = Builder::new()
.with_max_level(LevelFilter::DEBUG)
.with_target("hyper", LevelFilter::WARN);

let filter = builder.build_filter();

tauri::Builder::default()
.plugin(builder.build())
.setup(move |app| {
Registry::default()
.with(fmt::layer())
.with(WebviewLayer::new(app.handle().clone()))
.with(filter)
.init();
Ok(())
})
.run(tauri::generate_context!())
.expect("error while running tauri application");
```

### Custom Subscriber with File Logging

Use `tracing_appender` (re-exported by this crate) for file logging with custom subscribers:

```rust
use tauri::Manager;
use tauri_plugin_tracing::{Builder, WebviewLayer, LevelFilter, tracing_appender};
use tracing_subscriber::{Registry, layer::SubscriberExt, util::SubscriberInitExt, fmt};

let builder = Builder::new().with_max_level(LevelFilter::DEBUG);
let filter = builder.build_filter();

tauri::Builder::default()
.plugin(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
app.manage(guard);

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!())
.expect("error while running tauri application");
```

### Early Initialization

For maximum control, initialize tracing before creating the Tauri app:

```rust
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();
- **Log levels**: trace, debug, info, warn, error
- **Targets**: stdout, stderr, webview, file (with rotation)
- **Filtering**: per-module log levels
- **Custom layers**: OpenTelemetry, Sentry, or any tracing-subscriber layer
- **Span visualization**: flamegraph/flamechart SVG generation (`flamegraph` feature)

Builder::new() // Return minimal builder - logging is already configured
}

fn main() {
let builder = setup_logger();
tauri::Builder::default()
.plugin(builder.build())
.run(tauri::generate_context!())
.expect("error while running tauri application");
}
```
### Cargo Features

## JavaScript API
- `colored` - ANSI color output
- `specta` - TypeScript type generation
- `flamegraph` - Span timing visualization

### Logging
## Console Integration

```typescript
import { trace, debug, info, warn, error } from '@fltsci/tauri-plugin-tracing';
import { attachConsole, interceptConsole, takeoverConsole } from '@fltsci/tauri-plugin-tracing';

trace('Very verbose info');
debug('Debug details');
info('General info');
warn('Warning');
error('Error');
attachConsole(); // Rust logs → browser console
interceptConsole(); // JS console → Rust tracing
takeoverConsole(); // Both directions (full integration)
```

### Event Listeners

```typescript
import { attachConsole, attachLogger } from '@fltsci/tauri-plugin-tracing';

// Forward all Rust logs to browser console
const unlisten = await attachConsole();
## Documentation

// Custom log handler
const unlisten = await attachLogger(({ level, message }) => {
// Send to external service, store locally, etc.
});
```
See [docs.rs](https://docs.rs/tauri-plugin-tracing) for the full API reference and advanced usage (custom subscribers, file logging, early initialization).

## License

Expand Down
Loading