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

# opentelemetry-http

> HTTP utilities for context propagation and telemetry export

# opentelemetry-http

**Version:** 0.31.0

The `opentelemetry-http` crate provides HTTP-related utilities for OpenTelemetry, including context propagation helpers and HTTP client abstractions for exporting telemetry.

## Installation

```toml theme={null}
[dependencies]
opentelemetry-http = "0.31"
```

### Feature Flags

**HTTP Client Implementations:**

* `reqwest`: Async reqwest client
* `reqwest-blocking`: Blocking reqwest client
* `reqwest-rustls`: Reqwest with rustls TLS
* `reqwest-rustls-webpki-roots`: Reqwest with webpki trust roots
* `hyper`: Hyper client

**Other:**

* `internal-logs`: Enable internal logging (enabled by default)

## Context Propagation

### Injecting Context into HTTP Requests

<ParamField path="HeaderInjector" type="struct">
  Helper for injecting OpenTelemetry context into HTTP headers
</ParamField>

```rust theme={null}
use opentelemetry::{global, Context};
use opentelemetry_http::HeaderInjector;
use http::HeaderMap;

let mut headers = HeaderMap::new();
let cx = Context::current();

global::get_text_map_propagator(|propagator| {
    propagator.inject_context(&cx, &mut HeaderInjector(&mut headers));
});

// headers now contains propagated context (e.g., traceparent, tracestate)
```

### Extracting Context from HTTP Requests

<ParamField path="HeaderExtractor" type="struct">
  Helper for extracting OpenTelemetry context from HTTP headers
</ParamField>

```rust theme={null}
use opentelemetry::global;
use opentelemetry_http::HeaderExtractor;
use http::HeaderMap;

let headers: HeaderMap = /* incoming request headers */;

let parent_cx = global::get_text_map_propagator(|propagator| {
    propagator.extract(&HeaderExtractor(&headers))
});

// Use parent_cx as parent context for new spans
```

## HTTP Client Trait

<ParamField path="HttpClient" type="trait">
  Minimal interface for sending HTTP requests. Used by exporters to send telemetry data.
</ParamField>

```rust theme={null}
use opentelemetry_http::{HttpClient, HttpError};
use async_trait::async_trait;
use http::{Request, Response};
use bytes::Bytes;

#[derive(Debug)]
struct MyHttpClient;

#[async_trait]
impl HttpClient for MyHttpClient {
    async fn send_bytes(&self, request: Request<Bytes>) 
        -> Result<Response<Bytes>, HttpError> {
        // Your HTTP client implementation
        todo!()
    }
}
```

## Built-in HTTP Clients

### Reqwest Client (Async)

```toml theme={null}
[dependencies]
opentelemetry-http = { version = "0.31", features = ["reqwest"] }
reqwest = "0.12"
```

```rust theme={null}
use opentelemetry_http::HttpClient;

let client = reqwest::Client::new();
// client implements HttpClient trait
```

### Reqwest Blocking Client

```toml theme={null}
[dependencies]
opentelemetry-http = { version = "0.31", features = ["reqwest-blocking"] }
reqwest = { version = "0.12", features = ["blocking"] }
```

```rust theme={null}
use opentelemetry_http::HttpClient;

let client = reqwest::blocking::Client::new();
// client implements HttpClient trait
```

### Hyper Client

```toml theme={null}
[dependencies]
opentelemetry-http = { version = "0.31", features = ["hyper"] }
hyper = "1.0"
tokio = { version = "1.0", features = ["full"] }
```

```rust theme={null}
use opentelemetry_http::hyper::HyperClient;
use std::time::Duration;

let client = HyperClient::with_default_connector(
    Duration::from_secs(10), // timeout
    None, // optional authorization header
);
```

## Complete Example

### Context Propagation in HTTP Server

```rust theme={null}
use opentelemetry::{global, trace::{Tracer, TraceContextExt}};
use opentelemetry_http::{HeaderExtractor, HeaderInjector};
use http::{Request, Response, HeaderMap};

fn handle_request(req: Request<Vec<u8>>) -> Response<Vec<u8>> {
    // Extract parent context from incoming headers
    let parent_cx = global::get_text_map_propagator(|propagator| {
        propagator.extract(&HeaderExtractor(req.headers()))
    });

    let tracer = global::tracer("http-server");
    
    // Start span with extracted parent context
    let span = tracer
        .span_builder("handle_request")
        .start_with_context(&tracer, &parent_cx);
    let cx = parent_cx.with_span(span);

    // Do work...

    // If making downstream request, inject context
    let mut headers = HeaderMap::new();
    global::get_text_map_propagator(|propagator| {
        propagator.inject_context(&cx, &mut HeaderInjector(&mut headers));
    });

    Response::new(vec![])
}
```

### Using Custom HTTP Client with Exporter

```rust theme={null}
use opentelemetry_http::{HttpClient, HttpError};
use opentelemetry_otlp::SpanExporter;
use async_trait::async_trait;
use http::{Request, Response};
use bytes::Bytes;

#[derive(Debug)]
struct CustomClient {
    // Your client implementation
}

#[async_trait]
impl HttpClient for CustomClient {
    async fn send_bytes(&self, request: Request<Bytes>) 
        -> Result<Response<Bytes>, HttpError> {
        // Custom HTTP logic
        todo!()
    }
}

let exporter = SpanExporter::builder()
    .with_http_client(CustomClient { /* ... */ })
    .build()?;
```

## Response Extension Trait

<ParamField path="ResponseExt" type="trait">
  Extension methods for `http::Response`
</ParamField>

```rust theme={null}
use opentelemetry_http::ResponseExt;
use http::Response;

let response: Response<Vec<u8>> = /* ... */;

// Convert 4xx/5xx responses to errors
let response = response.error_for_status()?;
```

## Types

<ParamField path="HttpError" type="type">
  Type alias for boxed error: `Box<dyn std::error::Error + Send + Sync + 'static>`
</ParamField>

<ParamField path="Bytes" type="re-export">
  Re-exported from `bytes` crate for convenience
</ParamField>

<ParamField path="Request" type="re-export">
  Re-exported from `http` crate: `http::Request`
</ParamField>

<ParamField path="Response" type="re-export">
  Re-exported from `http` crate: `http::Response`
</ParamField>

## Use Cases

<CardGroup cols={2}>
  <Card title="Distributed Tracing" icon="network-wired">
    Propagate trace context across HTTP service boundaries
  </Card>

  <Card title="Custom Exporters" icon="file-export">
    Implement custom HTTP-based telemetry exporters
  </Card>

  <Card title="Client Selection" icon="square-check">
    Choose HTTP client based on async runtime and performance needs
  </Card>

  <Card title="Testing" icon="flask">
    Mock HTTP client for testing exporters
  </Card>
</CardGroup>

## Example: Propagation in Web Framework

### With Axum

```rust theme={null}
use axum::{extract::Request, middleware::Next, response::Response};
use opentelemetry::{global, trace::{Tracer, TraceContextExt}};
use opentelemetry_http::HeaderExtractor;

async fn trace_middleware(req: Request, next: Next) -> Response {
    let parent_cx = global::get_text_map_propagator(|propagator| {
        propagator.extract(&HeaderExtractor(req.headers()))
    });

    let tracer = global::tracer("axum-server");
    let span = tracer
        .span_builder(format!("{} {}", req.method(), req.uri().path()))
        .start_with_context(&tracer, &parent_cx);
    
    let cx = parent_cx.with_span(span);
    let _guard = cx.attach();

    next.run(req).await
}
```

## Related Crates

* **[opentelemetry](/api/opentelemetry)** - Core API with propagation traits
* **[opentelemetry-otlp](/api/opentelemetry-otlp)** - OTLP exporter using `HttpClient`
* **[opentelemetry-zipkin](/api/opentelemetry-zipkin)** - Zipkin exporter using `HttpClient`
* **[http](https://crates.io/crates/http)** - HTTP types
* **[reqwest](https://crates.io/crates/reqwest)** - HTTP client

## Documentation

<Card title="Full API Documentation" icon="book" href="https://docs.rs/opentelemetry-http/0.31.0">
  View complete API reference on docs.rs
</Card>

<Card title="Context Propagation Example" icon="code" href="https://github.com/open-telemetry/opentelemetry-rust/tree/main/examples/tracing-http-propagator">
  Full working example on GitHub
</Card>

## Minimum Rust Version

**MSRV:** 1.75.0
