Skip to content

Tracing

Powertools tracing is an opinionated thin wrapper for AWS X-Ray Java SDK a provides functionality to reduce the overhead of performing common tracing tasks.

Tracing showcase

Key Features

  • Capture cold start as annotation, and responses as well as full exceptions as metadata
  • Helper methods to improve the developer experience of creating new X-Ray subsegments.
  • Better developer experience when developing with multiple threads.
  • Auto patch supported modules by AWS X-Ray

Initialization

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
10
11
Resources:
    HelloWorldFunction:
        Type: AWS::Serverless::Function
        Properties:
        ...
        Runtime: java8

        Tracing: Active
        Environment:
            Variables:
                POWERTOOLS_SERVICE_NAME: example

The Powertools service name is used as the X-Ray namespace. This can be set using the environment variable POWERTOOLS_SERVICE_NAME

Lambda handler

To enable Powertools tracing to your function add the @Tracing annotation to yourhandleRequest` method or on any method will capture the method as a separate subsegment automatically. You can optionally choose to customize segment name that appears in traces.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
public class App implements RequestHandler<APIGatewayProxyRequestEvent, APIGatewayProxyResponseEvent> {

    @Tracing
    public APIGatewayProxyResponseEvent handleRequest(APIGatewayProxyRequestEvent input, Context context) {
        businessLogic1();

        businessLogic2();
    }

    @Tracing
    public void businessLogic1(){

    }

    @Tracing
    public void businessLogic2(){

    }
}
1
2
3
4
5
6
public class App implements RequestHandler<APIGatewayProxyRequestEvent, APIGatewayProxyResponseEvent> {

    @Tracing(segmentName="yourCustomName")
    public APIGatewayProxyResponseEvent handleRequest(APIGatewayProxyRequestEvent input, Context context) {
    ...
    }

By default, this annotation will automatically record method responses and exceptions. You can change the default behavior by setting the environment variables POWERTOOLS_TRACER_CAPTURE_RESPONSE and POWERTOOLS_TRACER_CAPTURE_ERROR as needed. Optionally, you can override behavior by different supported captureMode to record response, exception or both.

Returning sensitive information from your Lambda handler or functions, where Tracing is used?

You can disable annotation from capturing their responses and exception as tracing metadata with captureMode=DISABLED or globally by setting environment variables POWERTOOLS_TRACER_CAPTURE_RESPONSE and POWERTOOLS_TRACER_CAPTURE_ERROR to false

1
2
3
4
5
6
public class App implements RequestHandler<APIGatewayProxyRequestEvent, APIGatewayProxyResponseEvent> {

    @Tracing(captureMode=CaptureMode.DISABLED)
    public APIGatewayProxyResponseEvent handleRequest(APIGatewayProxyRequestEvent input, Context context) {
    ...
    }
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
Resources:
    HelloWorldFunction:
        Type: AWS::Serverless::Function
        Properties:
        ...
        Runtime: java8

        Tracing: Active
        Environment:
            Variables:
                POWERTOOLS_TRACER_CAPTURE_RESPONSE: false
                POWERTOOLS_TRACER_CAPTURE_ERROR: false

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 from TracingUtils

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
import software.amazon.lambda.powertools.tracing.Tracing;
import software.amazon.lambda.powertools.tracing.TracingUtils;

public class App implements RequestHandler<APIGatewayProxyRequestEvent, APIGatewayProxyResponseEvent> {

    @Tracing
    public APIGatewayProxyResponseEvent handleRequest(APIGatewayProxyRequestEvent input, Context context) {
        TracingUtils.putAnnotation("annotation", "value");
    }
}

You can add metadata using putMetadata() method from TracingUtils

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
import software.amazon.lambda.powertools.tracing.Tracing;
import software.amazon.lambda.powertools.tracing.TracingUtils;

public class App implements RequestHandler<APIGatewayProxyRequestEvent, APIGatewayProxyResponseEvent> {

    @Tracing
    public APIGatewayProxyResponseEvent handleRequest(APIGatewayProxyRequestEvent input, Context context) {
        TracingUtils.putMetadata("content", "value");
    }
}

Utilities

Tracing modules comes with certain utility method when you don't want to use annotation for capturing a code block under a subsegment, or you are doing multithreaded programming. Refer examples below.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
import software.amazon.lambda.powertools.tracing.Tracing;
import software.amazon.lambda.powertools.tracing.TracingUtils;

public class App implements RequestHandler<APIGatewayProxyRequestEvent, APIGatewayProxyResponseEvent> {

    public APIGatewayProxyResponseEvent handleRequest(APIGatewayProxyRequestEvent input, Context context) {
         TracingUtils.withSubsegment("loggingResponse", subsegment -> {
            // Some business logic
         });

         TracingUtils.withSubsegment("localNamespace", "loggingResponse", subsegment -> {
            // Some business logic
         });
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
import static software.amazon.lambda.powertools.tracing.TracingUtils.withEntitySubsegment;

public class App implements RequestHandler<APIGatewayProxyRequestEvent, APIGatewayProxyResponseEvent> {

    public APIGatewayProxyResponseEvent handleRequest(APIGatewayProxyRequestEvent input, Context context) {
        // Extract existing trace data
        Entity traceEntity = AWSXRay.getTraceEntity();

        Thread anotherThread = new Thread(() -> withEntitySubsegment("inlineLog", traceEntity, subsegment -> {
            // Business logic in separate thread
        }));
    }
}

Instrumenting SDK clients and HTTP calls

User should make sure to instrument the SDK clients explicitly based on the function dependency. Refer details on how to instrument SDK client with Xray and outgoing http calls.


Last update: 2021-03-05