> ## 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.

# Zipkin Exporter

> Export distributed traces to Zipkin backends for visualization and analysis

The Zipkin exporter sends OpenTelemetry trace data to Zipkin, a popular distributed tracing system. Use this exporter when you have existing Zipkin infrastructure or need compatibility with Zipkin's trace format.

<Info>
  The Zipkin exporter **only supports traces**. For metrics and logs, use the [OTLP exporter](/exporters/otlp).
</Info>

## Installation

Add the dependency to your `Cargo.toml`:

```toml theme={null}
[dependencies]
opentelemetry = "0.31"
opentelemetry_sdk = { version = "0.31", features = ["trace"] }
opentelemetry-zipkin = "0.31"
```

### Feature Flags

**Default features** (blocking HTTP client):

```toml theme={null}
opentelemetry-zipkin = { version = "0.31", default-features = true }
# Includes: reqwest-blocking-client
```

**Async HTTP client** (recommended for async applications):

```toml theme={null}
opentelemetry-zipkin = { version = "0.31", features = ["reqwest-client"], default-features = false }
```

**With Rustls TLS:**

```toml theme={null}
opentelemetry-zipkin = { version = "0.31", features = ["reqwest-rustls"] }
```

## Quick Start

### 1. Run Zipkin

Start Zipkin using Docker:

```bash theme={null}
docker run -d -p 9411:9411 openzipkin/zipkin
```

Zipkin UI will be available at: `http://localhost:9411`

### 2. Basic Setup

```rust theme={null}
use opentelemetry::global;
use opentelemetry::trace::Tracer;
use opentelemetry_sdk::trace::SdkTracerProvider;
use opentelemetry_sdk::Resource;
use opentelemetry_zipkin::ZipkinExporter;

fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync + 'static>> {
    // Set Zipkin propagator
    global::set_text_map_propagator(opentelemetry_zipkin::Propagator::new());

    // Create Zipkin exporter
    let exporter = ZipkinExporter::builder().build()?;

    // Create tracer provider
    let provider = SdkTracerProvider::builder()
        .with_simple_exporter(exporter)
        .with_resource(
            Resource::builder()
                .with_service_name("my-service")
                .build()
        )
        .build();

    global::set_tracer_provider(provider.clone());

    // Get a tracer and create spans
    let tracer = global::tracer("my-tracer");
    
    tracer.in_span("operation", |_cx| {
        // Your application logic
    });

    // Shutdown to ensure all spans are sent
    provider.shutdown()?;
    Ok(())
}
```

### 3. View Traces

Open `http://localhost:9411` in your browser to view traces in the Zipkin UI.

## Complete Example

Here's a complete example with nested spans and attributes:

```rust theme={null}
use opentelemetry::{
    global,
    trace::{Span, Tracer},
    InstrumentationScope,
    KeyValue,
};
use opentelemetry_sdk::trace::SdkTracerProvider;
use opentelemetry_sdk::Resource;
use opentelemetry_zipkin::ZipkinExporter;
use std::thread;
use std::time::Duration;

fn process_request(tracer: &impl Tracer) {
    let mut span = tracer.start("process_request");
    span.set_attribute(KeyValue::new("request.id", "12345"));
    span.set_attribute(KeyValue::new("user.id", "user_456"));
    
    thread::sleep(Duration::from_millis(10));
    
    span.add_event(
        "Request validated",
        vec![KeyValue::new("validation.time_ms", 5)],
    );
    
    span.end();
}

fn database_query(tracer: &impl Tracer) {
    let mut span = tracer.start("database_query");
    span.set_attribute(KeyValue::new("db.system", "postgresql"));
    span.set_attribute(KeyValue::new("db.statement", "SELECT * FROM users"));
    
    thread::sleep(Duration::from_millis(15));
    span.end();
}

fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync + 'static>> {
    // Set Zipkin propagator for context propagation
    global::set_text_map_propagator(opentelemetry_zipkin::Propagator::new());

    // Create exporter
    let exporter = ZipkinExporter::builder().build()?;

    // Create provider with resource information
    let provider = SdkTracerProvider::builder()
        .with_simple_exporter(exporter)
        .with_resource(
            Resource::builder()
                .with_service_name("zipkin-demo")
                .with_service_version("1.0.0")
                .with_attributes([
                    KeyValue::new("environment", "development"),
                ])
                .build()
        )
        .build();

    global::set_tracer_provider(provider.clone());

    // Create instrumentation scope
    let scope = InstrumentationScope::builder("my-app")
        .with_version(env!("CARGO_PKG_VERSION"))
        .with_attributes([KeyValue::new("scope-key", "scope-value")])
        .build();

    let tracer = global::tracer_with_scope(scope);

    // Create nested spans
    tracer.in_span("main_operation", |_cx| {
        thread::sleep(Duration::from_millis(5));
        
        process_request(&tracer);
        database_query(&tracer);
        
        thread::sleep(Duration::from_millis(5));
    });

    // Ensure all spans are sent
    provider.shutdown()?;
    Ok(())
}
```

## Configuration

### Custom Endpoint

By default, the exporter sends to `http://localhost:9411/api/v2/spans`. Customize the endpoint:

```rust theme={null}
use opentelemetry_zipkin::ZipkinExporter;

let exporter = ZipkinExporter::builder()
    .with_collector_endpoint("https://zipkin.example.com:9411/api/v2/spans")
    .build()?;
```

### Service Name Configuration

Set the service name via Resource:

```rust theme={null}
use opentelemetry_sdk::Resource;

let resource = Resource::builder()
    .with_service_name("my-service")
    .with_service_version("1.2.3")
    .with_service_namespace("production")
    .build();

let provider = SdkTracerProvider::builder()
    .with_simple_exporter(exporter)
    .with_resource(resource)
    .build();
```

### Environment Variables

The exporter supports these environment variables:

* `OTEL_EXPORTER_ZIPKIN_ENDPOINT` - Zipkin collector endpoint
* `OTEL_SERVICE_NAME` - Service name

## Performance Optimization

### Use Batch Exporter

For production applications, use batch processing for better performance:

```rust theme={null}
use opentelemetry_sdk::trace::{BatchSpanProcessor, BatchConfigBuilder};
use opentelemetry_zipkin::ZipkinExporter;

let exporter = ZipkinExporter::builder().build()?;

// Configure batching
let batch_config = BatchConfigBuilder::default()
    .with_max_queue_size(4096)
    .with_max_export_batch_size(512)
    .with_scheduled_delay(std::time::Duration::from_secs(5))
    .with_max_export_timeout(std::time::Duration::from_secs(30))
    .build();

let batch_processor = BatchSpanProcessor::builder(exporter)
    .with_batch_config(batch_config)
    .build();

let provider = SdkTracerProvider::builder()
    .with_span_processor(batch_processor)
    .build();
```

### Async HTTP Client

For async applications, use the non-blocking client:

```toml theme={null}
[dependencies]
opentelemetry-zipkin = { version = "0.31", features = ["reqwest-client"], default-features = false }
```

No code changes needed - the async client is used automatically.

## Context Propagation

Zipkin uses B3 propagation for distributing trace context across service boundaries.

### Set B3 Propagator

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

// Set the Zipkin B3 propagator
global::set_text_map_propagator(Propagator::new());
```

### Injecting Context (Outgoing Requests)

```rust theme={null}
use opentelemetry::global;
use opentelemetry::propagation::Injector;
use std::collections::HashMap;

// Your HTTP headers
let mut headers = HashMap::new();

// Inject trace context into headers
struct HeaderInjector<'a>(&'a mut HashMap<String, String>);

impl<'a> Injector for HeaderInjector<'a> {
    fn set(&mut self, key: &str, value: String) {
        self.0.insert(key.to_string(), value);
    }
}

let cx = opentelemetry::Context::current();
global::get_text_map_propagator(|propagator| {
    propagator.inject_context(&cx, &mut HeaderInjector(&mut headers));
});

// Now headers contains B3 trace context (X-B3-TraceId, X-B3-SpanId, etc.)
```

### Extracting Context (Incoming Requests)

```rust theme={null}
use opentelemetry::global;
use opentelemetry::propagation::Extractor;
use std::collections::HashMap;

struct HeaderExtractor<'a>(&'a HashMap<String, String>);

impl<'a> Extractor for HeaderExtractor<'a> {
    fn get(&self, key: &str) -> Option<&str> {
        self.0.get(key).map(|v| v.as_str())
    }

    fn keys(&self) -> Vec<&str> {
        self.0.keys().map(|k| k.as_str()).collect()
    }
}

let headers: HashMap<String, String> = /* incoming request headers */;
let parent_cx = global::get_text_map_propagator(|propagator| {
    propagator.extract(&HeaderExtractor(&headers))
});

// Use parent_cx when creating spans to maintain trace continuity
```

## Integration Examples

### With Actix-Web

```rust theme={null}
use actix_web::{web, App, HttpServer, HttpResponse};
use opentelemetry::trace::Tracer;
use opentelemetry::global;

async fn index() -> HttpResponse {
    let tracer = global::tracer("actix-web");
    
    tracer.in_span("handle_request", |_cx| {
        // Handler logic
        HttpResponse::Ok().body("Hello, World!")
    })
}

#[actix_web::main]
async fn main() -> std::io::Result<()> {
    // Initialize Zipkin exporter
    let exporter = opentelemetry_zipkin::ZipkinExporter::builder()
        .build()
        .expect("Failed to create exporter");
    
    let provider = opentelemetry_sdk::trace::SdkTracerProvider::builder()
        .with_batch_exporter(exporter)
        .build();
    
    global::set_tracer_provider(provider);

    HttpServer::new(|| {
        App::new()
            .route("/", web::get().to(index))
    })
    .bind("127.0.0.1:8080")?
    .run()
    .await
}
```

### With Tokio

```rust theme={null}
use opentelemetry::trace::Tracer;
use opentelemetry::global;
use tokio::time::{sleep, Duration};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync + 'static>> {
    let exporter = opentelemetry_zipkin::ZipkinExporter::builder().build()?;
    
    let provider = opentelemetry_sdk::trace::SdkTracerProvider::builder()
        .with_batch_exporter(exporter)
        .build();
    
    global::set_tracer_provider(provider.clone());

    let tracer = global::tracer("tokio-app");

    tracer.in_span("async_operation", |_cx| async {
        sleep(Duration::from_millis(100)).await;
        println!("Async work done");
    }).await;

    provider.shutdown()?;
    Ok(())
}
```

## Troubleshooting

### Traces Not Appearing

1. **Verify Zipkin is running:**
   ```bash theme={null}
   curl http://localhost:9411/api/v2/services
   ```

2. **Check endpoint configuration:**
   * Default: `http://localhost:9411/api/v2/spans`
   * Ensure no typos in custom endpoints

3. **Ensure shutdown is called:**
   ```rust theme={null}
   provider.shutdown()?;  // Flushes all pending spans
   ```

### Missing Span Attributes

Attributes must be set before the span ends:

```rust theme={null}
let mut span = tracer.start("operation");
span.set_attribute(KeyValue::new("key", "value"));  // Before end()
span.end();
```

### Context Not Propagating

Ensure the Zipkin propagator is set:

```rust theme={null}
global::set_text_map_propagator(opentelemetry_zipkin::Propagator::new());
```

## When to Use Zipkin Exporter

**Use Zipkin exporter when:**

* You have existing Zipkin infrastructure
* You need B3 propagation compatibility
* You're integrating with Zipkin-native tools
* You're migrating gradually from Zipkin to OpenTelemetry

**Use OTLP exporter when:**

* Starting a new project
* You need metrics and logs in addition to traces
* You want vendor-neutral telemetry
* You need maximum flexibility in backend choice

## Zipkin vs OTLP

| Feature     | Zipkin Exporter | OTLP Exporter                  |
| ----------- | --------------- | ------------------------------ |
| Traces      | ✓               | ✓                              |
| Metrics     | ✗               | ✓                              |
| Logs        | ✗               | ✓                              |
| Protocol    | HTTP/JSON       | gRPC, HTTP/protobuf, HTTP/JSON |
| Maintenance | Active          | Active                         |
| Use Case    | Zipkin backends | Universal                      |

## Next Steps

<CardGroup cols={2}>
  <Card title="OTLP Exporter" icon="arrow-right" href="/exporters/otlp">
    Export all signals with OTLP
  </Card>

  <Card title="Tracing Guide" icon="diagram-project" href="/traces/overview">
    Learn about distributed tracing
  </Card>
</CardGroup>
