Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

ashlar-trace: telemetry

Crash, performance and usage telemetry for Rust desktop apps, with a backend you host yourself.

  • ashlar-trace — a small client you embed. Safe Rust only, no async runtime, no UI toolkit. It never blocks your frame loop and never prints.
  • ashlar-trace-server — one binary and one data folder: ingest API, SQLite storage, and a dashboard for crashes, performance and usage.
  • ashlar-trace-proto — the wire types both share.

Status: release candidate, load-tested; not yet published. See roadmap.md. Apps built on ashlar use it through ashlar-telemetry, which wires it to the command chokepoint, logging, the frame loop and native dialogs.

What it collects

SignalWhat you get
CrashesPanics with backtrace, handled errors, unclean exits found on next launch, abnormal child-process exits, each with recent log lines and device details.
HangsA report when the main loop stops responding.
PerformanceFrame-time histogram, slow and frozen frames, startup time, process CPU and memory, plus your own counters and gauges.
UsageSessions, daily opens, focused / active / idle time, and the events you declare.

The host app decides what is tracked. Events are declared as enums and checked at build time; anything not declared and listened to is never recorded. End users can switch each category off, and DO_NOT_TRACK=1 is honoured. docs/privacy.md lists every field.

Sketch

ashlar_trace::events! {
    pub enum Category { File = "file", Edit = "edit" }
    pub enum AppEvent {
        FileOpen = "file.open" in File,
        Undo = "edit.undo" in Edit,
    }
}

let tracer = ashlar_trace::Tracer::builder("app-write-key", "my-app", env!("CARGO_PKG_VERSION"))
    .data_dir(my_data_dir)
    .endpoint("https://telemetry.example.com")
    .listen(Category::File)
    .init();

// Nothing is sent until the user has seen your first-run notice.
tracer.notice_shown();

// Once per turn of the main loop:
let _turn = tracer.turn();      // a turn that takes too long is reported as a hang
tracer.track(AppEvent::FileOpen);
tracer.frame(frame_duration);   // once per frame

Documentation

Development

The crates are part of the ashlar workspace and its gate (cargo xtask ci). Heavier runs: cargo xtask trace-stress (the SDK’s benchmarks and stress tests, release build), cargo xtask trace-load (a short load profile against a spawned release server) and cargo xtask trace-demo (checks the windowed demo, which is its own workspace).