> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/open-telemetry/opentelemetry-rust/llms.txt
> Use this file to discover all available pages before exploring further.

# Tracers

> Create and configure tracers to generate spans in your Rust applications

The `Tracer` trait is the interface for constructing spans. Tracers are responsible for creating new spans and managing the active span context.

## Tracer Interface

The core `Tracer` trait is defined in `opentelemetry/src/trace/tracer.rs:121`:

```rust theme={null}
pub trait Tracer {
    type Span: Span;

    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 build_with_context(&self, builder: SpanBuilder, parent_cx: &Context) -> Self::Span;
}
```

## Getting a Tracer

### Using the Global TracerProvider

The simplest way to get a tracer is through the global provider:

```rust theme={null}
use opentelemetry::global;

// Get a tracer with just a name
let tracer = global::tracer("my-component");

// Get a tracer with version
let tracer = global::tracer_with_version(
    "my-component",
    env!("CARGO_PKG_VERSION")
);
```

### Using InstrumentationScope

For library instrumentation, use `InstrumentationScope` to provide version and schema information:

```rust theme={null}
use opentelemetry::{global, InstrumentationScope};

let scope = InstrumentationScope::builder("my-library")
    .with_version(env!("CARGO_PKG_VERSION"))
    .with_schema_url("https://opentelemetry.io/schemas/1.17.0")
    .build();

let tracer = global::tracer_provider().tracer_with_scope(scope);
```

## Creating Spans

### Simple Span Creation

The `start` method creates a span with the current context as its parent:

```rust theme={null}
use opentelemetry::trace::{Tracer, Span};

let tracer = global::tracer("my-component");
let mut span = tracer.start("operation_name");

// Do work...

span.end();
```

### Explicit Parent Context

Use `start_with_context` to specify the parent context:

```rust theme={null}
use opentelemetry::{Context, trace::{Tracer, TraceContextExt}};

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

// Create a parent span
let parent = tracer.start("parent");
let parent_cx = Context::current_with_span(parent);

// Create a child span
let child = tracer.start_with_context("child", &parent_cx);
```

### Using SpanBuilder

For advanced span configuration, use `SpanBuilder`:

```rust theme={null}
use opentelemetry::trace::{Tracer, SpanKind};
use opentelemetry::KeyValue;

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

let span = tracer
    .span_builder("http_request")
    .with_kind(SpanKind::Client)
    .with_attributes(vec![
        KeyValue::new("http.method", "GET"),
        KeyValue::new("http.url", "https://example.com"),
    ])
    .start(&tracer);
```

## Active Span Management

### Using `in_span`

The `in_span` method automatically manages span activation and cleanup:

```rust theme={null}
use opentelemetry::{global, trace::Tracer};

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

tracer.in_span("operation", |cx| {
    // Span is active within this closure
    // Span ends automatically when closure returns

    // Nested spans work automatically
    tracer.in_span("sub_operation", |_cx| {
        // This is a child span
    });
});
```

### Manual Span Activation

For more control, manually activate spans:

```rust theme={null}
use opentelemetry::trace::{Tracer, Span, mark_span_as_active};

let tracer = global::tracer("my-component");
let span = tracer.start("operation");

// Mark as active and get a guard
let _guard = mark_span_as_active(span);

// Span is active until guard is dropped
```

### Accessing the Active Span

Get a reference to the currently active span:

```rust theme={null}
use opentelemetry::trace::{get_active_span, Tracer};
use opentelemetry::KeyValue;

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

tracer.in_span("parent", |_cx| {
    // Access active span from anywhere
    get_active_span(|span| {
        span.add_event(
            "Something happened",
            vec![KeyValue::new("detail", "important")]
        );
    });
});
```

## Advanced Configuration with SpanBuilder

The `SpanBuilder` struct (defined in `opentelemetry/src/trace/tracer.rs:356`) provides full control over span creation:

```rust theme={null}
pub struct SpanBuilder {
    pub span_kind: Option<SpanKind>,
    pub name: Cow<'static, str>,
    pub start_time: Option<SystemTime>,
    pub attributes: Option<Vec<KeyValue>>,
    pub events: Option<Vec<Event>>,
    pub links: Option<Vec<Link>>,
}
```

### Builder Methods

```rust theme={null}
use opentelemetry::trace::{Tracer, SpanKind, Link};
use opentelemetry::KeyValue;
use std::time::SystemTime;

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

let span = tracer
    .span_builder("complex_operation")
    .with_kind(SpanKind::Server)
    .with_start_time(SystemTime::now())
    .with_attributes(vec![
        KeyValue::new("service.name", "my-service"),
        KeyValue::new("environment", "production"),
    ])
    .with_links(vec![
        // Link to another span context
    ])
    .start(&tracer);
```

## Working with Context

### Creating Context with Spans

```rust theme={null}
use opentelemetry::{Context, trace::{Tracer, TraceContextExt}};

let tracer = global::tracer("my-component");
let span = tracer.start("operation");

// Create a context containing this span
let cx = Context::current_with_span(span);

// Use this context to create child spans
let child = tracer.start_with_context("child", &cx);
```

### Using Contexts with `in_span`

```rust theme={null}
use opentelemetry::trace::{Tracer, SpanKind};

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

// Use in_span_with_builder for full control
tracer.in_span_with_builder(
    tracer.span_builder("http_request")
        .with_kind(SpanKind::Client),
    |cx| {
        // Span is active here
        let span = cx.span();
        span.set_attribute(KeyValue::new("key", "value"));
    }
);
```

## Async/Await Support

<Warning>
  The standard span activation methods do not work correctly with async/await. Use `FutureExt` instead.
</Warning>

### Correct Async Pattern

```rust theme={null}
use opentelemetry::{Context, trace::FutureExt};

let cx = Context::current();

let my_future = async {
    // Async work here
};

// Attach context to the future
my_future.with_context(cx).await;
```

### Why Guards Don't Work in Async

From `opentelemetry/src/trace/tracer.rs:79-95`:

```rust theme={null}
// This will NOT work correctly:
async {
    let _g = mark_span_as_active(span);
    // The guard stays active for the entire future lifetime,
    // not just when it's being polled!
};
```

The context guard `_g` will not exit until the future completes. Since futures can be entered and exited multiple times without completing, the span remains active for as long as the future exists, leading to incorrect traces.

## Real-World Example

Here's a complete example from `examples/tracing-grpc/src/client.rs:41-84`:

```rust theme={null}
use opentelemetry::{global, trace::{Tracer, SpanKind, TraceContextExt}, KeyValue};

async fn greet() -> Result<(), Box<dyn std::error::Error>> {
    let tracer = global::tracer("example/client");

    let span = tracer
        .span_builder("Greeter/client")
        .with_kind(SpanKind::Client)
        .with_attributes([
            KeyValue::new("rpc.system", "grpc"),
            KeyValue::new("server.port", 50052),
            KeyValue::new("rpc.method", "say_hello"),
        ])
        .start(&tracer);

    let cx = Context::current_with_span(span);

    // Make gRPC call...

    let span = cx.span();
    span.add_event(
        "Got response!",
        vec![KeyValue::new("status", "OK")]
    );

    Ok(())
}
```

## Best Practices

<AccordionGroup>
  <Accordion title="Use meaningful span names">
    Span names should be general enough to group similar operations but specific enough to be useful. Use `get_user` instead of `get_user/314159`.
  </Accordion>

  <Accordion title="Prefer in_span over manual management">
    The `in_span` method handles activation and cleanup automatically, reducing the risk of leaking spans or incorrect parent relationships.
  </Accordion>

  <Accordion title="Include version information">
    Always provide version information when instrumenting libraries to help with debugging and understanding trace data.
  </Accordion>

  <Accordion title="Set appropriate SpanKind">
    Use the correct `SpanKind` (Client, Server, Internal, Producer, Consumer) to help tracing backends understand the relationships between spans.
  </Accordion>
</AccordionGroup>

## Next Steps

<CardGroup cols={2}>
  <Card title="Spans" icon="cube" href="/traces/spans">
    Learn about span lifecycle, attributes, and events
  </Card>

  <Card title="Context" icon="arrow-right-arrow-left" href="/traces/context">
    Understand context propagation
  </Card>
</CardGroup>
