rama::telemetry::opentelemetry::trace

Trait Tracer

pub trait Tracer {
    type Span: Span;

    // Required method
    fn build_with_context(
        &self,
        builder: SpanBuilder,
        parent_cx: &Context,
    ) -> Self::Span;

    // Provided methods
    fn start<T>(&self, name: T) -> Self::Span
       where T: Into<Cow<'static, str>> { ... }
    fn start_with_context<T>(&self, name: T, parent_cx: &Context) -> Self::Span
       where T: Into<Cow<'static, str>> { ... }
    fn span_builder<T>(&self, name: T) -> SpanBuilder
       where T: Into<Cow<'static, str>> { ... }
    fn build(&self, builder: SpanBuilder) -> Self::Span { ... }
    fn in_span<T, F, N>(&self, name: N, f: F) -> T
       where F: FnOnce(Context) -> T,
             N: Into<Cow<'static, str>>,
             Self::Span: Send + Sync + 'static { ... }
}
Expand description

The interface for constructing Spans.

§In Synchronous Code

Spans can be created and nested manually:

use opentelemetry::{global, trace::{Span, Tracer, TraceContextExt}, Context};

let tracer = global::tracer("my-component");

let parent = tracer.start("foo");
let parent_cx = Context::current_with_span(parent);
let mut child = tracer.start_with_context("bar", &parent_cx);

// ...

child.end(); // explicitly end
drop(parent_cx) // or implicitly end on drop

Spans can also use the current thread’s Context to track which span is active:

use opentelemetry::{global, trace::{SpanKind, Tracer}};

let tracer = global::tracer("my-component");

// Create simple spans with `in_span`
tracer.in_span("foo", |_foo_cx| {
    // parent span is active
    tracer.in_span("bar", |_bar_cx| {
        // child span is now the active span and associated with the parent span
    });
    // child has ended, parent now the active span again
});
// parent has ended, no active spans

Spans can also be marked as active, and the resulting guard allows for greater control over when the span is no longer considered active.

use opentelemetry::{global, trace::{Span, Tracer, mark_span_as_active}};
let tracer = global::tracer("my-component");

let parent_span = tracer.start("foo");
let parent_active = mark_span_as_active(parent_span);

{
    let child = tracer.start("bar");
    let _child_active = mark_span_as_active(child);

    // do work in the context of the child span...

    // exiting the scope drops the guard, child is no longer active
}
// Parent is active span again

// Parent can be dropped manually, or allowed to go out of scope as well.
drop(parent_active);

// no active span

§In Asynchronous Code

If you are instrumenting code that make use of std::future::Future or async/await, be sure to use the FutureExt trait. This is needed because the following example will not work:

async {
    // Does not work
    let _g = mark_span_as_active(span);
    // ...
};

The context guard _g will not exit until the future generated by the async block is complete. Since futures can be entered and exited multiple times without them completing, the span remains active for as long as the future exists, rather than only when it is polled, leading to very confusing and incorrect output.

In order to trace asynchronous code, the Future::with_context combinator can be used:

use opentelemetry::{trace::FutureExt, Context};
let cx = Context::current();

let my_future = async {
    // ...
};

my_future
    .with_context(cx)
    .await;

Future::with_context attaches a context to the future, ensuring that the context’s lifetime is as long as the future’s.

Required Associated Types§

type Span: Span

The Span type used by this tracer.

Required Methods§

fn build_with_context( &self, builder: SpanBuilder, parent_cx: &Context, ) -> Self::Span

Start a span from a SpanBuilder with a parent context.

Provided Methods§

fn start<T>(&self, name: T) -> Self::Span
where T: Into<Cow<'static, str>>,

Starts a new Span.

By default the currently active Span is set as the new Span’s parent.

Each span has zero or one parent span and zero or more child spans, which represent causally related operations. A tree of related spans comprises a trace. A span is said to be a root span if it does not have a parent. Each trace includes a single root span, which is the shared ancestor of all other spans in the trace.

fn start_with_context<T>(&self, name: T, parent_cx: &Context) -> Self::Span
where T: Into<Cow<'static, str>>,

Starts a new Span with a given context.

If this context contains a span, the newly created span will be a child of that span.

Each span has zero or one parent span and zero or more child spans, which represent causally related operations. A tree of related spans comprises a trace. A span is said to be a root span if it does not have a parent. Each trace includes a single root span, which is the shared ancestor of all other spans in the trace.

fn span_builder<T>(&self, name: T) -> SpanBuilder
where T: Into<Cow<'static, str>>,

Creates a span builder.

SpanBuilders allow you to specify all attributes of a Span before the span is started.

fn build(&self, builder: SpanBuilder) -> Self::Span

Start a Span from a SpanBuilder.

fn in_span<T, F, N>(&self, name: N, f: F) -> T
where F: FnOnce(Context) -> T, N: Into<Cow<'static, str>>, Self::Span: Send + Sync + 'static,

Start a new span and execute the given closure with reference to the context in which the span is active.

This method starts a new span and sets it as the active span for the given function. It then executes the body. It ends the span before returning the execution result.

§Examples
use opentelemetry::{global, trace::{Span, Tracer, get_active_span}, KeyValue};

fn my_function() {
    // start an active span in one function
    global::tracer("my-component").in_span("span-name", |_cx| {
        // anything happening in functions we call can still access the active span...
        my_other_function();
    })
}

fn my_other_function() {
    // call methods on the current span from
    get_active_span(|span| {
        span.add_event("An event!".to_string(), vec![KeyValue::new("happened", true)]);
    })
}

Object Safety§

This trait is not object safe.

Implementors§