#aws-lambda #otlp #open-telemetry #tracing

otlp-stdout-span-exporter

A span exporter that writes OpenTelemetry spans to stdout in OTLP format

10 releases (5 breaking)

0.13.0 Mar 28, 2025
0.11.1 Mar 26, 2025
0.10.1 Mar 4, 2025
0.9.0 Feb 25, 2025
0.1.2 Jan 25, 2025

#509 in Debugging

Download history 204/week @ 2025-01-11 53/week @ 2025-01-18 112/week @ 2025-01-25 17/week @ 2025-02-01 111/week @ 2025-02-08 14/week @ 2025-02-15 111/week @ 2025-02-22 300/week @ 2025-03-01 47/week @ 2025-03-08 136/week @ 2025-03-15 216/week @ 2025-03-22 115/week @ 2025-03-29 29/week @ 2025-04-05

501 downloads per month
Used in lambda-otel-lite

MIT license

62KB
834 lines

Rust OTLP Stdout Span Exporter

A Rust span exporter that writes OpenTelemetry spans to stdout, using a custom serialization format that embeds the spans serialized as OTLP protobuf in the payload field. The message envelope carries some metadata about the spans, such as the service name, the OTLP endpoint, and the HTTP method:

{
  "__otel_otlp_stdout": "0.1.0",
  "source": "my-service",
  "endpoint": "http://localhost:4318/v1/traces",
  "method": "POST",
  "content-type": "application/x-protobuf",
  "content-encoding": "gzip",
  "headers": {
    "custom-header": "value"
  },
  "payload": "<base64-encoded-gzipped-protobuf>",
  "base64": true,
  "level": "DEBUG"
}

Outputting the telemetry data in this format directly to stdout makes the library easily usable in network constrained environments, or in enviroments that are particularly sensitive to the overhead of HTTP connections, such as AWS Lambda.

Part of the serverless-otlp-forwarder project, that implements a forwarder for OTLP telemetry data from serverless environments to OTLP compliant collectors.

Features

  • Uses OTLP Protobuf serialization for efficient encoding
  • Applies GZIP compression with configurable levels
  • Detects service name from environment variables or AWS Lambda function name
  • Supports custom headers via standard OTEL environment variables
  • Supports writing to stdout or named pipe
  • Consistent JSON output format
  • Zero external HTTP dependencies
  • Lightweight and fast

Installation

Run cargo add otlp-stdout-span-exporter to add the crate to your project.

Usage

The recommended way to use this exporter is with the standard OpenTelemetry BatchSpanProcessor, which provides better performance by buffering and exporting spans in batches, or, in conjunction with the lambda-otel-lite crate, with the LambdaSpanProcessor strategy, which is particularly optimized for AWS Lambda.

You can create a simple tracer provider with the default configuration:

use opentelemetry::global;
use opentelemetry::trace::Tracer;
use opentelemetry_sdk::trace::SdkTracerProvider;
use otlp_stdout_span_exporter::OtlpStdoutSpanExporter;

fn init_tracer() -> SdkTracerProvider {
    // Create an exporter that writes to stdout (default)
    let exporter = OtlpStdoutSpanExporter::default();

    // Or create one that writes to a named pipe
    let pipe_exporter = OtlpStdoutSpanExporter::builder()
        .pipe(true)  // Will write to /tmp/otlp-stdout-span-exporter.pipe
        .build();

    let provider = SdkTracerProvider::builder()
        .with_batch_exporter(exporter)
        .build();

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

#[tokio::main]
async fn main() {
    let provider = init_tracer();
    let tracer = global::tracer("example/simple");
    tracer.in_span("parent-operation", |_cx| {
        println!("Doing work...");
        
        // Create nested spans
        tracer.in_span("child-operation", |_cx| {
            println!("Doing more work...");
        });
    });

    if let Err(err) = provider.force_flush() {
        println!("Error flushing provider: {:?}", err);
    }
}

This setup ensures that:

  • Spans are batched together for efficient export
  • Parent-child relationships are preserved
  • System resources are used efficiently
  • Spans are properly flushed on shutdown

Environment Variables

The exporter respects the following environment variables:

  • OTEL_SERVICE_NAME: Service name to use in output, used in the source field
  • AWS_LAMBDA_FUNCTION_NAME: Fallback service name (if OTEL_SERVICE_NAME not set)
  • OTEL_EXPORTER_OTLP_HEADERS: Headers for OTLP export, used in the headers field
  • OTEL_EXPORTER_OTLP_TRACES_HEADERS: Trace-specific headers (takes precedence if conflicting with OTEL_EXPORTER_OTLP_HEADERS)
  • OTLP_STDOUT_SPAN_EXPORTER_COMPRESSION_LEVEL: GZIP compression level (0-9, default: 6)
  • OTLP_STDOUT_SPAN_EXPORTER_LOG_LEVEL: Log level for filtering (debug, info, warn, error)
  • OTLP_STDOUT_SPAN_EXPORTER_OUTPUT_TYPE: Output type ("pipe" or "stdout", default: "stdout")

Configuration

The exporter can be configured in multiple ways, with a strict precedence order:

  1. Environment variables (highest precedence)
  2. Builder methods (medium precedence)
  3. Default values (lowest precedence)

Using Environment Variables

Environment variables always take precedence over any programmatic configuration:

# Set GZIP compression level to 9 (maximum compression)
export OTLP_STDOUT_SPAN_EXPORTER_COMPRESSION_LEVEL=9

# Write to a named pipe instead of stdout
export OTLP_STDOUT_SPAN_EXPORTER_OUTPUT_TYPE=pipe

Using default or builder methods

The exporter provides two main ways to create and configure it:

use otlp_stdout_span_exporter::{OtlpStdoutSpanExporter, LogLevel};

// Create with default options (compression level 6, stdout output)
let default_exporter = OtlpStdoutSpanExporter::default();

// Create with specific compression level
let max_compression_exporter = OtlpStdoutSpanExporter::builder()
    .compression_level(9)
    .build();

// Create with a specific log level
let debug_level_exporter = OtlpStdoutSpanExporter::builder()
    .level(LogLevel::Debug)
    .build();

// Create with pipe output
let pipe_exporter = OtlpStdoutSpanExporter::builder()
    .pipe(true)  // Will write to /tmp/otlp-stdout-span-exporter.pipe
    .build();

// Create with multiple options
let configured_exporter = OtlpStdoutSpanExporter::builder()
    .compression_level(9)
    .level(LogLevel::Error)
    .pipe(true)
    .build();

Note that even when using these constructor parameters, environment variables will still take precedence if they are set.

Default Values

When neither environment variables nor constructor parameters are provided, the following defaults are used:

  • Compression level: 6 (good balance between speed and compression)
  • Service name: "unknown-service" (unless AWS_LAMBDA_FUNCTION_NAME is available)
  • Endpoint: "http://localhost:4318/v1/traces"
  • Output type: stdout
  • Log level: None (no filtering)

Development

  1. Clone the repository:
git clone https://github.com/dev7a/serverless-otlp-forwarder
cd serverless-otlp-forwarder/packages/rust/otlp-stdout-span-exporter
  1. Run tests:
cargo test
  1. Run the example:
cargo run --example hello

License

Apache License 2.0

See Also

Dependencies

~9–17MB
~212K SLoC