Skip to main content

Crate awssdk_instrumentation

Crate awssdk_instrumentation 

Source
Expand description

Out-of-the-box OpenTelemetry/X-Ray instrumentation for the AWS SDK for Rust, with first-class support for AWS Lambda.

This crate wires together three concerns in one place:

  1. SDK interceptors — automatically attach OTel semantic-convention attributes to every AWS SDK call (DynamoDB, S3, SQS, …).
  2. Lambda Tower layer — create a per-invocation span covering the handler, propagate the X-Ray trace context, track cold-starts, and flush the exporter after each invocation.
  3. Environment resource detection — detect whether the process is running on Lambda, ECS, EKS, or EC2 and populate the OTel Resource accordingly.

The default feature set (tracing-backend + env-lambda + extract-dynamodb + export-xray) covers the most common Lambda workload with zero extra configuration.

§Quick Start — Lambda with DynamoDB

The fastest path to a fully instrumented Lambda function:

use awssdk_instrumentation::lambda::{LambdaError, LambdaEvent};
use serde_json::Value;

// 1. Declare the handler.
async fn handler(event: LambdaEvent<Value>) -> Result<Value, LambdaError> {
    // Use dynamodb_client() anywhere in your crate — the interceptor
    // automatically records DynamoDB spans.
    let resp = dynamodb_client().get_item().table_name("orders").send().await?;
    Ok(event.payload)
}

// 2. One macro call generates main(), telemetry init, and the Tower layer.
//    Here you also create a DynamoDB client singleton with the interceptor pre-attached.
awssdk_instrumentation::make_lambda_runtime!(
    handler,
    dynamodb_client() -> aws_sdk_dynamodb::Client
);

With this setup, you only need the following crates as direct dependencies in your Cargo.toml: awssdk-instrumentation, tokio (for the #[tokio::main] attribute generated by the macro), serde_json (for the Value event type), and the aws-sdk-* service crates you actually call.

§Key Concepts

§Backend

Two mutually-exclusive (but co-installable) backends bridge the AWS SDK interceptor and Lambda Tower layer to OpenTelemetry:

  • tracing-backend (default) — the interceptor writes attributes into the active tracing::Span, which is then forwarded to OTel via tracing-opentelemetry. This is the recommended choice: it integrates naturally with the tracing ecosystem and requires no extra setup.
  • otel-backend — the interceptor manages OTel spans directly via the opentelemetry API.

At least one backend must be enabled; the crate will fail to compile otherwise.

The interceptor::DefaultInterceptor type alias always resolves to the right interceptor for the active backend.

§Interceptors

interceptor::DefaultInterceptor implements the AWS SDK Intercept trait. Attach it to any SDK client config to get automatic span attribute extraction:

// Attach the interceptor when building the SDK client config.
// `aws_config` is re-exported by this crate, so you can either depend on
// it directly or reach it via `awssdk_instrumentation::aws_config`.
// The `aws-sdk-*` service crates (e.g. `aws-sdk-dynamodb`) are *not*
// re-exported and must be added to your own `Cargo.toml`.
let sdk_config = aws_config::load_from_env().await;
let dynamo = aws_sdk_dynamodb::Client::from_conf(
    aws_sdk_dynamodb::config::Builder::from(&sdk_config)
        .interceptor(DefaultInterceptor::new())
        .build(),
);

The interceptor::DefaultExtractor inside the interceptor dispatches to per-service extractors (DynamoDB, S3, SQS) and then runs any user-registered hooks or interceptor::AttributeExtractor implementations.

§Lambda support

The lambda module (feature env-lambda) provides:

  • lambda::layer::TracingLayer — a Tower Layer that wraps the Lambda runtime service, creates a span per invocation, and flushes the exporter when the invocation future drops.
  • make_lambda_runtime! — a macro that generates a complete main() function: telemetry init, SDK config/client singletons, Tower layer setup, and lambda_runtime::Runtime::run().

§Resource detection

env::default_resource() probes the environment at startup and returns an OTel Resource populated with the appropriate semantic-convention attributes. It tries Lambda first (if feature env-lambda), then ECS (if feature env-ecs), then EKS (if feature env-eks), then EC2 (if feature env-ec2), and then falls back to a minimal cloud.provider = aws resource.

§Telemetry initialisation

init::default_telemetry_init() is a one-call setup that:

  • Builds a SdkTracerProvider with the detected resource, X-Ray ID generator and a batch X-Ray exporter (when export-xray is enabled).
  • Registers it as the global OTel tracer provider.
  • Installs a tracing-subscriber with a JSON console layer and an OTel bridge layer (when tracing-backend is enabled).

§Manual Setup

When you need more control, wire the pieces together yourself:

use serde_json::Value;
use awssdk_instrumentation::{
    init::default_telemetry_init,
    interceptor::DefaultInterceptor,
    lambda::{LambdaError, LambdaEvent, OTelFaasTrigger, layer::DefaultTracingLayer},
};

// 1. Declare the handler.
async fn handler(event: LambdaEvent<Value>) -> Result<Value, LambdaError> {
    todo!("Do Stuff...");
}

#[tokio::main]
async fn main() -> Result<(), LambdaError> {
// Initialise telemetry (sets global tracer provider + tracing subscriber).
let tracer_provider = default_telemetry_init();

// Build an SDK client with the interceptor attached.
let sdk_config = aws_config::load_from_env().await;
let dynamo = aws_sdk_dynamodb::Client::from_conf(
    aws_sdk_dynamodb::config::Builder::from(&sdk_config)
        .interceptor(DefaultInterceptor::new())
        .build(),
);

// Wrap the Lambda runtime with the Tower layer.
lambda_runtime::Runtime::new(lambda_runtime::service_fn(handler))
    .layer(
        DefaultTracingLayer::new(move || {
            let _ = tracer_provider.force_flush();
        })
        .with_trigger(OTelFaasTrigger::Http),
    )
    .run()
    .await
}

§Feature Flags

Features are grouped by category. Items marked ✅ are enabled by default.

§Backend

FeatureDefaultDescription
tracing-backendWrites span attributes via tracing::Span + tracing-opentelemetry
otel-backendManages OTel spans directly without tracing

§Environment detection

FeatureDefaultDescription
env-lambdaLambda Tower layer, resource detector, make_lambda_runtime!
env-ecsECS resource detector (reads container metadata endpoint)
env-eksEKS resource detector (reads k8s service account + IMDS)
env-ec2EC2 resource detector (reads IMDSv2)

§Service attribute extraction

FeatureDefaultDescription
extract-dynamodbDynamoDB OTel semantic-convention attributes
extract-s3S3 OTel semantic-convention attributes
extract-sqsSQS OTel semantic-convention attributes

§Export

FeatureDefaultDescription
export-xrayX-Ray ID generator, propagator, and daemon exporter via opentelemetry-aws

When export-xray is enabled, the opentelemetry_aws crate is re-exported at the crate root so you can access the X-Ray propagator and exporter types directly.

§Re-exported crates

To minimise the dependencies users need to declare in their own Cargo.toml, this crate re-exports every external crate that appears in its public API. You can reach any of them via awssdk_instrumentation::<crate>.

Always re-exported at the crate root:

Re-exported when feature tracing-backend is enabled (the default):

Re-exported when feature env-lambda is enabled (the default):

Re-exported when feature export-xray is enabled (the default):

  • opentelemetry_aws — for the X-Ray ID generator, propagator, and daemon exporter types.

§Crates you still need to add as direct dependencies

  • The aws-sdk-* service crates you actually use (aws-sdk-dynamodb, aws-sdk-s3, …). These are not re-exported because they are the user’s primary dependencies.
  • tokio — required for the #[tokio::main] attribute generated by make_lambda_runtime!. The tokio proc-macro resolves the crate by its absolute path (::tokio), so re-exporting it would not help. Lambda functions in Rust need tokio anyway.
  • serde_json (or serde) — for typical Lambda event types. Lambda functions almost always need this for event/response (de)serialisation.

Re-exports§

pub use opentelemetry_aws;
pub use tracing;
pub use tracing_opentelemetry;
pub use tracing_subscriber;
pub use aws_config;
pub use aws_smithy_runtime_api;
pub use aws_smithy_types;
pub use opentelemetry;
pub use opentelemetry_sdk;
pub use opentelemetry_semantic_conventions;

Modules§

env
OTel Resource detection for AWS environments.
init
Telemetry initialisation helpers and SDK client convenience macros.
interceptor
AWS SDK interceptor that automatically extracts OTel semantic-convention attributes from SDK calls.
lambda
Lambda support: Tower layer, per-invocation spans, and the make_lambda_runtime! macro (env-lambda feature).
span_write
Backend-agnostic interface for writing attributes and status into a span.

Macros§

aws_sdk_client_provider
Declares a OnceLock-backed AWS SDK client accessor function.
aws_sdk_config_provider
Declares a OnceLock-backed aws_sdk_config() accessor and an async sdk_config_init() initialiser.
make_lambda_runtime
Generates a complete #[tokio::main] async fn main() for a Lambda function.