A lightweight distributed tracing collector for your terminal — built in Rust.
SpanTide receives trace spans from your services over UDP, stores them in memory, and displays a live waterfall dashboard in your terminal. No config files, no database, no browser required.
When a request travels through multiple services, something always slows it down or breaks. SpanTide tells you exactly where.
Each service sends a small JSON message (a "span") to SpanTide over UDP saying "I handled this request, it took X milliseconds, status was Y." SpanTide collects all these spans, groups them by trace, and shows you the full picture in real time.
your services → UDP spans → SpanTide → live terminal dashboard
→ HTTP REST API
- UDP span receiver on port
4317 - Live terminal dashboard with waterfall view (
ratatui) - Keyboard navigation between traces
- Color coded spans — green for success, red for errors
- HTTP REST API to query traces programmatically
- Zero config, zero dependencies — just
cargo run
Prerequisites: Rust 1.75+ (install here)
git clone https://github.com/AkZcH/SpanTide
cd spantide
cargo runYou should see:
UDP listening on 0.0.0.0:4317
HTTP listening on 0.0.0.0:8080
And the terminal dashboard opens automatically.
SpanTide receives spans as JSON over UDP on port 4317.
Span format:
{
"trace_id": "req001",
"span_id": "s1",
"parent_id": null,
"service": "api-gateway",
"operation": "/users",
"started_at": "2024-01-01T00:00:00Z",
"duration_ms": 312,
"status": 200
}Send a test span (PowerShell):
$udpClient = New-Object System.Net.Sockets.UdpClient
$udpClient.Connect("127.0.0.1", 4317)
$bytes = [System.Text.Encoding]::UTF8.GetBytes('{"trace_id":"req001","span_id":"s1","parent_id":null,"service":"api-gateway","operation":"/users","started_at":"2024-01-01T00:00:00Z","duration_ms":312,"status":200}')
$udpClient.Send($bytes, $bytes.Length)
$udpClient.Close()Send a test span (Linux/macOS):
echo '{"trace_id":"req001","span_id":"s1","parent_id":null,"service":"api-gateway","operation":"/users","started_at":"2024-01-01T00:00:00Z","duration_ms":312,"status":200}' | nc -u 127.0.0.1 4317Run the included demo to see SpanTide in action with realistic multi-service traces:
# Windows Powershell
.\demo.ps1# Linux/macOS
chmod +x demo.sh && ./demo.shThis sends a realistic trace with 3 spans across api-gateway, db, and cache — including a simulated error.
While SpanTide is running, query your traces programmatically:
| Endpoint | Description |
|---|---|
GET /traces |
List all traces with span count and total duration |
GET /traces/:id |
Get all spans for a specific trace |
GET /stats |
Total trace and span counts |
Examples:
curl http://localhost:8080/traces
curl http://localhost:8080/traces/req001
curl http://localhost:8080/stats| Key | Action |
|---|---|
↑ / ↓ |
Navigate between traces |
q |
Quit |
┌─────────────────────────────────────────────────────┐
│ SpanTide │
│ │
│ ┌──────────┐ ┌──────────┐ ┌───────────┐ │
│ │ udp.rs │ │ http.rs │ │ tui.rs │ │
│ │ │ │ │ │ │ │
│ │ :4317 │ │ :8080 │ │ terminal │ │
│ └────┬─────┘ └────┬─────┘ └─────┬─────┘ │
│ │ │ │ │
│ └────────────────┴─────────────────┘ │
│ │ │
│ ┌──────▼──────┐ │
│ │ store.rs │ │
│ │ │ │
│ │ Arc<Mutex< │ │
│ │ HashMap>> │ │
│ └─────────────┘ │
└─────────────────────────────────────────────────────┘
All three components share a single SpanStore wrapped in Arc<Mutex<...>>, allowing safe concurrent access across async tasks.
spantide/
├── src/
│ ├── main.rs # entry point, spawns UDP, HTTP, and TUI
│ ├── span.rs # Span data model
│ ├── store.rs # thread-safe in-memory span storage
│ ├── udp.rs # async UDP listener
│ ├── http.rs # axum HTTP REST API
│ └── tui.rs # ratatui terminal dashboard
└── Cargo.toml
- tokio — async runtime
- axum — HTTP server
- ratatui — terminal UI
- serde — JSON serialization
- crossterm — terminal control
MIT
