Skip to content

Feature Request: Add withXrayTracing helper to simplify AWS SDK client instrumentation #192

@godu

Description

@godu

Problem

Currently, when using @effect-aws/powertools-tracer with any @effect-aws/client-* package, users must write significant boilerplate to properly instrument AWS SDK clients for X-Ray subsegments:

import { DynamoDBClient } from "@aws-sdk/client-dynamodb";
import { DynamoDBDocumentClient } from "@aws-sdk/lib-dynamodb";
import { DynamoDBDocumentService } from "@effect-aws/dynamodb";
import { XrayTracer } from "@effect-aws/powertools-tracer/Tracer";
import { Effect, Layer } from "effect";

export const InstrumentedLayer = Layer.unwrapEffect(
    Effect.gen(function* () {
        const tracer = yield* XrayTracer;
        const rawClient = new DynamoDBClient({});
        const instrumentedClient = yield* Effect.fromNullable(
            tracer.captureAWSv3Client(rawClient),
        );
        const documentClient = DynamoDBDocumentClient.from(instrumentedClient);
        return DynamoDBDocumentService.baseLayer(() => documentClient);
    }),
);

This pattern:

  1. Requires understanding of Layer.unwrapEffect + Effect.gen combination
  2. Must be repeated for every AWS service client
  3. Requires manually accessing XrayTracer and calling captureAWSv3Client
  4. Easy to get wrong (timing of client capture matters for X-Ray)

Proposed Solution

Add a helper function to @effect-aws/powertools-tracer that simplifies AWS SDK client instrumentation. Ideally something like:

import { DynamoDB } from "@effect-aws/client-dynamodb";
import { S3 } from "@effect-aws/client-s3";
import { withXrayTracing } from "@effect-aws/powertools-tracer";

// Wrap any client layer - works with all @effect-aws/client-* packages
const InstrumentedDynamoDB = withXrayTracing(DynamoDB.defaultLayer);
const InstrumentedS3 = withXrayTracing(S3.defaultLayer);

// Also works with custom configurations
const CustomDynamoDB = withXrayTracing(
    DynamoDB.layer({ region: "eu-central-1" })
);

The exact API design is open for discussion - the key goal is to eliminate the boilerplate while keeping the instrumentation in @effect-aws/powertools-tracer rather than modifying client packages.

Why add this to powertools-tracer?

  1. No changes to client packages - All 60+ @effect-aws/client-* packages remain unchanged
  2. No new dependencies - Client packages don't need to depend on powertools-tracer
  3. Single maintenance point - Instrumentation logic lives in one place
  4. Composable - Works with Effect's layer composition and any client layer
  5. Optional - Users who don't need X-Ray don't pay any cost

Additional Context

  • AWS Powertools Tracer uses captureAWSv3Client() which patches the AWS SDK client
  • The @effect-aws/powertools-tracer package already provides XrayTracer tag
  • All @effect-aws/client-* packages use baseLayer() which accepts a client factory - this could be leveraged

Benefits

  1. Reduced boilerplate - One-liner instead of 10+ lines
  2. Consistent pattern - Same API for all AWS services
  3. Harder to misuse - Library handles timing/scoping correctly
  4. Better DX - Users don't need to understand Layer internals

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions