telemetry-rust
OpenTelemetry instrumentation library for Rust. Provides middleware for Axum and AWS Lambda, instrumentation helpers for outbound HTTP and AWS SDK clients, and utilities for context propagation.
Axum middleware
Requires the axum feature flag.
use INFO;
use ;
async
async
async
HTTP client instrumentation
Reqwest
Requires the reqwest feature flag.
use ReqwestBuilderInstrument;
let response = new
.get
.instrument
.send
.await?;
Hyper legacy client
Requires the hyper-client-legacy feature flag. Wraps a hyper_util::client::legacy::Client once and reuses it across requests.
use Bytes;
use Empty;
use Request;
use TokioExecutor;
use HyperLegacyClientInstrument;
let client = builder
.
.instrument;
let response = client
.request
.await?;
Hyper low-level send
Requires the hyper-http1 or hyper-http2 feature flag. Wraps a per-connection SendRequest.
use Bytes;
use Empty;
use ;
use TokioIo;
use HyperSendRequestInstrument;
use TcpStream;
let stream = connect.await?;
let io = new;
let = handshake.await?;
spawn;
let mut sender = send_request.instrument;
let response = sender
.send_request
.await?;
HTTP/2 follows the same pattern with hyper::client::conn::http2::handshake.
AWS SDK instrumentation
The following AWS services have full first-class support. Each feature flag adds the corresponding AWS SDK crate as a dependency:
- DynamoDB (
aws-dynamodb) - SNS (
aws-sns) - SQS (
aws-sqs) - S3 (
aws-s3) - Firehose (
aws-firehose) - SageMaker Runtime (
aws-sagemaker-runtime) - Secrets Manager (
aws-secretsmanager) - SSM Parameter Store (
aws-ssm) - AppConfig Data (
aws-appconfigdata)
aws-full enables all AWS-related features at once. Prefer enabling only the flags you need to avoid bloating the dependencies tree.
Each per-service feature flag enables the AwsBuilderInstrument trait for that service. Call .instrument() on any fluent builder before .send() — attributes are automatically extracted from both the request and response following OpenTelemetry semantic conventions.
let res = dynamo_client
.get_item
.table_name
.set_key
.instrument
.send
.await;
// Automatically extracts:
// - Request attributes from fluent builder: table name, consistent read, projection expression, etc.
// - Output attributes: consumed capacity, item found status, etc.
S3 GetObject
GetObject requires special handling because the response body is a ByteStream transferred separately from the SDK call. .instrument().send() only covers the API call itself, not the body transfer.
Use .collect() or .stream() to instrument the full operation:
// `.collect()` — loads the full body into memory:
let body = s3_client
.get_object
.bucket
.key
.instrument
.collect
.await?;
// `.stream()` — yields chunks as they arrive:
let mut stream = s3_client
.get_object
.bucket
.key
.instrument
.stream
.await?;
// `.send()` is still available when you need the full `GetObjectOutput`:
let res = s3_client
.get_object
.bucket
.key
.instrument
.send
.await;
let body = res.body.collect.await?; // not instrumented
Paginator streams: AwsStreamInstrument trait
Requires the aws-stream-instrumentation feature flag.
Paginator streams can't use AwsBuilderInstrument directly. Use .build_aws_span() on the fluent builder (available with any per-service feature flag) to extract request attributes automatically, then pass the span builder to .instrument(). Response attributes are not extracted — there is no single response object for a paginated stream.
let query = dynamo_client
.query
.table_name
.index_name
.key_condition_expression
.expression_attribute_values;
// Extracts the same request attributes as `.instrument().send()` would
let span = query.build_aws_span;
let items = query
.into_paginator
.items
.send
.instrument
.
.await?;
AWS Lambda instrumentation
Requires the aws-lambda feature flag.
async
Context Propagation
The following context propagation formats are supported:
tracecontext: W3C Trace Context (default)baggage: W3C Baggageb3: B3 single header (requireszipkinfeature)b3multi: B3 multiple headers (requireszipkinfeature)xray: AWS X-Ray (requiresxrayfeature)
Advanced AWS instrumentation
AwsInstrument trait
Requires the aws-instrumentation feature flag.
Use this when you need explicit control over span attributes — for example, to attach attributes not automatically extracted, or to instrument a service that lacks a per-service feature flag.
Call .instrument(SpanBuilder) on the future returned by .send():
// DynamoDB
let res = dynamo_client
.get_item
.table_name
.index_name
.set_key
.send
.instrument
.await;
// SQS
let res = sqs_client
.send_message
.queue_url
.message_body
.send
.instrument
.await;
// SNS
let res = sns_client
.publish
.topic_arn
.message
.send
.instrument
.await;
// Firehose
let res = firehose_client
.put_record
.delivery_stream_name
.record
.send
.instrument
.await;
// S3
let res = s3_client
.get_object
.bucket
.key
.send
.instrument
.await;
Low-level span API
Requires the aws-span feature flag. Use this for AWS services not listed above, or when you need full manual control over the span lifecycle (e.g. the span must cross an async boundary).
// Dedicated constructor for a supported service
let aws_span = get_item.start;
// Generic constructor for any AWS service
let aws_span = dynamodb.start;
// Explicit parent context
let context = current.context;
let aws_span = get_item.context.start;
// Custom attributes
let aws_span = get_item
.attribute
.attributes
.start;
End the span once the operation completes:
let res = dynamo_client
.get_item
.table_name
.index_name
.set_key
.send
.await;
aws_span.end;
For unsupported services, use the generic AwsSpanBuilder:
let lambda_span = client
.start;
Publishing new version
New version could be published using cargo-release: