Control which traces are recorded and exported in OpenTelemetry Rust with built-in and custom samplers
Sampling is a mechanism to control the noise and overhead introduced by OpenTelemetry by reducing the number of traces collected and sent to the backend.
From opentelemetry-sdk/src/trace/sampler.rs:22-33:
pub enum SamplingDecision { /// Span will not be recorded and all events and attributes will be dropped. Drop, /// Span data will be recorded, but not exported. RecordOnly, /// Span data will be recorded and exported. RecordAndSample,}
pub struct SamplingResult { /// The decision about whether or not to sample pub decision: SamplingDecision, /// Extra attributes to be added to the span by the sampler pub attributes: Vec<KeyValue>, /// Trace state from parent context, may be modified by samplers pub trace_state: TraceState,}
OpenTelemetry SDK provides several built-in samplers defined in opentelemetry-sdk/src/trace/sampler.rs:142-167:
pub enum Sampler { /// Always sample the trace AlwaysOn, /// Never sample the trace AlwaysOff, /// Respects the parent span's sampling decision or delegates to a sampler for root spans ParentBased(Box<dyn ShouldSample>), /// Sample a given fraction of traces (0.0 to 1.0) TraceIdRatioBased(f64), /// Jaeger remote sampler (requires feature flag) #[cfg(feature = "jaeger_remote_sampler")] JaegerRemote(JaegerRemoteSampler),}
Configure sampling via environment variables (from opentelemetry-sdk/src/trace/config.rs:60-100):
# Always sampleexport OTEL_TRACES_SAMPLER=always_on# Never sampleexport OTEL_TRACES_SAMPLER=always_off# Sample 50% of tracesexport OTEL_TRACES_SAMPLER=traceidratioexport OTEL_TRACES_SAMPLER_ARG=0.5# Parent-based with AlwaysOn delegateexport OTEL_TRACES_SAMPLER=parentbased_always_on# Parent-based with ratio delegateexport OTEL_TRACES_SAMPLER=parentbased_traceidratioexport OTEL_TRACES_SAMPLER_ARG=0.1
use opentelemetry::global;use opentelemetry_sdk::trace::{SdkTracerProvider, Sampler};use opentelemetry_sdk::Resource;use opentelemetry_otlp::SpanExporter;#[tokio::main]async fn main() -> Result<(), Box<dyn std::error::Error>> { // Configure a parent-based sampler with 10% ratio for root spans let sampler = Sampler::ParentBased( Box::new(Sampler::TraceIdRatioBased(0.1)) ); let exporter = SpanExporter::builder() .with_tonic() .build()?; let provider = SdkTracerProvider::builder() .with_resource(Resource::builder() .with_service_name("my-service") .build()) .with_sampler(sampler) .with_batch_exporter(exporter) .build(); global::set_tracer_provider(provider.clone()); // Your application code here // Only ~10% of root traces will be sampled provider.shutdown()?; Ok(())}