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.
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.
The Zipkin exporter only supports traces . For metrics and logs, use the OTLP exporter .
Installation
Add the dependency to your Cargo.toml:
[ dependencies ]
opentelemetry = "0.31"
opentelemetry_sdk = { version = "0.31" , features = [ "trace" ] }
opentelemetry-zipkin = "0.31"
Feature Flags
Default features (blocking HTTP client):
opentelemetry-zipkin = { version = "0.31" , default-features = true }
# Includes: reqwest-blocking-client
Async HTTP client (recommended for async applications):
opentelemetry-zipkin = { version = "0.31" , features = [ "reqwest-client" ], default-features = false }
With Rustls TLS:
opentelemetry-zipkin = { version = "0.31" , features = [ "reqwest-rustls" ] }
Quick Start
1. Run Zipkin
Start Zipkin using Docker:
docker run -d -p 9411:9411 openzipkin/zipkin
Zipkin UI will be available at: http://localhost:9411
2. Basic Setup
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:
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:
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:
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
Use Batch Exporter
For production applications, use batch processing for better performance:
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:
[ 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
use opentelemetry :: global;
use opentelemetry_zipkin :: Propagator ;
// Set the Zipkin B3 propagator
global :: set_text_map_propagator ( Propagator :: new ());
Injecting Context (Outgoing Requests)
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.)
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
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
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
Verify Zipkin is running:
curl http://localhost:9411/api/v2/services
Check endpoint configuration:
Default: http://localhost:9411/api/v2/spans
Ensure no typos in custom endpoints
Ensure shutdown is called:
provider . shutdown () ? ; // Flushes all pending spans
Missing Span Attributes
Attributes must be set before the span ends:
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:
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
OTLP Exporter Export all signals with OTLP
Tracing Guide Learn about distributed tracing