Lambda OTel Lite
The lambda-otel-lite crate provides a lightweight, efficient OpenTelemetry implementation specifically designed for AWS Lambda environments. It features a custom span processor and internal extension mechanism that optimizes telemetry collection for Lambda's unique execution model.
By leveraging Lambda's execution lifecycle and providing multiple processing modes, this crate enables efficient telemetry collection with minimal impact on function latency. By default, it uses the otlp-stdout-span-exporter to export spans to stdout for the serverless-otlp-forwarder project.
[!IMPORTANT] This crate is highly experimental and should not be used in production. Contributions are welcome.
Table of Contents
- Requirements
- Features
- Architecture and Modules
- Installation
- Quick Start
- Processing Modes
- Telemetry Configuration
- Event Extractors
- Events
- Environment Variables
- License
- See Also
Requirements
- Rust 1.70+
- AWS Lambda Rust Runtime
- OpenTelemetry packages (automatically included as dependencies)
Features
- Flexible Processing Modes: Support for synchronous, asynchronous, and custom export strategies
- Automatic Resource Detection: Automatic extraction of Lambda environment attributes
- Lambda Extension Integration: Built-in extension for efficient telemetry export
- Efficient Memory Usage: Fixed-size queue to prevent memory growth
- AWS Event Support: Automatic extraction of attributes from common AWS event types
- Structured Event Logging: Bridge traditional logging and OpenTelemetry with structured span events
- Flexible Context Propagation: Support for W3C Trace Context, AWS X-Ray, and custom propagators
Architecture and Modules
-
telemetry: Core initialization and configuration- Main entry point via
init_telemetry - Configures global tracer and span processors
- Returns a
TelemetryCompletionHandlerfor span lifecycle management
- Main entry point via
-
processor: Lambda-optimized span processor- Fixed-size queue implementation
- Multiple processing modes
- Coordinates with extension for async export
-
extension: Lambda Extension implementation- Manages extension lifecycle and registration
- Handles span export coordination
- Implements graceful shutdown
-
resource: Resource attribute management- Automatic Lambda attribute detection
- Environment-based configuration
- Custom attribute support
-
constants: Centralized configuration constants- Environment variable names
- Default values
- Resource attribute keys
- Ensures consistency across the codebase
-
extractors: Event processing- Built-in support for API Gateway and ALB events
- Extensible trait system for custom events
- W3C Trace Context and AWS X-Ray propagation
-
layer: Tower middleware integration- Best for complex services with middleware chains
- Integrates with Tower's service ecosystem
- Standardized instrumentation across services
-
handler: Direct function wrapper- Provides
create_traced_handlerfunction to wrap Lambda handlers - Automatically tracks cold starts using the
faas.cold_startattribute - Extracts and propagates trace context from event carriers
- Manages span lifecycle with automatic status handling for HTTP responses
- Records exceptions in spans with appropriate status codes
- Properly completes telemetry processing on handler completion
- Supports reuse of handler functions with efficient boxing strategy
- Provides
Installation
Add the crate to your project:
Quick Start
use ;
use Body;
use HeaderMap;
use ;
use ;
use KeyValue;
use ;
use HashMap;
use OpenTelemetrySpanExt;
// Business logic function
async
async
// Define the handler function
async
Processing Modes
The crate supports three processing modes for span export:
-
Sync Mode (default):
- Direct, synchronous export in handler thread
- Recommended for:
- low-volume telemetry
- limited resources (memory, cpu)
- when latency is not critical
- Set via
LAMBDA_EXTENSION_SPAN_PROCESSOR_MODE=sync
-
Async Mode:
- Export via Lambda extension using AWS Lambda Extensions API
- Spans are queued and exported after handler completion
- Uses channel-based communication between handler and extension
- Registers specifically for Lambda INVOKE events
- Implements graceful shutdown with SIGTERM handling
- Error handling for:
- Channel communication failures
- Export failures
- Extension registration issues
- Best for production use with high telemetry volume
- Set via
LAMBDA_EXTENSION_SPAN_PROCESSOR_MODE=async
-
Finalize Mode:
- Registers extension with no events
- Maintains SIGTERM handler for graceful shutdown
- Ensures all spans are flushed during shutdown
- Compatible with BatchSpanProcessor for custom export strategies
- Best for specialized export requirements where you need full control
- Set via
LAMBDA_EXTENSION_SPAN_PROCESSOR_MODE=finalize
Async Processing Mode Architecture
The async mode leverages Lambda's extension API to optimize perceived latency by deferring span export until after the response is sent to the user:
sequenceDiagram
participant Lambda Runtime
participant Extension Thread
participant Handler
participant LambdaSpanProcessor
participant OTLPStdoutSpanExporter
Note over Extension Thread: Initialization
Extension Thread->>Lambda Runtime: Register extension (POST /register)
Lambda Runtime-->>Extension Thread: Extension ID
Extension Thread->>Lambda Runtime: Get next event (GET /next)
Note over Handler: Function Invocation
Handler->>LambdaSpanProcessor: Create & queue spans during execution
Note over LambdaSpanProcessor: Spans stored in fixed-size queue
Handler->>Extension Thread: Send completion signal
Note over Handler: Handler returns response
Extension Thread->>LambdaSpanProcessor: Flush spans
LambdaSpanProcessor->>OTLPStdoutSpanExporter: Export batched spans
Extension Thread->>Lambda Runtime: Get next event (GET /next)
Note over Extension Thread: On SIGTERM
Lambda Runtime->>Extension Thread: SHUTDOWN event
Extension Thread->>LambdaSpanProcessor: Force flush remaining spans
LambdaSpanProcessor->>OTLPStdoutSpanExporter: Export remaining spans
The async mode leverages Lambda's extension API to optimize perceived latency by deferring span export until after the response is sent to the user. The diagram above shows the core coordination between components:
- Extension thread registers with the Lambda Runtime and awaits events
- Handler creates and queues spans during execution via LambdaSpanProcessor
- Handler signals completion to the extension thread before returning
- Extension thread processes and exports queued spans after handler completes
- Extension thread returns to waiting for the next event
- On shutdown (SIGTERM), remaining spans are flushed and exported
Telemetry Configuration
The crate provides several ways to configure the open telemetry tracing pipeline, which is a required first step to instrument your lambda function:
Custom configuration with custom resource attributes:
use ;
use KeyValue;
use Resource;
use Error;
async
Custom configuration with custom span processors:
use ;
use SimpleSpanProcessor;
use OtlpStdoutSpanExporter;
use Error;
async
Note that the .with_span_processor method accepts a SpanProcessor trait object, so you can pass in any type that implements the SpanProcessor trait, and can be called multiple times. The order of the processors is the order of the calls to .with_span_processor.
Custom configuration with context propagators:
use ;
use ;
use XrayPropagator;
use Error;
async
By default, the crate combines two propagators: W3C Trace Context (TraceContextPropagator) and the Lambda-specific X-Ray propagator (LambdaXrayPropagator), providing out-of-the-box support for both industry-standard tracing and AWS-specific tracing. You can add additional propagators using the with_propagator method, or use with_named_propagator with the following options:
"tracecontext": W3C Trace Context propagator"xray": Standard AWS X-Ray propagator"xray-lambda": Enhanced X-Ray propagator with Lambda environment variable support"none": No propagation (disables context propagation)
Multiple propagators are combined into a composite propagator that can handle various trace context formats.
Custom configuration with ID generator:
use ;
use XrayIdGenerator;
use Error;
async
By default, OpenTelemetry uses a random ID generator that creates W3C-compatible trace and span IDs. The with_id_generator method allows you to customize the ID generation strategy. This is particularly useful when integrating with AWS X-Ray, which requires a specific ID format.
To use the X-Ray ID generator, you'll need to add the opentelemetry-aws crate to your dependencies:
[]
= "0.16.0"
The XrayIdGenerator formats trace IDs in a way that's compatible with AWS X-Ray, using a timestamp in the first part of the trace ID. This allows X-Ray to display and organize traces correctly, and enables correlation between OpenTelemetry traces and traces from other services that use X-Ray.
Custom configuration with sampler:
use ;
use Sampler;
use Error;
async
You can configure custom samplers using the with_sampler() method:
You can also implement custom samplers by implementing the ShouldSample trait:
use ;
use ;
use ;
use Error;
async
Using the Tower Layer
You can "wrap" your handler in the OtelTracingLayer using the ServiceBuilder from the tower crate:
use ;
use ;
use ServiceBuilder;
use ApiGatewayV2httpRequest;
use Value;
async
async
Using the handler wrapper function
Or, you can use the create_traced_handler function to wrap your handler:
use ;
use ;
use ApiGatewayV2httpRequest;
use Value;
async
async
Library specific Resource Attributes
The crate adds several resource attributes under the lambda_otel_lite namespace to provide configuration visibility:
lambda_otel_lite.extension.span_processor_mode: Current processing mode (sync,async, orfinalize)lambda_otel_lite.lambda_span_processor.queue_size: Maximum number of spans that can be queuedlambda_otel_lite.otlp_stdout_span_exporter.compression_level: GZIP compression level used for span export
These attributes are automatically added to the resource and can be used to understand the telemetry configuration in your observability backend.
Event Extractors
Event extractors are responsible for extracting span attributes and context from Lambda event and context objects. The crate provides built-in extractors for common Lambda triggers.
Automatic Attributes extraction
The crate automatically sets relevant FAAS attributes based on the Lambda context and event:
-
Resource Attributes (set at initialization):
cloud.provider: "aws"cloud.region: from AWS_REGIONfaas.name: from AWS_LAMBDA_FUNCTION_NAMEfaas.version: from AWS_LAMBDA_FUNCTION_VERSIONfaas.instance: from AWS_LAMBDA_LOG_STREAM_NAMEfaas.max_memory: from AWS_LAMBDA_FUNCTION_MEMORY_SIZEservice.name: from OTEL_SERVICE_NAME (defaults to function name)- Additional attributes from OTEL_RESOURCE_ATTRIBUTES
-
Span Attributes (set per invocation):
faas.cold_start: true on first invocationcloud.account.id: extracted from context's invokedFunctionArnfaas.invocation_id: from awsRequestIdcloud.resource_id: from context's invokedFunctionArn
-
HTTP Attributes (set for API Gateway events):
faas.trigger: "http"http.status_code: from handler responsehttp.route: from routeKey (v2) or resource (v1)http.method: from requestContext (v2) or httpMethod (v1)http.target: from pathhttp.scheme: from protocol
The crate automatically detects API Gateway v1 and v2 events and sets the appropriate HTTP attributes. For HTTP responses, the status code is automatically extracted from the handler's response and set as http.status_code. For 5xx responses, the span status is set to ERROR.
Built-in Extractors
The crate provides built-in support for extracting span attributes from common AWS event types:
- API Gateway REST API (v1)
- API Gateway HTTP API (v2)
- Application Load Balancer (ALB)
Each extractor is designed to handle a specific event type and extract relevant attributes, including trace context propagation from HTTP headers (both W3C Trace Context and AWS X-Ray formats).
Custom Extractors
For other events than the ones directly supported by the crate, you can implement the SpanAttributesExtractor trait for your own event types:
use ;
use ;
use ;
use HashMap;
use Value;
use Value as JsonValue;
// Define a custom event type
// Implement SpanAttributesExtractor for the custom event
async
async
The SpanAttributes object returned by the extractor contains:
attributes: A map of attributes to add to the spancarrier: Optional map containing trace context headers for propagation (supports both W3C and X-Ray formats)span_name: Optional custom name for the span (defaults to handler name)
Handling Standard AWS Lambda Events
For standard AWS Lambda event types provided by the aws-lambda-events crate that don't have built-in extractors, you can create a newtype wrapper and implement the SpanAttributesExtractor trait for it. This approach is necessary due to Rust's orphan rule, which prevents implementing external traits for external types directly.
Here's an example for Kinesis events:
use KinesisEvent;
use ;
use ;
use Value;
use ;
use HashMap;
// Create a newtype wrapper around KinesisEvent
;
// Implement SpanAttributesExtractor for the wrapper
// Handler function that uses the wrapper
async
async
This pattern can be applied to any event type from the aws-lambda-events crate, such as:
- SQS events
- SNS events
- DynamoDB events
- S3 events
- CloudWatch events
- And more
By creating a newtype wrapper, you can add custom span attributes specific to each event type while maintaining type safety and satisfying Rust's orphan rule.
Events
The crate provides a structured event logging system that bridges traditional logging and OpenTelemetry span events. Events are emitted as OpenTelemetry span events on the current span, providing structured, queryable data that integrates seamlessly with your distributed tracing.
Event Features
- Structured Events: Events are emitted as OpenTelemetry span events with structured attributes
- Log Level Filtering: Events respect the configured log level (via
AWS_LAMBDA_LOG_LEVELorLOG_LEVEL) - Generic Attribute Values: Support for strings, integers, booleans, and other types without manual conversion
- Dual API: Both function-based and builder-based APIs for different use cases
- Current Span Integration: Events are automatically attached to the current active span
Basic Usage
The simplest way to record an event is using the function-based API:
use ;
use KeyValue;
// Record a simple event
record_event;
Builder API
For more ergonomic usage, especially when adding attributes individually:
use ;
use KeyValue;
// Builder with individual attributes
event
.level
.message
.attribute
.attribute
.attribute
.attribute
.attribute
.call;
// Builder with batch attributes
event
.level
.message
.add_attributes
.call;
// Mixed usage - individual and batch attributes
event
.level
.message
.attribute
.attribute
.add_attributes
.call;
Event Levels
Events support standard logging levels that determine whether an event should be recorded:
use EventLevel;
// Available levels (in order of precedence)
let _trace = Trace; // Most verbose
let _debug = Debug;
let _info = Info; // Default level
let _warn = Warn;
let _error = Error; // Least verbose, always recorded
Event filtering follows standard logging conventions:
Errorlevel: Only error events are recordedWarnlevel: Warning and error events are recordedInfolevel: Info, warning, and error events are recordedDebuglevel: Debug, info, warning, and error events are recordedTracelevel: All events are recorded
Level Configuration
The event level is controlled by the same environment variables used for internal logging:
AWS_LAMBDA_LOG_LEVEL(primary, Lambda standard)LOG_LEVEL(fallback)
# Set event level to debug
# Or use the fallback
Supported values (case-insensitive): trace, debug, info, warn, error
Complete Example
Here's a comprehensive example showing events in a Lambda function:
use ;
use ;
use ;
use KeyValue;
use json;
async
async
async
Integration with Observability
Events appear as span events in your OpenTelemetry traces, making them queryable alongside your distributed tracing data. This enables powerful observability scenarios:
- Structured Logging: Events provide structured, searchable logs within trace context
- Business Metrics: Track business events with custom attributes for analysis
- Error Correlation: Link errors to specific business contexts and user actions
- Performance Insights: Record timing and performance metrics as part of traces
Events are particularly valuable in Lambda functions where traditional logging can be expensive and hard to correlate across distributed systems.
Environment Variables
The library uses environment variables for configuration, with a clear precedence order:
- Environment variables (highest precedence)
- Constructor parameters
- Default values (lowest precedence)
Processing Configuration
LAMBDA_EXTENSION_SPAN_PROCESSOR_MODE: Controls processing mode"sync"for Sync mode (default)"async"for Async mode"finalize"for Finalize mode
LAMBDA_SPAN_PROCESSOR_QUEUE_SIZE: Maximum spans to queue (default: 2048)
You can also set the processor mode programmatically through the TelemetryConfig:
use ;
use Error;
async
Note that the environment variable LAMBDA_EXTENSION_SPAN_PROCESSOR_MODE will always take precedence over the programmatic setting if both are specified.
Resource Configuration
OTEL_SERVICE_NAME: Service name for spans (falls back toAWS_LAMBDA_FUNCTION_NAME)OTEL_RESOURCE_ATTRIBUTES: Additional resource attributes in format:key=value,key2=value2
Resource attributes from environment variables are only included in the resource when the environment variable is explicitly set. This ensures that the reported resource attributes accurately reflect the actual configuration used.
Export Configuration
OTLP_STDOUT_SPAN_EXPORTER_COMPRESSION_LEVEL: GZIP compression level (0-9, default: 6)
Sampling Configuration
OTEL_TRACES_SAMPLER: Sampler type for OpenTelemetry traces"always_on": Sample all traces (default)"always_off": Sample no traces"trace_id_ratio": Sample based on trace ID ratio"parent_based": Sample based on parent span sampling decision
OTEL_TRACES_SAMPLER_ARG: Sampler argument (e.g., ratio fortrace_id_ratiosampler, default: 1.0)
Logging and Debug
RUST_LOGorAWS_LAMBDA_LOG_LEVEL: Configure log levelsAWS_LAMBDA_LOG_FORMAT: Set to "JSON" for JSON formatted logsLAMBDA_TRACING_ENABLE_FMT_LAYER: Enable console output of spans for debugging (default: false)- Takes precedence over code configuration when set
- Setting to "true" enables console output even if disabled in code
- Setting to "false" disables console output even if enabled in code
- Only accepts exact string values "true" or "false" (case-insensitive)
- Invalid values will log a warning and fall back to code configuration
License
This project is licensed under the MIT License - see the LICENSE file for details.