Skip to main content

span

Macro span 

Source
span!() { /* proc-macro */ }
Expand description

Creates a new span using OpenTelemetry.

This macro provides a concise syntax for creating spans with optional attributes, span kind, parent context, and body (closure or async block).

§Syntax

span!(name [, scope: expr] [, parent: cx] [, kind: K] [, attrs...] [, body])

Where:

  • name - Span name (string literal or expression)
  • scope: expr - Optional instrumentation scope. If omitted, uses calling crate’s scope.
  • parent: cx - Optional parent context. If omitted, uses Context::current().
  • kind: K - Optional span kind (e.g., kind: SpanKind::Server)
  • attrs... - Optional attributes as "key" = value pairs
  • body - Optional body: || { }, move || { }, async { }, or async move { }

Without a body, returns the span for manual lifetime management. With a body, the span is active for the duration of the closure/async block.

§Examples

use apollo_opentelemetry::span;
use opentelemetry::trace::SpanKind;

// Simple span
let _span = span!("my-operation");

// With closure
span!("process", || {
    // work happens here
});

// With kind and attributes
span!("db-query", kind: SpanKind::Client, "db.system" = "postgresql", || {
    // execute query
});

// Async
span!("async-operation", async {
    // async work
}).await;

§Spawned tasks

The async block form returns a Future, making it composable with tokio::spawn(), select!, join!, etc. The span context is captured when the span is created, so spawned tasks inherit the parent automatically:

use apollo_opentelemetry::span;

span!("parent", async {
    tokio::spawn(span!("child", async {
        do_background_work().await;
    })).await.unwrap();
}).await;

§Dynamic span names

Span names can be expressions — variables, format!, function calls, etc.:

use apollo_opentelemetry::span;

let name = String::from("dynamic-span");
let _span = span!(name);

let id = 42u32;
span!(format!("request-{id}"), || { /* work */ });

§Optional attributes

Attribute values of Option<T> are silently skipped when None:

use apollo_opentelemetry::span;

let user_id: Option<i64> = Some(42);
let _span = span!("request", "user.id" = user_id);

§Automatic span status from Result

Closure and async block forms automatically set the span status based on the return value:

  • Ok(_) → span status set to Ok
  • Err(e) → span status set to Error with the error’s display message
  • Any other type → span status unchanged
use apollo_opentelemetry::span;

fn process() -> Result<(), String> {
    span!("process", || {
        do_work()?;
        Ok(())
    })
}

§Custom Instrumentation Scope

Use scope: to override the instrumentation scope (library name and version reported in telemetry). If omitted, the calling crate’s scope is used.

use apollo_opentelemetry::span;
use opentelemetry::InstrumentationScope;

let _span = span!("my-operation", scope: my_scope());

§Explicit Parent Context

Use parent: to create a span with a specific parent context:

use apollo_opentelemetry::span;
use opentelemetry::Context;
use opentelemetry::trace::TraceContextExt;

span!("child", parent: parent_cx, || {
    // This span's parent comes from parent_cx
});

Creates a new span using OpenTelemetry.

See apollo_opentelemetry::span! for full documentation.