Log and monitor Java Lambda functions
AWS Lambda automatically monitors Lambda functions and sends log entries to Amazon CloudWatch. Your Lambda function comes with a CloudWatch Logs log group and a log stream for each instance of your function. The Lambda runtime environment sends details about each invocation and other output from your function's code to the log stream. For more information about CloudWatch Logs, see Sending Lambda function logs to CloudWatch Logs.
To output logs from your function code, you can use methods on java.lang.System
Creating a function that returns logs
To output logs from your function code, you can use methods on java.lang.Systemstdout or stderr. The aws-lambda-java-core library provides a logger class named LambdaLogger that you can access
from the context object. The logger class supports multiline logs.
The following example uses the LambdaLogger logger provided by the context object.
Example Handler.java
// Handler value: example.Handler public class Handler implements RequestHandler<Object, String>{ Gson gson = new GsonBuilder().setPrettyPrinting().create(); @Override public String handleRequest(Object event, Context context) {LambdaLogger logger = context.getLogger();String response = new String("SUCCESS"); // log execution detailslogger.log("ENVIRONMENT VARIABLES: " + gson.toJson(System.getenv())); logger.log("CONTEXT: " + gson.toJson(context));// process eventlogger.log("EVENT: " + gson.toJson(event));return response; } }
Example log format
START RequestId: 6bc28136-xmpl-4365-b021-0ce6b2e64ab0 Version: $LATEST ENVIRONMENT VARIABLES: { "_HANDLER": "example.Handler", "AWS_EXECUTION_ENV": "AWS_Lambda_java8", "AWS_LAMBDA_FUNCTION_MEMORY_SIZE": "512", ... } CONTEXT: { "memoryLimit": 512, "awsRequestId": "6bc28136-xmpl-4365-b021-0ce6b2e64ab0", "functionName": "java-console", ... } EVENT: { "records": [ { "messageId": "19dd0b57-xmpl-4ac1-bd88-01bbb068cb78", "receiptHandle": "MessageReceiptHandle", "body": "Hello from SQS!", ... } ] } END RequestId: 6bc28136-xmpl-4365-b021-0ce6b2e64ab0 REPORT RequestId: 6bc28136-xmpl-4365-b021-0ce6b2e64ab0 Duration: 198.50 ms Billed Duration: 724 ms Memory Size: 512 MB Max Memory Used: 90 MB Init Duration: 524.75 ms
The Java runtime logs the START, END, and REPORT lines for each
invocation. The report line provides the following details:
REPORT line data fields
-
RequestId – The unique request ID for the invocation.
-
Duration – The amount of time that your function's handler method spent processing the event.
-
Billed Duration – The amount of time billed for the invocation.
-
Memory Size – The amount of memory allocated to the function.
-
Max Memory Used – The amount of memory used by the function. When invocations share an execution environment, Lambda reports the maximum memory used across all invocations. This behavior might result in a higher than expected reported value.
-
Init Duration – For the first request served, the amount of time it took the runtime to load the function and run code outside of the handler method.
-
XRAY TraceId – For traced requests, the AWS X-Ray trace ID.
-
SegmentId – For traced requests, the X-Ray segment ID.
-
Sampled – For traced requests, the sampling result.
Using Lambda advanced logging controls with Java
To give you more control over how your functions' logs are captured, processed, and consumed, you can configure the following logging options for supported Java runtimes:
-
Log format - select between plain text and structured JSON format for your function's logs
-
Log level - for logs in JSON format, choose the detail level of the logs Lambda sends to CloudWatch, such as ERROR, DEBUG, or INFO
-
Log group - choose the CloudWatch log group your function sends logs to
For more information about these logging options, and instructions on how to configure your function to use them, see Configuring advanced logging controls for Lambda functions.
To use the log format and log level options with your Java Lambda functions, see the guidance in the following sections.
Using structured JSON log format with Java
If you select JSON for your function's log format, Lambda sends logs output using the LambdaLogger class as
structured JSON. Each JSON log object contains at least four key value pairs with the following keys:
-
"timestamp"- the time the log message was generated -
"level"- the log level assigned to the message -
"message"- the contents of the log message -
"AWSrequestId"- the unique request ID for the function invocation
Depending on the logging method you use, log outputs from your function captured in JSON format can also contain additional key value pairs.
To assign a level to logs you create using the LambdaLogger logger, you need to provide a
LogLevel argument in your logging command as shown in the following example.
Example Java logging code
LambdaLogger logger = context.getLogger(); logger.log("This is a debug log", LogLevel.DEBUG);
This log output by this example code would be captured in CloudWatch Logs as follows:
Example JSON log record
{
"timestamp":"2023-11-01T00:21:51.358Z",
"level":"DEBUG",
"message":"This is a debug log",
"AWSrequestId":"93f25699-2cbf-4976-8f94-336a0aa98c6f"
}If you don't assign a level to your log output, Lambda automatically assigns it the level INFO.
If your code already uses another logging library to produce JSON structured logs, you don't need to make any changes. Lambda doesn't double-encode any logs that are already JSON encoded. Even if you configure your function to use the JSON log format, your logging outputs appear in CloudWatch in the JSON structure you define.
Using log-level filtering with Java
For AWS Lambda to filter your application logs according to their log level, your function must use JSON formatted logs. You can achieve this in two ways:
-
Create log outputs using the standard
LambdaLoggerand configure your function to use JSON log formatting. Lambda then filters your log outputs using the "level" key value pair in the JSON object described in Using structured JSON log format with Java. To learn how to configure your function's log format, see Configuring advanced logging controls for Lambda functions. -
Use another logging library or method to create JSON structured logs in your code that include a "level" key value pair defining the level of the log output. You can use any logging library that can write JSON logs to
stdoutorstderr. For example, you can use Powertools for AWS Lambda or the Log4j2 package to generate JSON structured log outputs from your code. See Using Powertools for AWS Lambda (Java) and AWS SAM for structured logging and Implementing advanced logging with Log4j2 and SLF4J to learn more.
When you configure your function to use log-level filtering, you must select from the following options for the level of logs you want Lambda to send to CloudWatch Logs:
| Log level | Standard usage |
|---|---|
| TRACE (most detail) | The most fine-grained information used to trace the path of your code's execution |
| DEBUG | Detailed information for system debugging |
| INFO | Messages that record the normal operation of your function |
| WARN | Messages about potential errors that may lead to unexpected behavior if unaddressed |
| ERROR | Messages about problems that prevent the code from performing as expected |
| FATAL (least detail) | Messages about serious errors that cause the application to stop functioning |
For Lambda to filter your function's logs, you must also include a "timestamp" key value pair in your JSON log
output. The time must be specified in valid RFC 3339
Lambda sends logs of the selected level and lower to CloudWatch. For example, if you configure a log level of WARN, Lambda sends logs corresponding to the WARN, ERROR, and FATAL levels.
Implementing advanced logging with Log4j2 and SLF4J
Note
AWS Lambda does not include Log4j2 in its managed runtimes or base container images. These are therefore not affected by the issues described in CVE-2021-44228, CVE-2021-45046, and CVE-2021-45105.
For cases where a customer function includes an impacted Log4j2 version, we have applied a change to the Lambda Java managed runtimes and base container images that helps to mitigate the issues in CVE-2021-44228, CVE-2021-45046, and CVE-2021-45105.
As a result of this change, customers using Log4J2 may see an additional log entry, similar to "Transforming org/apache/logging/log4j/core/lookup/JndiLookup (java.net.URLClassLoader@...)".
Any log strings that reference the jndi mapper in the Log4J2 output are replaced with "Patched JndiLookup::lookup()".
Independent of this change, we strongly encourage all customers whose functions include Log4j2 to update to the latest version.
Specifically, customers using the aws-lambda-java-log4j2 library in their functions should update to version 1.5.0 (or later), and redeploy their functions.
This version updates the underlying Log4j2 utility dependencies to version 2.17.0 (or later). The updated aws-lambda-java-log4j2 binary is available at the Maven repository
Lastly, take note that any libraries related to aws-lambda-java-log4j (v1.0.0 or 1.0.1) should not be used under any circumstance. These libraries are related to version 1.x of log4j which went end of life in 2015. The libraries are not supported, not maintained, not patched, and have known security vulnerabilities.
To customize log output, support logging during unit tests, and log AWS SDK calls, use Apache Log4j2 with SLF4J. Log4j is a logging library for Java programs that you can use to configure log levels and use appender libraries. SLF4J is a facade library that you can use to change which library you use without changing your function code.
To add the request ID to your function's logs, use the appender in the aws-lambda-java-log4j2 library.
Example src/main/resources/log4j2.xml – Appender configuration
<Configuration> <Appenders> <Lambda name="Lambda" format="${env:AWS_LAMBDA_LOG_FORMAT:-TEXT}"> <LambdaTextFormat> <PatternLayout> <pattern>%d{yyyy-MM-dd HH:mm:ss} %X{AWSRequestId} %-5p %c{1} - %m%n </pattern> </PatternLayout> </LambdaTextFormat> <LambdaJSONFormat> <JsonTemplateLayout eventTemplateUri="classpath:LambdaLayout.json" /> </LambdaJSONFormat> </Lambda> </Appenders> <Loggers> <Root level="${env:AWS_LAMBDA_LOG_LEVEL:-INFO}"> <AppenderRef ref="Lambda"/> </Root> <Logger name="software.amazon.awssdk" level="WARN" /> <Logger name="software.amazon.awssdk.request" level="DEBUG" /> </Loggers> </Configuration>
You can decide how your Log4j2 logs are configured for either plain text or JSON outputs by specifying a layout under
the <LambdaTextFormat> and <LambdaJSONFormat> tags.
In this example, in text mode, each line is prepended with the date, time, request ID, log level, and class
name. In JSON mode, the <JsonTemplateLayout> is used with a configuration that ships together with the
aws-lambda-java-log4j2 library.
SLF4J is a facade library for logging in Java code. In your function code, you use the SLF4J logger factory to
retrieve a logger with methods for log levels like info() and warn(). In your build
configuration, you include the logging library and SLF4J adapter in the classpath. By changing the libraries in
the build configuration, you can change the logger type without changing your function code. SLF4J is required to
capture logs from the SDK for Java.
In the following example code, the handler class uses SLF4J to retrieve a logger.
Example src/main/java/example/HandlerS3.java – Logging with SLF4J
package example; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.amazonaws.services.lambda.runtime.Context; import com.amazonaws.services.lambda.runtime.RequestHandler; import com.amazonaws.services.lambda.runtime.events.S3Event; import static org.apache.logging.log4j.CloseableThreadContext.put; public class HandlerS3 implements RequestHandler<S3Event, String>{ private static final Logger logger = LoggerFactory.getLogger(HandlerS3.class); @Override public String handleRequest(S3Event event, Context context) { for(var record : event.getRecords()) { try (var loggingCtx = put("awsRegion", record.getAwsRegion())) { loggingCtx.put("eventName", record.getEventName()); loggingCtx.put("bucket", record.getS3().getBucket().getName()); loggingCtx.put("key", record.getS3().getObject().getKey()); logger.info("Handling s3 event"); } } return "Ok"; } }
This code produces log outputs like the following:
Example log format
{
"timestamp": "2023-11-15T16:56:00.815Z",
"level": "INFO",
"message": "Handling s3 event",
"logger": "example.HandlerS3",
"AWSRequestId": "0bced576-3936-4e5a-9dcd-db9477b77f97",
"awsRegion": "eu-south-1",
"bucket": "java-logging-test-input-bucket",
"eventName": "ObjectCreated:Put",
"key": "test-folder/"
}The build configuration takes runtime dependencies on the Lambda appender and SLF4J adapter, and implementation dependencies on Log4j2.
Example build.gradle – Logging dependencies
dependencies { ... 'com.amazonaws:aws-lambda-java-log4j2:[1.6.0,)', 'com.amazonaws:aws-lambda-java-events:[3.11.3,)', 'org.apache.logging.log4j:log4j-layout-template-json:[2.17.1,)', 'org.apache.logging.log4j:log4j-slf4j2-impl:[2.19.0,)', ... }
When you run your code locally for tests, the context object with the Lambda logger is not available, and there's no request ID for the Lambda appender to use. For example test configurations, see the sample applications in the next section.
Using other logging tools and libraries
Powertools for AWS Lambda (Java) is a developer toolkit to implement Serverless best practices and increase developer velocity. The Logging utility provides a Lambda optimized logger which includes additional information about function context across all your functions with output structured as JSON. Use this utility to do the following:
Capture key fields from the Lambda context, cold start and structures logging output as JSON
Log Lambda invocation events when instructed (disabled by default)
Print all the logs only for a percentage of invocations via log sampling (disabled by default)
Append additional keys to structured log at any point in time
Use a custom log formatter (Bring Your Own Formatter) to output logs in a structure compatible with your organization’s Logging RFC
Using Powertools for AWS Lambda (Java) and AWS SAM for structured logging
Follow the steps below to download, build, and deploy a sample Hello World Java application with integrated Powertools for AWS Lambda (Java) modules using the AWS SAM. This application implements a
basic API backend and uses Powertools for emitting logs, metrics, and traces. It consists of an Amazon API Gateway endpoint and a Lambda function.
When you send a GET request to the API Gateway endpoint, the Lambda function invokes, sends logs and metrics using Embedded Metric Format to CloudWatch, and
sends traces to AWS X-Ray. The function returns a hello world message.
Prerequisites
To complete the steps in this section, you must have the following:
-
Java 11
-
AWS SAM CLI version 1.75 or later. If you have an older version of the AWS SAM CLI, see Upgrading the AWS SAM CLI.
Deploy a sample AWS SAM application
-
Initialize the application using the Hello World Java template.
sam init --app-template hello-world-powertools-java --name sam-app --package-type Zip --runtime java11 --no-tracing -
Build the app.
cd sam-app && sam build -
Deploy the app.
sam deploy --guided -
Follow the on-screen prompts. To accept the default options provided in the interactive experience, press
Enter.Note
For HelloWorldFunction may not have authorization defined, Is this okay?, make sure to enter
y. -
Get the URL of the deployed application:
aws cloudformation describe-stacks --stack-name sam-app --query 'Stacks[0].Outputs[?OutputKey==`HelloWorldApi`].OutputValue' --output text -
Invoke the API endpoint:
curl -X GET<URL_FROM_PREVIOUS_STEP>If successful, you'll see this response:
{"message":"hello world"} -
To get the logs for the function, run sam logs. For more information, see Working with logs in the AWS Serverless Application Model Developer Guide.
sam logs --stack-name sam-appThe log output looks like this:
2025/09/03/[$LATEST]851411a899b545eea2cffeba4cfbec81 2023-02-03T09:24:34.095000 INIT_START Runtime Version: java:11.v15 Runtime Version ARN: arn:aws:lambda:eu-central-1::runtime:0a25e3e7a1cc9ce404bc435eeb2ad358d8fa64338e618d0c224fe509403583ca 2025/09/03/[$LATEST]851411a899b545eea2cffeba4cfbec81 2023-02-03T09:24:34.114000 Picked up JAVA_TOOL_OPTIONS: -XX:+TieredCompilation -XX:TieredStopAtLevel=1 2025/09/03/[$LATEST]851411a899b545eea2cffeba4cfbec81 2023-02-03T09:24:34.793000 Transforming org/apache/logging/log4j/core/lookup/JndiLookup (lambdainternal.CustomerClassLoader@1a6c5a9e) 2025/09/03/[$LATEST]851411a899b545eea2cffeba4cfbec81 2023-02-03T09:24:35.252000 START RequestId: 7fcf1548-d2d4-41cd-a9a8-6ae47c51f765 Version: $LATEST 2025/09/03/[$LATEST]851411a899b545eea2cffeba4cfbec81 2023-02-03T09:24:36.531000 { "_aws": { "Timestamp": 1675416276051, "CloudWatchMetrics": [ { "Namespace": "sam-app-powerools-java", "Metrics": [ { "Name": "ColdStart", "Unit": "Count" } ], "Dimensions": [ [ "Service", "FunctionName" ] ] } ] }, "function_request_id": "7fcf1548-d2d4-41cd-a9a8-6ae47c51f765", "traceId": "Root=1-63dcd2d1-25f90b9d1c753a783547f4dd;Parent=e29684c1be352ce4;Sampled=1", "FunctionName": "sam-app-HelloWorldFunction-y9Iu1FLJJBGD", "functionVersion": "$LATEST", "ColdStart": 1.0, "Service": "service_undefined", "logStreamId": "2025/09/03/[$LATEST]851411a899b545eea2cffeba4cfbec81", "executionEnvironment": "AWS_Lambda_java11" } 2025/09/03/[$LATEST]851411a899b545eea2cffeba4cfbec81 2023-02-03T09:24:36.974000 Feb 03, 2023 9:24:36 AM com.amazonaws.xray.AWSXRayRecorder <init> 2025/09/03/[$LATEST]851411a899b545eea2cffeba4cfbec81 2023-02-03T09:24:36.993000 Feb 03, 2023 9:24:36 AM com.amazonaws.xray.config.DaemonConfiguration <init> 2025/09/03/[$LATEST]851411a899b545eea2cffeba4cfbec81 2023-02-03T09:24:36.993000 INFO: Environment variable AWS_XRAY_DAEMON_ADDRESS is set. Emitting to daemon on address XXXX.XXXX.XXXX.XXXX:2000. 2025/09/03/[$LATEST]851411a899b545eea2cffeba4cfbec81 2023-02-03T09:24:37.331000 09:24:37.294 [main] INFO helloworld.App -