or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

aws-sdk-instrumentation.mddecorator-tracing.mdindex.mdmanual-instrumentation.mdmiddleware-tracing.mdtypes.md
tile.json

aws-sdk-instrumentation.mddocs/

AWS SDK Instrumentation

AWS SDK instrumentation automatically captures traces for AWS service calls, providing visibility into downstream service interactions. The Tracer supports AWS SDK v3 (recommended) and AWS SDK v2 (deprecated).

Capabilities

AWS SDK v3 Client Instrumentation

Instrument AWS SDK v3 clients to automatically trace service calls.

/**
 * Patch an AWS SDK v3 client to create traces for AWS service calls
 *
 * Automatically captures:
 * - Service name and operation
 * - Request parameters (if configured)
 * - Response data (if configured)
 * - Errors and exceptions
 *
 * @param service - AWS SDK v3 client instance
 * @returns The same client instance, instrumented for tracing
 */
captureAWSv3Client<T>(service: T): T;

Basic Usage:

import { Tracer } from '@aws-lambda-powertools/tracer';
import { DynamoDBClient, PutItemCommand, GetItemCommand } from '@aws-sdk/client-dynamodb';

const tracer = new Tracer({ serviceName: 'orderService' });

// Instrument the DynamoDB client
const dynamoDB = tracer.captureAWSv3Client(new DynamoDBClient({}));

export const handler = async (event: OrderEvent, context: unknown) => {
  // This PutItem call will be automatically traced
  await dynamoDB.send(new PutItemCommand({
    TableName: 'Orders',
    Item: {
      orderId: { S: event.orderId },
      status: { S: 'pending' }
    }
  }));

  // This GetItem call will also be traced
  const result = await dynamoDB.send(new GetItemCommand({
    TableName: 'Orders',
    Key: { orderId: { S: event.orderId } }
  }));

  return result.Item;
};

Multiple SDK Clients

Instrument multiple AWS SDK clients for comprehensive tracing:

import { Tracer } from '@aws-lambda-powertools/tracer';
import { DynamoDBClient, GetItemCommand } from '@aws-sdk/client-dynamodb';
import { S3Client, GetObjectCommand } from '@aws-sdk/client-s3';
import { SQSClient, SendMessageCommand } from '@aws-sdk/client-sqs';

const tracer = new Tracer({ serviceName: 'dataProcessor' });

// Instrument multiple clients
const dynamoDB = tracer.captureAWSv3Client(new DynamoDBClient({}));
const s3 = tracer.captureAWSv3Client(new S3Client({}));
const sqs = tracer.captureAWSv3Client(new SQSClient({}));

export const handler = async (event: ProcessEvent, context: unknown) => {
  // Get data from DynamoDB (traced)
  const dbResult = await dynamoDB.send(new GetItemCommand({
    TableName: 'Data',
    Key: { id: { S: event.id } }
  }));

  // Get file from S3 (traced)
  const s3Result = await s3.send(new GetObjectCommand({
    Bucket: 'my-bucket',
    Key: event.fileKey
  }));

  // Send message to SQS (traced)
  await sqs.send(new SendMessageCommand({
    QueueUrl: process.env.QUEUE_URL,
    MessageBody: JSON.stringify({ processed: true })
  }));

  return { success: true };
};

Client Configuration

You can configure the client before instrumentation:

import { Tracer } from '@aws-lambda-powertools/tracer';
import { DynamoDBClient } from '@aws-sdk/client-dynamodb';

const tracer = new Tracer({ serviceName: 'userService' });

// Configure client with custom options
const dynamoDB = tracer.captureAWSv3Client(
  new DynamoDBClient({
    region: 'us-east-1',
    maxAttempts: 3,
    requestHandler: {
      connectionTimeout: 1000,
      socketTimeout: 3000
    }
  })
);

export const handler = async (event: UserEvent, context: unknown) => {
  // Client is configured AND traced
  await dynamoDB.send(/* ... */);
};

Complete Example with Decorators

Combine AWS SDK instrumentation with decorator-based tracing:

import { Tracer } from '@aws-lambda-powertools/tracer';
import { DynamoDBClient, PutItemCommand, QueryCommand } from '@aws-sdk/client-dynamodb';
import { S3Client, PutObjectCommand } from '@aws-sdk/client-s3';
import type { LambdaInterface } from '@aws-lambda-powertools/commons/types';

const tracer = new Tracer({ serviceName: 'bookingService' });

// Instrument AWS clients
const dynamoDB = tracer.captureAWSv3Client(new DynamoDBClient({}));
const s3 = tracer.captureAWSv3Client(new S3Client({}));

interface Booking {
  id: string;
  userId: string;
  details: unknown;
}

class BookingHandler implements LambdaInterface {
  @tracer.captureMethod()
  private async saveBooking(booking: Booking): Promise<void> {
    // DynamoDB call is automatically traced within this method's subsegment
    await dynamoDB.send(new PutItemCommand({
      TableName: 'Bookings',
      Item: {
        bookingId: { S: booking.id },
        userId: { S: booking.userId }
      }
    }));

    tracer.putAnnotation('bookingSaved', true);
  }

  @tracer.captureMethod()
  private async saveBookingDetails(bookingId: string, details: unknown): Promise<void> {
    // S3 call is automatically traced within this method's subsegment
    await s3.send(new PutObjectCommand({
      Bucket: 'booking-details',
      Key: `${bookingId}.json`,
      Body: JSON.stringify(details)
    }));

    tracer.putAnnotation('detailsSaved', true);
  }

  @tracer.captureMethod()
  private async getUserBookings(userId: string): Promise<Booking[]> {
    // Query is automatically traced
    const result = await dynamoDB.send(new QueryCommand({
      TableName: 'Bookings',
      KeyConditionExpression: 'userId = :userId',
      ExpressionAttributeValues: {
        ':userId': { S: userId }
      }
    }));

    return result.Items?.map(item => ({
      id: item.bookingId.S!,
      userId: item.userId.S!,
      details: {}
    })) || [];
  }

  @tracer.captureLambdaHandler()
  public async handler(event: BookingEvent, context: unknown): Promise<void> {
    tracer.putAnnotation('userId', event.userId);

    const booking: Booking = {
      id: event.bookingId,
      userId: event.userId,
      details: event.details
    };

    await this.saveBooking(booking);
    await this.saveBookingDetails(booking.id, booking.details);

    const userBookings = await this.getUserBookings(event.userId);
    tracer.putMetadata('userBookingCount', userBookings.length);
  }
}

const handlerClass = new BookingHandler();
export const handler = handlerClass.handler.bind(handlerClass);

Complete Example with Middleware

Combine AWS SDK instrumentation with middleware-based tracing:

import { Tracer } from '@aws-lambda-powertools/tracer';
import { captureLambdaHandler } from '@aws-lambda-powertools/tracer/middleware';
import { DynamoDBClient, UpdateItemCommand, GetItemCommand } from '@aws-sdk/client-dynamodb';
import { SNSClient, PublishCommand } from '@aws-sdk/client-sns';
import middy from '@middy/core';

const tracer = new Tracer({ serviceName: 'orderService' });

// Instrument AWS clients
const dynamoDB = tracer.captureAWSv3Client(new DynamoDBClient({}));
const sns = tracer.captureAWSv3Client(new SNSClient({}));

interface OrderEvent {
  orderId: string;
  status: string;
}

const lambdaHandler = async (event: OrderEvent, context: unknown): Promise<void> => {
  tracer.putAnnotation('orderId', event.orderId);
  tracer.putAnnotation('newStatus', event.status);

  // Update order status in DynamoDB (traced)
  await dynamoDB.send(new UpdateItemCommand({
    TableName: 'Orders',
    Key: { orderId: { S: event.orderId } },
    UpdateExpression: 'SET #status = :status',
    ExpressionAttributeNames: { '#status': 'status' },
    ExpressionAttributeValues: { ':status': { S: event.status } }
  }));

  // Get updated order (traced)
  const result = await dynamoDB.send(new GetItemCommand({
    TableName: 'Orders',
    Key: { orderId: { S: event.orderId } }
  }));

  // Publish notification to SNS (traced)
  await sns.send(new PublishCommand({
    TopicArn: process.env.ORDER_TOPIC_ARN,
    Message: JSON.stringify({
      orderId: event.orderId,
      status: event.status
    })
  }));

  tracer.putAnnotation('orderUpdated', true);
};

export const handler = middy(lambdaHandler).use(captureLambdaHandler(tracer));

AWS SDK v2 (Deprecated)

The Tracer provides backward compatibility with AWS SDK v2, but these methods are deprecated.

/**
 * @deprecated Use captureAWSv3Client instead
 *
 * Patch all AWS SDK v2 clients and create traces when your application makes calls to AWS services
 *
 * @param aws - AWS SDK v2 import
 * @returns The patched AWS SDK
 */
captureAWS<T>(aws: T): T;

/**
 * @deprecated Use captureAWSv3Client instead
 *
 * Patch a specific AWS SDK v2 client and create traces for that AWS service
 *
 * @param service - AWS SDK v2 client instance
 * @returns The patched client
 */
captureAWSClient<T>(service: T): T;

AWS SDK v2 Usage (Not Recommended):

import { Tracer } from '@aws-lambda-powertools/tracer';
import AWS from 'aws-sdk';

const tracer = new Tracer({ serviceName: 'legacyService' });

// Patch all AWS SDK v2 clients (deprecated)
const AWSWithTracing = tracer.captureAWS(AWS);
const dynamoDB = new AWSWithTracing.DynamoDB.DocumentClient();

// OR patch a specific client (deprecated)
const s3 = tracer.captureAWSClient(new AWS.S3());

export const handler = async (event: unknown, context: unknown) => {
  await dynamoDB.put({
    TableName: 'Items',
    Item: { id: '123' }
  }).promise();
};

Migration from SDK v2 to v3

Before (AWS SDK v2):

import { Tracer } from '@aws-lambda-powertools/tracer';
import AWS from 'aws-sdk';

const tracer = new Tracer({ serviceName: 'myService' });
const dynamoDB = tracer.captureAWSClient(new AWS.DynamoDB.DocumentClient());

await dynamoDB.put({
  TableName: 'Items',
  Item: { id: '123' }
}).promise();

After (AWS SDK v3):

import { Tracer } from '@aws-lambda-powertools/tracer';
import { DynamoDBClient } from '@aws-sdk/client-dynamodb';
import { DynamoDBDocumentClient, PutCommand } from '@aws-sdk/lib-dynamodb';

const tracer = new Tracer({ serviceName: 'myService' });

// Create and instrument base client
const client = tracer.captureAWSv3Client(new DynamoDBClient({}));

// Wrap with document client
const dynamoDB = DynamoDBDocumentClient.from(client);

await dynamoDB.send(new PutCommand({
  TableName: 'Items',
  Item: { id: '123' }
}));

Tracing Behavior

When you instrument an AWS SDK v3 client with captureAWSv3Client():

  1. Subsegments Created: Each AWS service call creates a subsegment under the current active segment
  2. Service Information: The subsegment includes service name (e.g., "DynamoDB", "S3")
  3. Operation Details: The operation name is captured (e.g., "PutItem", "GetObject")
  4. Error Tracking: Errors from AWS services are automatically captured
  5. User Agent: Powertools user agent is added to help AWS identify Powertools usage

Important Notes

  1. Instrument clients once: Create and instrument clients outside the handler for reuse across invocations
  2. SDK v3 recommended: AWS SDK v3 is the recommended approach; v2 support is deprecated
  3. All operations traced: Every operation sent through an instrumented client is traced
  4. Works with all services: Instrumentation works with all AWS SDK v3 service clients
  5. Document clients: For DynamoDB Document Client, instrument the base client then wrap it