Skip to content

AWS

autotel-aws provides ergonomic, vendor-agnostic OpenTelemetry instrumentation for AWS services.

Terminal window
npm install autotel-aws autotel
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 };
});
import 'autotel-aws/lambda/auto'; // Must be FIRST import
export const handler = async (event, context) => {
return { statusCode: 200 };
};
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' });
import { instrumentSDK, createTracedClient } from 'autotel-aws/sdk';
import { S3Client } from '@aws-sdk/client-s3';
// Wrap existing client
const s3 = instrumentSDK(new S3Client({ region: 'us-east-1' }));
// Or create pre-instrumented
const s3 = createTracedClient(S3Client, { region: 'us-east-1' });
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);
},
});

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.

Terminal window
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-transformer

Drop the signal-specific peers you don't use (e.g. omit sdk-logs if you only export 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())],
});
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,
}),
],
});

| | 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.

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, service logs
  • metrics: https://monitoring.<region>.amazonaws.com/v1/metrics, service monitoring
  • 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.

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.

  • 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.

import { traceS3, traceDynamoDB } from 'autotel-aws';
// S3 with automatic semantic attributes
export const uploadFile = traceS3({
bucket: 'my-bucket',
operation: 'PutObject',
})((ctx) => async (key: string, body: Buffer) => {
return s3.putObject({ Bucket: 'my-bucket', Key: key, Body: body });
});
  • example-aws-lambda — Lambda with wrapHandler(), AWS SDK v3 auto-instrumentation, S3/DynamoDB/SQS helpers, and LocalStack support.
  • autotel-aws/lambda — Lambda handler wrapping
  • autotel-aws/lambda/auto — Zero-config Lambda
  • autotel-aws/sdk — AWS SDK instrumentation
  • autotel-aws/sqs — SQS producer/consumer
  • autotel-aws/sns — SNS publisher
  • autotel-aws/kinesis — Kinesis producer/consumer
  • autotel-aws/step-functions — Step Functions
  • autotel-aws/eventbridge — EventBridge publisher
  • autotel-aws/xray — X-Ray compatibility
  • autotel-aws/cloudwatch — SigV4-signed OTLP exporters for CloudWatch's native endpoints
  • autotel-aws/testing — Test utilities