Expand description

A high-performance, ergonomic timeline tracing library for Rust.

Span

A SpanRecord represents an individual unit of work. It contains:

  • An operation name
  • A start timestamp and duration
  • A set of key-value properties
  • A reference to a parent Span

To record such a span record, we create a Span to start clocking and drop it to stop recording.

A new Span can be started via Span::root() and Span::enter_with_parent(). Span::enter_with_parent() will start a child span to a given parent span.

Span is thread-safe and can be sent across threads.

use minitrace::prelude::*;
use futures::executor::block_on;

let (root, collector) = Span::root("root");

{
    let _child_span = Span::enter_with_parent("a child span", &root);
    // some work
}

drop(root);
let records: Vec<SpanRecord> = block_on(collector.collect());

println!("{:#?}", records);
// [
//     SpanRecord {
//         id: 1,
//         parent_id: 0,
//         begin_unix_time_ns: 1642166520139678013,
//         duration_ns: 16008,
//         event: "root",
//         properties: [],
//     },
//     SpanRecord {
//         id: 2,
//         parent_id: 1,
//         begin_unix_time_ns: 1642166520139692070,
//         duration_ns: 634,
//         event: "a child span",
//         properties: [],
//     },
// ]

Local Span

A Span can be optimized into LocalSpan, if the span is not supposed to be sent to other threads, which can greatly reduce the overhead.

Before starting a LocalSpan, a scope of parent span should be set using Span::set_local_parent(). Use LocalSpan::enter_with_local_parent() to start a LocalSpan, and then, it will become the new local parent.

If no local parent is set, the enter_with_local_parent() will do nothing.

use minitrace::prelude::*;

let (root, collector) = Span::root("root");

{
    let _guard = root.set_local_parent();

    // The parent of this span is `root`.
    let _span1 = LocalSpan::enter_with_local_parent("a child span");

    foo();
}

fn foo() {
    // The parent of this span is `span1`.
    let _span2 = LocalSpan::enter_with_local_parent("a child span of child span");
}

Property

Property is an arbitrary custom kev-value pair associated to a span.

use minitrace::prelude::*;
use futures::executor::block_on;

let (mut root, collector) = Span::root("root");
root.with_property(|| ("key", "value".to_owned()));

{
    let _guard = root.set_local_parent();

    let _span1 = LocalSpan::enter_with_local_parent("a child span")
        .with_property(|| ("key", "value".to_owned()));
}

drop(root);
let records: Vec<SpanRecord> = block_on(collector.collect());

println!("{:#?}", records);
// [
//     SpanRecord {
//         id: 1,
//         parent_id: 0,
//         begin_unix_time_ns: 1642166791041022255,
//         duration_ns: 121705,
//         event: "root",
//         properties: [
//             (
//                 "key",
//                 "value",
//             ),
//         ],
//     },
//     SpanRecord {
//         id: 2,
//         parent_id: 1,
//         begin_unix_time_ns: 1642166791041132550,
//         duration_ns: 7724,
//         event: "a child span",
//         properties: [
//             (
//                 "key",
//                 "value",
//             ),
//         ],
//     },
// ]

Macro

An attribute-macro trace can help get rid of boilerplate. The macro always requires a local parent in the context, otherwise, no span will be recorded.

use minitrace::prelude::*;
use futures::executor::block_on;

#[trace("do_something")]
fn do_something(i: u64) {
    std::thread::sleep(std::time::Duration::from_millis(i));
}

#[trace("do_something_async")]
async fn do_something_async(i: u64) {
    futures_timer::Delay::new(std::time::Duration::from_millis(i)).await;
}

let (root, collector) = Span::root("root");

{
    let _g = root.set_local_parent();
    do_something(100);
    block_on(do_something_async(100));
}

drop(root);
let records: Vec<SpanRecord> = block_on(collector.collect());

println!("{:#?}", records);
// [
//     SpanRecord {
//         id: 1,
//         parent_id: 0,
//         begin_unix_time_ns: 1642167988459480418,
//         duration_ns: 200741472,
//         event: "root",
//         properties: [],
//     },
//     SpanRecord {
//         id: 2,
//         parent_id: 1,
//         begin_unix_time_ns: 1642167988459571971,
//         duration_ns: 100084126,
//         event: "do_something",
//         properties: [],
//     },
//     SpanRecord {
//         id: 3,
//         parent_id: 1,
//         begin_unix_time_ns: 1642167988559887219,
//         duration_ns: 100306947,
//         event: "do_something_async",
//         properties: [],
//     },
// ]

Modules

Collector and the collected spans.

Tools to trace a Future.

Non thread-safe span with low overhead.

A “prelude” for crates using the minitrace crate.

Structs

A thread-safe span.

Attribute Macros

An attribute-macro to help get rid of boilerplate.