AWS
autotel-aws provides ergonomic, vendor-agnostic OpenTelemetry instrumentation for AWS services.
Installation
Section titled “Installation”npm install autotel-aws autotelLambda Handler
Section titled “Lambda Handler”import { init } from 'autotel';import { wrapHandler } from 'autotel-aws/lambda';
init({ service: 'my-lambda', endpoint: process.env.OTEL_EXPORTER_OTLP_ENDPOINT,});
export const handler = wrapHandler(async (event, context) => { return { statusCode: 200 };});Zero-Config
Section titled “Zero-Config”import 'autotel-aws/lambda/auto'; // Must be FIRST import
export const handler = async (event, context) => { return { statusCode: 200 };};AWS SDK Auto-Instrumentation
Section titled “AWS SDK Auto-Instrumentation”import { autoInstrumentAWS } from 'autotel-aws/sdk';
autoInstrumentAWS(); // All SDK clients are automatically traced
const s3 = new S3Client({ region: 'us-east-1' });const dynamodb = new DynamoDBClient({ region: 'us-east-1' });Per-Client
Section titled “Per-Client”import { instrumentSDK, createTracedClient } from 'autotel-aws/sdk';import { S3Client } from '@aws-sdk/client-s3';
// Wrap existing clientconst s3 = instrumentSDK(new S3Client({ region: 'us-east-1' }));
// Or create pre-instrumentedconst s3 = createTracedClient(S3Client, { region: 'us-east-1' });SQS Producer/Consumer
Section titled “SQS Producer/Consumer”import { SQSProducer, SQSConsumer } from 'autotel-aws/sqs';
const producer = new SQSProducer(sqs, { queueUrl: 'https://sqs.us-east-1.amazonaws.com/123456/events',});
await producer.send({ body: JSON.stringify({ type: 'order.created', orderId: '123' }),});
const consumer = new SQSConsumer(sqs, { queueUrl: 'https://sqs.us-east-1.amazonaws.com/123456/events', handleMessage: async (message) => { // Trace context automatically extracted from message console.log('Received:', message.body); },});CloudWatch native OTLP
Section titled “CloudWatch native OTLP”As of late 2025 / early 2026, CloudWatch accepts OTLP/HTTP directly. No collector required for low-volume workloads.
| Signal | Endpoint | Lands in |
| ------- | ------------------------------------------------------------ | ------------------------------------------------------- |
| Traces | https://xray.<region>.amazonaws.com/v1/traces | X-Ray + Application Signals + Transaction Search |
| Logs | https://logs.<region>.amazonaws.com/v1/logs | CloudWatch Logs (Logs Insights / LiveTail) |
| Metrics | https://monitoring.<region>.amazonaws.com/v1/metrics | CloudWatch Metrics (PromQL-queryable) |
autotel-aws/cloudwatch ships SigV4-signing OTLP/JSON exporters that hit these endpoints directly — no sidecar, no extra layer.
Install peer dependencies
Section titled “Install peer dependencies”pnpm add autotel-aws autotel \ @smithy/signature-v4 @aws-crypto/sha256-js \ @aws-sdk/credential-providers \ @opentelemetry/sdk-trace-base \ @opentelemetry/sdk-logs \ @opentelemetry/sdk-metrics \ @opentelemetry/otlp-transformerDrop the signal-specific peers you don't use (e.g. omit sdk-logs if you only export traces).
Traces
Section titled “Traces”import { init } from 'autotel';import { BatchSpanProcessor } from '@opentelemetry/sdk-trace-base';import { CloudWatchTraceExporter } from 'autotel-aws/cloudwatch';
init({ service: 'my-service', spanProcessors: [ new BatchSpanProcessor( new CloudWatchTraceExporter({ region: 'eu-west-1' }), ), ],});In Lambda, force-flush before the handler returns (or use SimpleSpanProcessor) — the runtime freezes the process before the batch ships.
The exporter reads AWS_LAMBDA_LOG_GROUP_NAME / AWS_LAMBDA_LOG_STREAM_NAME by default (set automatically by the Lambda runtime).
import { BatchLogRecordProcessor, LoggerProvider } from '@opentelemetry/sdk-logs';import { CloudWatchLogExporter } from 'autotel-aws/cloudwatch';
const provider = new LoggerProvider({ processors: [new BatchLogRecordProcessor(new CloudWatchLogExporter())],});Metrics
Section titled “Metrics”import { MeterProvider, PeriodicExportingMetricReader } from '@opentelemetry/sdk-metrics';import { CloudWatchMetricExporter } from 'autotel-aws/cloudwatch';
const provider = new MeterProvider({ readers: [ new PeriodicExportingMetricReader({ exporter: new CloudWatchMetricExporter({ region: 'eu-west-1' }), exportIntervalMillis: 60_000, }), ],});Direct vs ADOT collector layer
Section titled “Direct vs ADOT collector layer”| | In-process (autotel-aws/cloudwatch) | ADOT Lambda extension layer |
| ---------------- | ------------------------------------- | --------------------------------- |
| Sidecar | None | Yes (extension layer) |
| Export latency | In the billed handler time | Outside billed time |
| Cold start cost | Bundle size + SigV4 init | Layer init |
| Best for | Low/medium volume Lambdas | Higher-throughput functions |
Pick one — running both ships duplicate spans.
ADOT collector config (SigV4)
Section titled “ADOT collector config (SigV4)”When using OTEL_MODE=cloudwatch-adot, configure the ADOT collector with sigv4auth so OTLP is signed before forwarding:
extensions: sigv4auth: region: us-west-2 service: xray
receivers: otlp: protocols: http:
exporters: otlphttp/traces: endpoint: https://xray.us-west-2.amazonaws.com/v1/traces auth: authenticator: sigv4auth
service: extensions: [sigv4auth] pipelines: traces: receivers: [otlp] exporters: [otlphttp/traces]For logs/metrics, use the same pattern with endpoint + service pairs:
- logs:
https://logs.<region>.amazonaws.com/v1/logs, servicelogs - metrics:
https://monitoring.<region>.amazonaws.com/v1/metrics, servicemonitoring
Production checklist
Section titled “Production checklist”- Set region explicitly (
AWS_REGION) and match it to the endpoint region. - Ensure IAM policy allows writes to X-Ray, CloudWatch Logs, and CloudWatch Metrics as needed.
- For logs endpoint, make sure target log group + stream exist, or use Lambda-provided env defaults.
- In Lambda, flush spans/logs/metrics before return (or use ADOT mode) to avoid frozen-runtime drops.
- Monitor 4xx/429 responses and tune export interval/batch size for quota limits.
- Prefer one export path per signal (direct or ADOT), not both, to avoid duplicates.
- Keep payload size under endpoint limits and use gzip where appropriate.
- Validate clocks (NTP) to avoid timestamp-window rejections.
Payload format note
Section titled “Payload format note”autotel-aws/cloudwatch currently sends OTLP over HTTP using JSON payloads. CloudWatch endpoints also accept protobuf payloads, but protobuf transport is not currently wired in these exporters.
Endpoint limits
Section titled “Endpoint limits”- Traces: 5 MB / request, 10 000 spans / batch, 200 KB / span, timestamps must be within
[-14d, +2h]. - Logs: 1 MB / request (20 MB in some regions for Large Log Objects). 1 MB / log event before truncation.
- Metrics: 500 TPS / account, 150 labels / datapoint, 1 MB / request, 1 000 datapoints / request.
Full details: CloudWatch OTLP endpoint docs.
Semantic Helpers
Section titled “Semantic Helpers”import { traceS3, traceDynamoDB } from 'autotel-aws';
// S3 with automatic semantic attributesexport const uploadFile = traceS3({ bucket: 'my-bucket', operation: 'PutObject',})((ctx) => async (key: string, body: Buffer) => { return s3.putObject({ Bucket: 'my-bucket', Key: key, Body: body });});Examples
Section titled “Examples”example-aws-lambda— Lambda withwrapHandler(), AWS SDK v3 auto-instrumentation, S3/DynamoDB/SQS helpers, and LocalStack support.
Entry Points
Section titled “Entry Points”autotel-aws/lambda— Lambda handler wrappingautotel-aws/lambda/auto— Zero-config Lambdaautotel-aws/sdk— AWS SDK instrumentationautotel-aws/sqs— SQS producer/consumerautotel-aws/sns— SNS publisherautotel-aws/kinesis— Kinesis producer/consumerautotel-aws/step-functions— Step Functionsautotel-aws/eventbridge— EventBridge publisherautotel-aws/xray— X-Ray compatibilityautotel-aws/cloudwatch— SigV4-signed OTLP exporters for CloudWatch's native endpointsautotel-aws/testing— Test utilities