Use attach() to make a context active for the current thread:
use opentelemetry::Context;#[derive(Debug, PartialEq)]struct UserId(u64);let ctx = Context::new().with_value(UserId(123));// Attach the contextlet _guard = ctx.attach();// Now it's accessible via Context::current()assert_eq!(Context::current().get::<UserId>(), Some(&UserId(123)));// The guard automatically restores the previous context when dropped
You must assign the guard to a variable (not _) or Rust will drop it immediately, restoring the previous context.
// ❌ Wrong - guard is immediately droppedContext::new().with_value(UserId(123)).attach();// ✅ Correct - guard lives for the scopelet _guard = Context::new().with_value(UserId(123)).attach();
use opentelemetry::{global, trace::{Tracer, TraceContextExt}, Context};let tracer = global::tracer("my_service");let span = tracer.start("operation");// Create context with the spanlet ctx = Context::current_with_span(span);// Access the span from contextctx.span().set_attribute(KeyValue::new("key", "value"));
For async code, use FutureExt to propagate context across .await points:
use opentelemetry::{Context, trace::FutureExt};async fn fetch_data() -> String { // This operation can access the context tokio::time::sleep(std::time::Duration::from_millis(100)).await; "data".to_string()}async fn process_request() { let ctx = Context::new().with_value(UserId(123)); // Propagate context to async operation let result = fetch_data().with_context(ctx.clone()).await; // Context is available throughout the async chain}
use opentelemetry::global;use opentelemetry_sdk::propagation::TraceContextPropagator;// Set the global propagatorglobal::set_text_map_propagator(TraceContextPropagator::new());
When receiving a request, extract the context from headers:
use opentelemetry::{global, trace::{Tracer, SpanKind}};use opentelemetry_http::HeaderExtractor;use hyper::Request;fn handle_request(req: Request<Body>) { // Extract context from incoming headers let parent_cx = global::get_text_map_propagator(|propagator| { propagator.extract(&HeaderExtractor(req.headers())) }); let tracer = global::tracer("example/server"); // Create a span that continues the trace let span = tracer .span_builder("handle_request") .with_kind(SpanKind::Server) .start_with_context(&tracer, &parent_cx); let cx = parent_cx.with_span(span); // Process the request with the extracted context...}
Baggage allows you to propagate arbitrary key-value pairs across service boundaries. Unlike span attributes, baggage is propagated to all downstream services.
OpenTelemetry components can suppress telemetry generation to prevent infinite loops:
use opentelemetry::Context;// Enter a suppressed scope (used internally by exporters)let _guard = Context::enter_telemetry_suppressed_scope();// Check if telemetry is suppressedif Context::is_current_telemetry_suppressed() { // Skip telemetry generation return;}
This is primarily used by OpenTelemetry SDK components (exporters, processors) to prevent generating telemetry about telemetry operations.