Skip to content

Tracer

Do not use this library in production

AWS Lambda Powertools for TypeScript is currently released as a beta developer preview and is intended strictly for feedback purposes only.
This version is not stable, and significant breaking changes might incur as part of the upcoming production-ready release.

Do not use this library for production workloads.

Tracer is an opinionated thin wrapper for AWS X-Ray SDK for Node.js.

Key features

  • Auto capture cold start and service name as annotations, and responses or full exceptions as metadata
  • Auto-disable when not running in AWS Lambda environment
  • Support tracing functions via decorators, middleware, and manual instrumentation
  • Support tracing AWS SDK v2 and v3 via AWS X-Ray SDK for Node.js

Tracer showcase

Getting started

Installation

Install the library in your project:

1
npm install @aws-lambda-powertools/tracer

Utility settings

The library requires one setting. You can set it as environment variables, or pass it in the constructor.

These settings will be used across all traces emitted:

Setting Description Environment variable Constructor parameter
Service name Sets an annotation with the name of the service across all traces e.g. shopping-cart-api POWERTOOLS_SERVICE_NAME serviceName

For a complete list of supported environment variables, refer to this section.

Permissions

Before your use this utility, your AWS Lambda function must have permissions to send traces to AWS X-Ray.

Example using AWS Serverless Application Model (SAM)

1
2
3
4
5
6
7
8
9
Resources:
  HelloWorldFunction:
    Type: AWS::Serverless::Function
    Properties:
      Runtime: nodejs14.x
      Tracing: Active
      Environment:
        Variables:
          POWERTOOLS_SERVICE_NAME: example

Lambda handler

You can quickly start by importing the Tracer class, initialize it outside the Lambda handler, and instrument your function.

Note

Middy comes bundled with Tracer, so you can just import it when using the middleware.

Using Middy for the first time?

Learn more about its usage and lifecycle in the official Middy documentation.

1
2
3
4
5
6
7
8
9
import { Tracer } from '@aws-lambda-powertools/tracer';
import middy from '@middy/core';

const tracer = Tracer(); // Sets service via env var
// OR tracer = Tracer({ service: 'example' });

export const handler = middy(async (_event: any, _context: any) => {
    ...
}).use(captureLambdaHandler(tracer));
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
import { Tracer } from '@aws-lambda-powertools/tracer';

const tracer = Tracer(); // Sets service via env var
// OR tracer = Tracer({ service: 'example' });

class Lambda {
    @tracer.captureLambdaHandler()
    public handler(event: any, context: any) {
        ...
    }
}

export const handlerClass = new Lambda();
export const handler = handlerClass.handler; 
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
import { Tracer } from '@aws-lambda-powertools/tracer';

const tracer = Tracer(); // Sets service via env var
// OR tracer = Tracer({ service: 'serverlessAirline' });

export const handler = async (_event: any, context: any) => {
    const segment = tracer.getSegment(); // This is the facade segment (the one that is created by AWS Lambda)
    // Create subsegment for the function & set it as active
    const subsegment = segment.addNewSubsegment(`## ${process.env._HANDLER}`);
    tracer.setSegment(subsegment);

    // Annotate the subsegment with the cold start & serviceName
    tracer.annotateColdStart();
    tracer.addServiceNameAnnotation();

    let res;
    try {
        res = ...
        // Add the response as metadata 
        tracer.addResponseAsMetadata(res, process.env._HANDLER);
    } catch (err) {
        // Add the error as metadata
        tracer.addErrorAsMetadata(err as Error);
        throw err;
    } finally {
        // Close subsegment (the AWS Lambda one is closed automatically)
        subsegment.close();
        // Set the facade segment as active again
        tracer.setSegment(segment);
    }

    return res;
}

When using the captureLambdaHandler decorator or middleware, Tracer performs these additional tasks to ease operations:

  • Handles the lifecycle of the subsegment
  • Creates a ColdStart annotation to easily filter traces that have had an initialization overhead
  • Creates a ServiceName annotation to easily filter traces that have a specific service name
  • Captures any response, or full exceptions generated by the handler, and include as tracing metadata

Annotations & Metadata

Annotations are key-values associated with traces and indexed by AWS X-Ray. You can use them to filter traces and to create Trace Groups to slice and dice your transactions.

Metadata are key-values also associated with traces but not indexed by AWS X-Ray. You can use them to add additional context for an operation using any native object.

You can add annotations using putAnnotation method.

1
2
3
4
5
6
7
import { Tracer } from '@aws-lambda-powertools/tracer';

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

export const handler = async (_event: any, _context: any) => {
    tracer.putAnnotation('successfulBooking', true);
}

You can add metadata using putMetadata method.

1
2
3
4
5
6
7
8
import { Tracer } from '@aws-lambda-powertools/tracer';

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

export const handler = async (_event: any, _context: any) => {
    const res = someLogic();
    tracer.putMetadata('paymentResponse', res);
}

Methods

You can trace other methods using the captureMethod decorator or manual instrumentation.

Info

We currently support a middleware for tracing methods, let us know if you'd like to see one!

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
import { Tracer } from '@aws-lambda-powertools/tracer';

const tracer = Tracer();

class Lambda {
    @tracer.captureMethod()
    public getChargeId(): string {
        ...
        return 'foo bar'
    }

    public handler(event: any, context: any) {
        const chargeId = this.getChargeId();
        const payment = collectPayment(chargeId);
        ...
    }
}

export const handlerClass = new Lambda();
export const getChargeId = handlerClass.getChargeId;
export const handler = handlerClass.handler; 
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
import { Tracer } from '@aws-lambda-powertools/tracer';

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

const chargeId = async () => {
    const parentSubsegment = tracer.getSegment(); // This is the subsegment currently active
    // Create subsegment for the function & set it as active
    const subsegment = parentSubsegment.addNewSubsegment(`### chargeId`);
    tracer.setSegment(subsegment);

    let res;
    try {
        res = await someLogic(); // Do something
        // Add the response as metadata
        tracer.addResponseAsMetadata(res, 'chargeId');
    } catch (err) {
        // Add the error as metadata
        tracer.addErrorAsMetadata(err as Error);
        throw err;
    }

    // Close subsegment (the AWS Lambda one is closed automatically)
    subsegment.close();
    // Set the facade segment as active again
    tracer.setSegment(parentSubsegment);

    return res;
}

export const handler = async (_event: any, _context: any) => {
    const chargeId = this.getChargeId();
    const payment = collectPayment(chargeId);
    ...
}

Patching AWS SDK clients

Tracer can patch AWS SDK clients and create traces when your application makes calls to AWS services.

Info

The following snippet assumes you are using AWS SDK v3 for JavaScript

You can patch any AWS SDK clients by calling captureAWSv3Client method:

1
2
3
4
5
6
import { S3Client } from "@aws-sdk/client-s3";
import { Tracer } from '@aws-lambda-powertools/tracer';

const tracer = new Tracer();
const client = new S3Client({});
tracer.captureAWSv3Client(client);

Info

The following two snippets assume you are using AWS SDK v2 for JavaScript

You can patch all AWS SDK clients by calling captureAWS method:

1
2
3
4
import { Tracer } from '@aws-lambda-powertools/tracer';

const tracer = new Tracer();
const AWS = tracer.captureAWS(require('aws-sdk'));

If you're looking to shave a few microseconds, or milliseconds depending on your function memory configuration, you can patch specific clients using captureAWSClient:

1
2
3
4
5
import { S3 } from "aws-sdk";
import { Tracer } from '@aws-lambda-powertools/tracer';

const tracer = new Tracer();
const s3 = tracer.captureAWSClient(new S3({ apiVersion: "2006-03-01" }));

Advanced

Disabling response auto-capture

Use POWERTOOLS_TRACER_CAPTURE_RESPONSE=false environment variable to instruct Tracer not to serialize function responses as metadata.

This is commonly useful in three scenarios

  1. You might return sensitive information you don't want it to be added to your traces
  2. You might manipulate streaming objects that can be read only once; this prevents subsequent calls from being empty
  3. You might return more than 64K of data e.g., message too long error

Disabling exception auto-capture

Use POWERTOOLS_TRACER_CAPTURE_ERROR=false environment variable to instruct Tracer not to serialize exceptions as metadata.

Commonly useful in one scenario

  1. You might return sensitive information from exceptions, stack traces you might not control

Escape hatch mechanism

You can use tracer.provider attribute to access all methods provided by the AWS X-Ray SDK.

This is useful when you need a feature available in X-Ray that is not available in the Tracer utility, for example SQL queries tracing, or a custom logger.

1
2
3
4
5
6
import { Logger } from '@aws-lambda-powertools/logger';
import { Tracer } from '@aws-lambda-powertools/tracer';

const logger = new Logger();
const tracer = new Tracer()
tracer.provider.setLogger(logger)

Testing your code

Tracer is disabled by default when not running in the AWS Lambda environment - This means no code changes or environment variables to be set.

Tips

  • Use annotations on key operations to slice and dice traces, create unique views, and create metrics from it via Trace Groups
  • Use a namespace when adding metadata to group data more easily
  • Annotations and metadata are added to the current subsegment opened. If you want them in a specific subsegment, create one via the escape hatch mechanism

Last update: 2021-12-30
Back to top