otel-bootstrap
One-call OpenTelemetry bootstrap for Rust services — traces, metrics, and logs over OTLP with sensible defaults.
The standard opentelemetry + opentelemetry-otlp + tracing-subscriber wiring is the same in every service. This crate does it once: call init_telemetry("my-service"), keep the handle alive, and drop it to flush.
Features
- One call to wire it all up — traces, metrics, and logs over OTLP,
tracing-subscriberconfigured, W3C TraceContext + Baggage propagators registered. - gRPC or HTTP/protobuf — select transport via cargo feature.
- Env-var configuration — follows the OpenTelemetry spec (
OTEL_EXPORTER_OTLP_ENDPOINT,OTEL_SERVICE_NAME,OTEL_TRACES_SAMPLER, …). - Builder API — version, environment, sampler, custom meter setup, extra subscriber layers.
- Optional axum middleware —
OtelTraceLayerfor inbound HTTP trace propagation. - Generic
enduser.*span enrichment — implementEnrichSpanon your context type and plug it intoSpanEnricherLayer<T>with no brefwiz dependencies required. - Graceful shutdown — drop
TelemetryHandlesto flush and shut down both providers.
Quick start
[]
= "2"
= { = "1", = ["full"] }
use init_telemetry;
async
For more control, use the builder:
use Telemetry;
let _telemetry = builder
.version
.environment
.init?;
Cargo features
| Feature | Default | Description |
|---|---|---|
grpc |
✅ | OTLP/gRPC transport via tonic |
http |
❌ | OTLP/HTTP-protobuf transport via reqwest |
axum |
❌ | OtelTraceLayer + SpanEnricherLayer<T> for axum servers |
testing |
❌ | In-memory exporters for unit tests |
At least one of grpc or http must be enabled (enforced at compile time).
Configuration
| Variable | Default |
|---|---|
OTEL_EXPORTER_OTLP_ENDPOINT |
http://localhost:4317 (gRPC) / http://localhost:4318 (HTTP) |
OTEL_EXPORTER_OTLP_PROTOCOL |
grpc |
OTEL_EXPORTER_OTLP_TIMEOUT |
10000 ms |
OTEL_SERVICE_NAME |
overridden by the service_name argument |
OTEL_TRACES_SAMPLER |
parentbased_always_on |
OTEL_TRACES_SAMPLER_ARG |
sampler-specific (e.g. ratio for traceidratio) |
Full reference: OTEL_TRACES_SAMPLER values.
Axum middleware
= { = "2", = ["axum"] }
use axum_layer;
let app = new
.route
.layer;
This layer reads the traceparent / tracestate headers, starts a server span, and propagates context to all child spans.
enduser.* span enrichment
= { = "2", = ["axum"] }
Implement EnrichSpan on your context type, then plug it into SpanEnricherLayer:
use ;
use Span;
let app = new
.route
.layer;
Routes with no MyContext extension are silently skipped.
Examples
basic_setup— minimal initshutdown_handling— explicit graceful flushcustom_config— builder API with version, environment, sampleraxum_span_enricher— axum + genericEnrichSpanenrichment
License
MIT — see LICENSE.