Instrumenting Java code in AWS Lambda
Lambda integrates with AWS X-Ray to help you trace, debug, and optimize Lambda applications. You can use X-Ray to trace a request as it traverses resources in your application, which may include Lambda functions and other AWS services.
To send tracing data to X-Ray, you can use one of two SDK libraries:
-
AWS Distro for OpenTelemetry (ADOT)
– A secure, production-ready, AWS-supported distribution of the OpenTelemetry (OTel) SDK. -
AWS X-Ray SDK for Java – An SDK for generating and sending trace data to X-Ray.
Both ADOT and the X-Ray SDK offer ways to send your telemetry data to the X-Ray service. You can then use X-Ray to view, filter, and gain insights into your application's performance metrics to identify issues and opportunities for optimization.
The X-Ray SDKs are part of a tightly integrated instrumentation solution offered by AWS. The ADOT Lambda Layers are part of an industry-wide standard for tracing instrumentation that collect more data in general, but may not be suited for all use cases. You can implement end-to-end tracing in X-Ray using either solution. To learn more about choosing between them, see Choosing between the AWS Distro for Open Telemetry and X-Ray SDKs.
Sections
- Using ADOT to instrument your Java functions
- Using the X-Ray SDK to instrument your Java functions
- Activating tracing with the Lambda console
- Activating tracing with the Lambda API
- Activating tracing with AWS CloudFormation
- Interpreting an X-Ray trace
- Storing runtime dependencies in a layer (X-Ray SDK)
- X-Ray tracing in sample applications (X-Ray SDK)
Using ADOT to instrument your Java functions
ADOT provides fully managed Lambda layers that package
everything you need to collect telemetry data using the OTel SDK. By consuming this layer, you can instrument your
Lambda functions without having to modify any function code. You can also configure your layer to do custom
initialization of OTel. For more information, see Custom configuration for the ADOT Collector on Lambda
For Java runtimes, you can choose between two layers to consume:
-
AWS managed Lambda layer for ADOT Java (Auto-instrumentation Agent) – This layer automatically transforms your function code at startup to collect tracing data. For detailed instructions on how to consume this layer together with the ADOT Java agent, see AWS Distro for OpenTelemetry Lambda Support for Java (Auto-instrumentation Agent)
in the ADOT documentation. -
AWS managed Lambda layer for ADOT Java – This layer also provides built-in instrumentation for Lambda functions, but it requires a few manual code changes to initialize the OTel SDK. For detailed instructions on how to consume this layer, see AWS Distro for OpenTelemetry Lambda Support for Java
in the ADOT documentation.
Using the X-Ray SDK to instrument your Java functions
To record data about calls that your function makes to other resources and services in your application, you can add the X-Ray SDK for Java to your build configuration. The following example shows a Gradle build configuration that includes the libraries that activate automatic instrumentation of AWS SDK for Java 2.x clients.
Example build.gradle – Tracing
dependencies
dependencies { implementation platform('software.amazon.awssdk:bom:2.15.0')
implementation platform('com.amazonaws:aws-xray-recorder-sdk-bom:2.11.0')
...implementation 'com.amazonaws:aws-xray-recorder-sdk-core' implementation 'com.amazonaws:aws-xray-recorder-sdk-aws-sdk' implementation 'com.amazonaws:aws-xray-recorder-sdk-aws-sdk-instrumentor'
... }
After you add the correct dependencies and make the necessary code changes, activate tracing in your function's configuration via the Lambda console or the API.
Activating tracing with the Lambda console
To toggle active tracing on your Lambda function with the console, follow these steps:
To turn on active tracing
Open the Functions page
of the Lambda console. -
Choose a function.
Choose Configuration and then choose Monitoring and operations tools.
Choose Edit.
-
Under X-Ray, toggle on Active tracing.
-
Choose Save.
Activating tracing with the Lambda API
Configure tracing on your Lambda function with the AWS CLI or AWS SDK, use the following API operations:
The following example AWS CLI command enables active tracing on a function named my-function.
aws lambda update-function-configuration --function-name my-function \ --tracing-config Mode=Active
Tracing mode is part of the version-specific configuration when you publish a version of your function. You can't change the tracing mode on a published version.
Activating tracing with AWS CloudFormation
To activate tracing on an AWS::Lambda::Function
resource in an AWS CloudFormation template, use the
TracingConfig
property.
Example function-inline.yml –
Tracing configuration
Resources: function: Type: AWS::Lambda::Function Properties:
TracingConfig: Mode: Active
...
For an AWS Serverless Application Model (AWS SAM) AWS::Serverless::Function
resource, use the Tracing
property.
Example template.yml – Tracing
configuration
Resources: function: Type: AWS::Serverless::Function Properties:
Tracing: Active
...
Interpreting an X-Ray trace
Your function needs permission to upload trace data to X-Ray. When you activate tracing in the Lambda
console, Lambda adds the required permissions to your function's execution role. Otherwise, add the AWSXRayDaemonWriteAccess
After you've configured active tracing, you can observe specific requests through your application. The X-Ray service graph shows information about your application and all its components. The following example from the error processor sample application shows an application with two functions. The primary function processes events and sometimes returns errors. The second function at the top processes errors that appear in the first's log group and uses the AWS SDK to call X-Ray, Amazon Simple Storage Service (Amazon S3), and Amazon CloudWatch Logs.

X-Ray doesn't trace all requests to your application. X-Ray applies a sampling algorithm to ensure that tracing is efficient, while still providing a representative sample of all requests. The sampling rate is 1 request per second and 5 percent of additional requests.
You cannot configure the X-Ray sampling rate for your functions.
When using active tracing, Lambda records 2 segments per trace, which creates two nodes on the service graph. The following image highlights these two nodes for the primary function from the error processor sample application.

The first node on the left represents the Lambda service, which receives the invocation request. The second
node represents your specific Lambda function. The following example shows a trace with these two segments. Both
are named my-function, but one has an origin of AWS::Lambda
and the other has
origin AWS::Lambda::Function
.

This example expands the function segment to show its three subsegments:
-
Initialization – Represents time spent loading your function and running initialization code. This subsegment only appears for the first event that each instance of your function processes.
-
Invocation – Represents the time spent running your handler code.
-
Overhead – Represents the time the Lambda runtime spends preparing to handle the next event.
You can also instrument HTTP clients, record SQL queries, and create custom subsegments with annotations and metadata. For more information, see AWS X-Ray SDK for Java in the AWS X-Ray Developer Guide.
You can use X-Ray tracing for free each month up to a certain limit as part of the AWS Free Tier. Beyond that threshold, X-Ray charges for trace storage and
retrieval. For more information, see AWS X-Ray pricing
Storing runtime dependencies in a layer (X-Ray SDK)
If you use the X-Ray SDK to instrument AWS SDK clients your function code, your deployment package can become quite large. To avoid uploading runtime dependencies every time you update your function code, package the X-Ray SDK in a Lambda layer.
The following example shows an AWS::Serverless::LayerVersion
resource that stores the AWS SDK for Java
and X-Ray SDK for Java.
Example template.yml – Dependencies
layer
Resources: function: Type: AWS::Serverless::Function Properties: CodeUri: build/distributions/blank-java.zip Tracing: Active
Layers: - !Ref libs
...libs: Type: AWS::Serverless::LayerVersion Properties: LayerName: blank-java-lib Description: Dependencies for the blank-java sample app. ContentUri: build/blank-java-lib.zip CompatibleRuntimes: - java8
With this configuration, you update the library layer only if you change your runtime dependencies. Since the function deployment package contains only your code, this can help reduce upload times.
Creating a layer for dependencies requires build configuration changes to generate the layer archive prior to
deployment. For a working example, see the java-basic
X-Ray tracing in sample applications (X-Ray SDK)
The GitHub repository for this guide includes sample applications that demonstrate the use of X-Ray tracing. Each sample application includes scripts for easy deployment and cleanup, an AWS SAM template, and supporting resources.
Sample Lambda applications in Java
-
java-basic
– A collection of minimal Java functions with unit tests and variable logging configuration. -
java-events
– A collection of Java functions that contain skeleton code for how to handle events from various services such as Amazon API Gateway, Amazon SQS, and Amazon Kinesis. These functions use the latest version of the aws-lambda-java-events library (3.0.0 and newer). These examples do not require the AWS SDK as a dependency. -
s3-java
– A Java function that processes notification events from Amazon S3 and uses the Java Class Library (JCL) to create thumbnails from uploaded image files. -
Use API Gateway to invoke a Lambda function – A Java function that scans a Amazon DynamoDB table that contains employee information. It then uses Amazon Simple Notification Service to send a text message to employees celebrating their work anniversaries. This example uses API Gateway to invoke the function.
All of the sample applications have active tracing enabled for Lambda functions. For example, the
s3-java
application shows automatic instrumentation of AWS SDK for Java 2.x clients, segment
management for tests, custom subsegments, and the use of Lambda layers to store runtime dependencies.