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

# OTLP gRPC Exporter

> Export telemetry data via OTLP over gRPC for high-performance observability

## Overview

The OTLP gRPC exporter provides a high-performance alternative to HTTP for sending traces, metrics, and logs. gRPC offers better throughput and lower latency, making it ideal for high-volume production environments.

## Dependencies

Add these dependencies to your `Cargo.toml`:

```toml Cargo.toml theme={null}
[dependencies]
opentelemetry = { version = "*" }
opentelemetry_sdk = { version = "*", features = ["rt-tokio"] }
opentelemetry-otlp = { version = "*", features = ["grpc-tonic"] }
tonic = "0.12"
tokio = { version = "1", features = ["full"] }
```

## Exporting Traces via gRPC

<Steps>
  <Step title="Configure OTLP gRPC Exporter">
    Set up the OTLP exporter with gRPC transport using Tonic.

    ```rust theme={null}
    use opentelemetry::global;
    use opentelemetry_sdk::trace::SdkTracerProvider;
    use opentelemetry_otlp::WithExportConfig;

    fn init_tracer() -> SdkTracerProvider {
        let exporter = opentelemetry_otlp::SpanExporter::builder()
            .with_tonic()
            .with_endpoint("http://localhost:4317")
            .build()
            .expect("Failed to create OTLP gRPC exporter");

        let provider = SdkTracerProvider::builder()
            .with_batch_exporter(exporter, opentelemetry_sdk::runtime::Tokio)
            .build();

        global::set_tracer_provider(provider.clone());
        provider
    }
    ```
  </Step>

  <Step title="Configure TLS and Authentication">
    Add TLS and metadata for secure connections.

    ```rust theme={null}
    use opentelemetry_otlp::WithTonicConfig;
    use tonic::metadata::{MetadataMap, MetadataValue};
    use tonic::transport::ClientTlsConfig;

    let mut metadata = MetadataMap::new();
    metadata.insert(
        "authorization",
        MetadataValue::from_str("Bearer YOUR_API_TOKEN").unwrap(),
    );

    let tls_config = ClientTlsConfig::new()
        .domain_name("your-backend.com");

    let exporter = opentelemetry_otlp::SpanExporter::builder()
        .with_tonic()
        .with_endpoint("https://your-backend.com:4317")
        .with_metadata(metadata)
        .with_tls_config(tls_config)
        .build()
        .expect("Failed to create OTLP gRPC exporter");
    ```
  </Step>

  <Step title="Use the Tracer">
    Create and export spans normally.

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

    #[tokio::main]
    async fn main() -> Result<(), Box<dyn std::error::Error>> {
        let tracer_provider = init_tracer();
        let tracer = global::tracer("my-service");

        let span = tracer
            .span_builder("grpc_operation")
            .with_kind(SpanKind::Internal)
            .start(&tracer);

        // Your application logic

        tracer_provider.shutdown()?;
        Ok(())
    }
    ```
  </Step>
</Steps>

## Exporting Metrics via gRPC

```rust theme={null}
use opentelemetry::global;
use opentelemetry_sdk::metrics::SdkMeterProvider;
use opentelemetry_otlp::WithExportConfig;

fn init_metrics() -> SdkMeterProvider {
    let exporter = opentelemetry_otlp::MetricExporter::builder()
        .with_tonic()
        .with_endpoint("http://localhost:4317")
        .build()
        .expect("Failed to create OTLP metrics exporter");

    let provider = SdkMeterProvider::builder()
        .with_periodic_exporter(exporter, opentelemetry_sdk::runtime::Tokio)
        .build();

    global::set_meter_provider(provider.clone());
    provider
}
```

## Exporting Logs via gRPC

```rust theme={null}
use opentelemetry_sdk::logs::SdkLoggerProvider;
use opentelemetry_appender_tracing::layer::OpenTelemetryTracingBridge;
use tracing_subscriber::prelude::*;

fn init_logs() -> SdkLoggerProvider {
    let exporter = opentelemetry_otlp::LogExporter::builder()
        .with_tonic()
        .with_endpoint("http://localhost:4317")
        .build()
        .expect("Failed to create OTLP log exporter");

    let provider = SdkLoggerProvider::builder()
        .with_batch_exporter(exporter, opentelemetry_sdk::runtime::Tokio)
        .build();

    let otel_layer = OpenTelemetryTracingBridge::new(&provider);
    tracing_subscriber::registry().with(otel_layer).init();

    provider
}
```

## gRPC-Specific Configuration

### Connection Settings

```rust theme={null}
use std::time::Duration;
use tonic::transport::Channel;

let channel = Channel::from_static("http://localhost:4317")
    .timeout(Duration::from_secs(10))
    .connect_timeout(Duration::from_secs(5))
    .tcp_keepalive(Some(Duration::from_secs(60)));

let exporter = opentelemetry_otlp::SpanExporter::builder()
    .with_tonic()
    .with_channel(channel)
    .build()?;
```

### Compression

```rust theme={null}
use tonic::codec::CompressionEncoding;

let exporter = opentelemetry_otlp::SpanExporter::builder()
    .with_tonic()
    .with_endpoint("http://localhost:4317")
    .with_compression(CompressionEncoding::Gzip)
    .build()?;
```

<Tip>
  gRPC compression can significantly reduce network bandwidth usage, especially for high-volume telemetry data.
</Tip>

## HTTP vs gRPC Comparison

| Feature               | HTTP                    | gRPC                      |
| --------------------- | ----------------------- | ------------------------- |
| **Performance**       | Good                    | Excellent                 |
| **Latency**           | Higher                  | Lower                     |
| **Throughput**        | Good                    | Better                    |
| **Ease of Debug**     | Easier (curl, browsers) | Harder (needs gRPC tools) |
| **Firewall Friendly** | More (port 80/443)      | Less (custom ports)       |
| **Compression**       | Optional                | Built-in, efficient       |
| **Streaming**         | No                      | Yes                       |

<Note>
  For most production use cases, gRPC is recommended due to better performance. Use HTTP if you have strict firewall requirements or need easier debugging.
</Note>

## Environment Variables

The OTLP gRPC exporter respects standard OpenTelemetry environment variables:

```bash theme={null}
# Endpoint
export OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4317

# Signal-specific endpoints
export OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=http://localhost:4317
export OTEL_EXPORTER_OTLP_METRICS_ENDPOINT=http://localhost:4317
export OTEL_EXPORTER_OTLP_LOGS_ENDPOINT=http://localhost:4317

# Headers (sent as gRPC metadata)
export OTEL_EXPORTER_OTLP_HEADERS="api-key=secret,x-custom-header=value"

# Protocol (should be 'grpc')
export OTEL_EXPORTER_OTLP_PROTOCOL=grpc

# Timeout (milliseconds)
export OTEL_EXPORTER_OTLP_TIMEOUT=10000
```

## Common Endpoints

### Local OpenTelemetry Collector

```rust theme={null}
// Default gRPC port
.with_endpoint("http://localhost:4317")
```

### Secure Connection

```rust theme={null}
use tonic::transport::ClientTlsConfig;

let tls_config = ClientTlsConfig::new();

let exporter = opentelemetry_otlp::SpanExporter::builder()
    .with_tonic()
    .with_endpoint("https://otel-collector.example.com:4317")
    .with_tls_config(tls_config)
    .build()?;
```

## Complete Example: All Signals

Here's a complete example exporting traces, metrics, and logs via gRPC:

```rust theme={null}
use opentelemetry::global;
use opentelemetry_sdk::{trace::SdkTracerProvider, metrics::SdkMeterProvider, logs::SdkLoggerProvider};
use opentelemetry_otlp::WithExportConfig;
use opentelemetry_appender_tracing::layer::OpenTelemetryTracingBridge;
use tracing_subscriber::prelude::*;

fn init_telemetry() -> (SdkTracerProvider, SdkMeterProvider, SdkLoggerProvider) {
    let endpoint = "http://localhost:4317";

    // Traces
    let trace_exporter = opentelemetry_otlp::SpanExporter::builder()
        .with_tonic()
        .with_endpoint(endpoint)
        .build()
        .expect("Failed to create trace exporter");
    
    let tracer_provider = SdkTracerProvider::builder()
        .with_batch_exporter(trace_exporter, opentelemetry_sdk::runtime::Tokio)
        .build();
    global::set_tracer_provider(tracer_provider.clone());

    // Metrics
    let metric_exporter = opentelemetry_otlp::MetricExporter::builder()
        .with_tonic()
        .with_endpoint(endpoint)
        .build()
        .expect("Failed to create metric exporter");
    
    let meter_provider = SdkMeterProvider::builder()
        .with_periodic_exporter(metric_exporter, opentelemetry_sdk::runtime::Tokio)
        .build();
    global::set_meter_provider(meter_provider.clone());

    // Logs
    let log_exporter = opentelemetry_otlp::LogExporter::builder()
        .with_tonic()
        .with_endpoint(endpoint)
        .build()
        .expect("Failed to create log exporter");
    
    let logger_provider = SdkLoggerProvider::builder()
        .with_batch_exporter(log_exporter, opentelemetry_sdk::runtime::Tokio)
        .build();
    
    let otel_layer = OpenTelemetryTracingBridge::new(&logger_provider);
    tracing_subscriber::registry().with(otel_layer).init();

    (tracer_provider, meter_provider, logger_provider)
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let (tracer_provider, meter_provider, logger_provider) = init_telemetry();

    // Use telemetry in your application

    // Shutdown all providers
    tracer_provider.shutdown()?;
    meter_provider.shutdown()?;
    logger_provider.shutdown()?;
    
    Ok(())
}
```

<Tip>
  Always shutdown all providers in the correct order (traces, metrics, logs) to ensure all telemetry data is flushed before the application exits.
</Tip>
