Distributed Tracing using AWS Lambda Powertools for TypeScript

Winnie Ho
AMA Technology Blog
4 min readDec 5, 2022

Modern applications often depend on multiple services, third-party systems, hosting and cloud providers. Gaining insight into the health of our applications and responding promptly to communication and latency issues through distributed tracing enable us to support and improve our business goals, thus achieving operational excellence.

Photo by José Martín Ramírez Carrasco on Unsplash

AWS X-Ray collects data about the requests to and from an application and allows us to visualize data to identify issues and areas for optimization. The Tracer utility of the AWS Lambda Powertools for TypeScript is a thin wrapper for AWS X-Ray SDK for Node.js with opinionated defaults to trace Lambda functions running on the Node.js runtime effortlessly. It automatically tracks the requests and responses of downstream API calls and generates segments to correlate individual operations in a distributed transaction. It also captures information like cold start, service names, and exceptions as annotations and metadata in additional subsegments.

Let’s create a simple Lambda application to see how easy it is to visualize the flow of a request between different AWS and external services. The application is a REST API built using API Gateway and Lambda proxy integration. We then simulate integration with external services by making two calls to httpbin.org. After getting the responses back, we call another API Gateway endpoint to store the results in a DynamoDB table. You can find the complete source code in this GitHub repo.

Installation and Setup

We can install the Powertools in two ways: a public Lambda Layer or an npm package. Using layers reduces the size of the Lambda package and makes deployment faster, so that’s what we will do in our CDK application:

Since all the Powertools packages are available in the Lambda Layer, we need to exclude the modules from being bundled with the Lambda code. We also need to enable active tracing and reference the Powertools Layer:

Lambda Code Instrumentation

We can use Powertools to instrument our code in three ways: Middy middleware, method decorator, and manually. Using Middy is seamless if you already use it to handle cross-cutting concerns in your Lambdas, such as authentication and request validation. If you write the business logic of your applications using the OOP paradigm, you can attach method decorators to a TypeScript class declaration. If you do not use Middy nor TypeScript classes, manual instrumentation provides the highest degree of customization without additional dependency. We will use Middy in our example.

To start using the Tracer utility, instantiate it outside the Lambda handler so that subsequent invocations processed by the same instance of your function can reuse it:

Notice how we pass the Lambda handler to Middy and the Tracer instance to the captureLambdaHandler middleware.

Outside the Lambda handler, we also fetch the API key from AWS Secrets Manager and the API URL from Parameter Store to call an endpoint to save results from the external API calls in DynamoDB.

Testing and View the X-Ray Trace in CloudWatch

To test the application, we can use the AWS CLI to get the API key from API Gateway and call our GET /middy endpoint in Postman with the key value in the X-API-Key request header.

Now we can visit CloudWatch to look up the X-Ray trace:

X-Ray traces in CloudWatch
X-Ray traces in CloudWatch

Follow Requests and Responses through Different Systems

Select a trace to see the trace map and the segments timeline. The Tracer utility has automatically traced the data fetch from Parameter Store and Secrets Manager in the Lambda init phase, the invocation of the Lambda handler, the external API calls to httpbin.org, and the data store to DynamoDB.

Trace map
Trace map
Segments timeline
Segments timeline

Record More Context

We can use annotations and metadata to show more details in the currently open subsegment. AWS X-Ray indexes annotations; we can use them to filter traces and slice and dice transactions. The metadata key-values are not indexed and provide additional context for an operation. For example, we use the putMetadata method to show the exception from the last external API call here:

When something goes wrong, we’d want to surface the root trace ID to our users so they can reference it when contacting support. We can do that by calling tracer.getRootXrayTraceId().

Segment details of the Lambda handler showing why an API call failed
Segment details of the Lambda handler showing why an API call failed

Note: The current version of Powertools for TypeScript does not support top-level await because the main dependency aws-xray-sdk-node only builds from CommonJS.

Summary and What’s Next

This post shows how AWS Lambda Powertools for TypeScript help us adopt operational excellence best practices by implementing transaction traceability. In the next post of the series, we will explore how Powertools support another element of application telemetry: logs.

Winnie Ho is a Senior Software Developer @ Alberta Motor Association who has an insatiable desire to learn, read and write about all the things AWS and the web.

--

--

Winnie Ho
AMA Technology Blog

Past: User Experience Designer | Now: 2 x AWS Certified 💙 Senior Software Developer @ amaabca | Future: Impact Beyond Code