Manual span creation

Creating SpanGuards

The #[span] attribute includes a guard control parameter that gives you access to a SpanGuard to manually complete it. The #[span] attribute takes care of constructing the SpanGuard for you and ensuring any ambient span properties are active in the body of your annotated function.

You can also create SpanGuards manually if you can't or don't want to use the #[span] attribute:

#![allow(unused)]
fn main() {
extern crate emit;
let (mut span, frame) = emit::new_span!("manual span");

frame.call(move || {
    span.start();

    // Your code goes here
})
}

The new_span! macro returns a tuple of SpanGuard for completing the span, and Frame for activating the span's ambient trace and span ids for correlation.

The syntax accepted by the new_span! macro is the same as the #[span] attribute.

Make sure you call SpanGuard::start in the closure in Frame::call or async block in Frame::in_future. If you don't call SpanGuard::start, the span won't be emitted. If you don't call it within the frame, the span may be emitted early and without its ambient context.

Using SpanGuards is the recommended way to trace code with emit. It applies filtering for you, so the span is only created if it matches the configured filter. It also ensures a span is emitted even if the traced code panics or otherwise returns without explicitly completing.

Creating spans without a SpanGuard

In cases where sampling or filtering aren't used, or when execution of a single span is split across multiple functions, you can create spans without using a SpanGuard:

#![allow(unused)]
fn main() {
extern crate emit;
// Create a new span context that is a child of the current one
// This context can be freely copied or stored elsewhere
let ctxt = emit::SpanCtxt::current(emit::ctxt())
    .new_child(emit::rng());

// Push the span onto the current context when you're about to execute
// some code within it
ctxt.push(emit::ctxt())
    .call(move || {
        let timer = emit::Timer::start(emit::clock());

        // Your code goes here
        let sleep_ms = 1200;
        std::thread::sleep(std::time::Duration::from_millis(sleep_ms));

        // Make sure you complete the span in the frame.
        // This is especially important for futures, otherwise the span may
        // complete before the future does
        emit::emit!(
            extent: timer,
            "wait a bit",
            evt_kind: "span",
            sleep_ms,
        );
    });
}

This approach can be used, for example, in web frameworks that split request handling across multiple independent function calls.

Creating spans without any ambient context

Trace and span ids don't need to be managed by emit if you have another scheme in mind. In these cases, they can be attached as regular properties to the span event:

#![allow(unused)]
fn main() {
extern crate emit;
let timer = emit::Timer::start(emit::clock());

// Your code goes here
let sleep_ms = 1200;
std::thread::sleep(std::time::Duration::from_millis(sleep_ms));

emit::emit! {
    extent: timer,
    "wait a bit",
    evt_kind: "span",
    trace_id: "4bf92f3577b34da6a3ce929d0e0e4736",
    span_id: "00f067aa0ba902b7",
    sleep_ms,
}
}

Note that when emitting spans as regular events that you still thread the trace context around somehow, otherwise other events emitted within its execution won't be correlated with it.