Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 56 additions & 0 deletions .github/workflows/build-integration-test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# this workflow verifies that the integration test Lambda function builds successfully.
# it does NOT deploy or run the tests (that requires AWS credentials and is done in
# run-integration-test.yml).
Comment on lines +1 to +3

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Aren't those supposed to fail as well in the run-integration-test. It seems to me that those test s are rebuilt also there.


name: Build integration tests

on:
push:
branches: [ main ]
paths:
- 'aws-lambda-java-log4j2/**'
- 'aws-lambda-java-core/**'
- 'lambda-integration-tests/**'
pull_request:
branches: [ '*' ]
paths:
- 'aws-lambda-java-log4j2/**'
- 'aws-lambda-java-core/**'
- 'lambda-integration-tests/**'
- '.github/workflows/build-integration-test.yml'

permissions:
contents: read

jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6

- name: Set up JDK
uses: actions/setup-java@v5
with:
java-version: |
8
21
distribution: corretto
cache: maven

- name: Install core with Maven
run: |
export JAVA_HOME=$JAVA_HOME_8_X64
mvn -B install --file aws-lambda-java-core/pom.xml
- name: Install log4j2 with Maven
run: |
export JAVA_HOME=$JAVA_HOME_8_X64
mvn -B install --file aws-lambda-java-log4j2/pom.xml
# build the integration test function
# this verifies that the function compiles and packages correctly.
# the tests will run in run-integration-test.yml which deploys to AWS.
- name: Package integration test function
run: |
export JAVA_HOME=$JAVA_HOME_21_X64
mvn -B package --file lambda-integration-tests/log4j2-test-function/pom.xml
102 changes: 102 additions & 0 deletions .github/workflows/run-integration-test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
# this workflow deploys a Lambda function that uses aws-lambda-java-log4j2,
# invokes it, and verifies that logs arrive in CloudWatch.

name: Run integration tests

permissions:
id-token: write
contents: read

on:
workflow_dispatch:
push:
branches: [ main ]
paths:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here the test should be run for most packages, at least the one that are involved.

core, serialization, runtime-interface-client, log4j and i would also add events.

- 'aws-lambda-java-log4j2/**'
- 'aws-lambda-java-core/**'
- 'lambda-integration-tests/**'

jobs:
run-integration-tests:
# Only run on the main repo, not forks
if: ${{ github.repository_owner == 'aws' }}
runs-on: ubuntu-latest
concurrency:
group: integration-test
cancel-in-progress: false
steps:
- uses: actions/checkout@v6

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add the commit sha to prevent supply chain attacks.


- name: Set up JDK
uses: actions/setup-java@v5

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here and in all other references to github actions.

with:
java-version: |
8
21
distribution: corretto
cache: maven

- name: Install SAM CLI
uses: aws-actions/setup-sam@v2
with:
use-installer: true

- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v6.0.0
with:
role-to-assume: ${{ secrets.AWS_ROLE_TO_ASSUME }}
role-session-name: ${{ secrets.ROLE_SESSION_NAME }}
aws-region: ${{ secrets.AWS_REGION }}

- name: Install core with Maven
run: |
export JAVA_HOME=$JAVA_HOME_8_X64
mvn -B install --file aws-lambda-java-core/pom.xml
- name: Install log4j2 with Maven
run: |
export JAVA_HOME=$JAVA_HOME_8_X64

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's probably correct here. But it is not correct in general.

In Java we have some C++ component that are dependent on the architecture. We should have a look at that together.

The test should be run per arch and probably runtime (I was doing a CR also for that). For the moment it's probably fine.

We should also do this #617

mvn -B install --file aws-lambda-java-log4j2/pom.xml
- name: Build SAM stack
run: |
export JAVA_HOME=$JAVA_HOME_21_X64
cd lambda-integration-tests && sam build
- name: Validate SAM stack
run: cd lambda-integration-tests && sam validate --lint

- name: Deploy stack
id: deploy_stack
env:
AWS_REGION: ${{ secrets.AWS_REGION }}
run: |
cd lambda-integration-tests
stackName="aws-lambda-java-log4j2-integ-test-$GITHUB_RUN_ID"
echo "STACK_NAME=$stackName" >> "$GITHUB_OUTPUT"
echo "Stack name = $stackName"
sam deploy \
--stack-name "${stackName}" \
--parameter-overrides "ParameterKey=LambdaRole,ParameterValue=${{ secrets.AWS_LAMBDA_ROLE }}" \
--no-confirm-changeset \
--no-progressbar \
--resolve-s3 \
--capabilities CAPABILITY_IAM \
2>&1 | tee /tmp/sam-deploy.log | tail -n 20
LOG4J2_TEST_FUNCTION=$(sam list stack-outputs --stack-name "${stackName}" --output json | jq -r '.[] | select(.OutputKey=="Log4j2TestFunction") | .OutputValue')
echo "LOG4J2_TEST_FUNCTION=$LOG4J2_TEST_FUNCTION" >> "$GITHUB_OUTPUT"
echo "Function name: $LOG4J2_TEST_FUNCTION"
- name: Run integration test
env:
LOG4J2_TEST_FUNCTION: ${{ steps.deploy_stack.outputs.LOG4J2_TEST_FUNCTION }}
AWS_REGION: ${{ secrets.AWS_REGION }}
run: ./lambda-integration-tests/run-tests.sh

- name: Cleanup
if: always() && steps.deploy_stack.outputs.STACK_NAME
env:
AWS_REGION: ${{ secrets.AWS_REGION }}
STACK_NAME: ${{ steps.deploy_stack.outputs.STACK_NAME }}
run: |
sam delete --stack-name "${STACK_NAME}" --no-prompts --region "${AWS_REGION}"
77 changes: 77 additions & 0 deletions lambda-integration-tests/log4j2-test-function/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>com.amazonaws</groupId>
<artifactId>log4j2-integration-test-function</artifactId>
<version>1.0.0</version>
<packaging>jar</packaging>

<name>Log4j2 Integration Test Function</name>
<description>
Lambda function used to verify that aws-lambda-java-log4j2 correctly emits logs to CloudWatch.
</description>

<properties>
<maven.compiler.source>21</maven.compiler.source>
<maven.compiler.target>21</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<log4j.version>2.25.4</log4j.version>
</properties>

<dependencies>
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-lambda-java-core</artifactId>
<version>1.4.0</version>
</dependency>
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-lambda-java-log4j2</artifactId>
<version>1.6.4</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>${log4j.version}</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>${log4j.version}</version>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.6.1</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<transformers>
<transformer
implementation="com.github.edwgiz.mavenShadePlugin.log4j2CacheTransformer.PluginsCacheFileTransformer">
</transformer>
</transformers>
</configuration>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>com.github.edwgiz</groupId>
<artifactId>maven-shade-plugin.log4j2-cachefile-transformer</artifactId>
<version>2.8.1</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package integ;

import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestHandler;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.util.Map;

/**
* integration test handler that logs a marker string using Log4j2 with the LambdaAppender.
* the test verifies that the marker appears in CloudWatch Logs, confirming end-to-end
* log delivery through the aws-lambda-java-log4j2 library.
*/
public class Log4j2TestHandler implements RequestHandler<Map<String, String>, String> {

private static final Logger logger = LogManager.getLogger(Log4j2TestHandler.class);

@Override
public String handleRequest(Map<String, String> event, Context context) {
String marker = event.getOrDefault("marker", "NO_MARKER_PROVIDED");

logger.info("INTEG_TEST_MARKER: {}", marker);
logger.debug("Debug level message with marker: {}", marker);
logger.warn("Warning level message with marker: {}", marker);
logger.error("Error level message with marker: {}", marker);

return "OK:" + marker;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
<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}:%L - %m%n</pattern>
</PatternLayout>
</LambdaTextFormat>
</Lambda>
</Appenders>
<Loggers>
<Root level="DEBUG">
<AppenderRef ref="Lambda" />
</Root>
</Loggers>
</Configuration>
103 changes: 103 additions & 0 deletions lambda-integration-tests/run-tests.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
# integration test script for aws-lambda-java-log4j2.
# invokes the deployed lambda function and verifies logs appear in CloudWatch.

set -euo pipefail

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For the moment it's sufficient like this but we probably can do something more advanced. For example we can create a Java project that uses a something like JUNIT to run the AWS SDK invoke the function and then get the logs.

In this way we avoid doing scripting and we can also have a nice report for how the test has gone.


FUNCTION_NAME="${LOG4J2_TEST_FUNCTION:?LOG4J2_TEST_FUNCTION env var is required}"
REGION="${AWS_REGION:?AWS_REGION env var is required}"
MARKER="integ-test-$(date +%s)-${RANDOM}"

echo "=== Log4j2 Integration Test ==="
echo "Function: ${FUNCTION_NAME}"
echo "Region: ${REGION}"
echo "Marker: ${MARKER}"
echo ""

# invoke the lambda function
echo ">>> Invoking Lambda function..."
INVOKE_OUTPUT=$(aws lambda invoke \
--function-name "${FUNCTION_NAME}" \
--region "${REGION}" \
--payload "{\"marker\": \"${MARKER}\"}" \
--cli-binary-format raw-in-base64-out \
--output json \
/tmp/integ-test-response.json) || {
echo "FAIL: aws lambda invoke command failed with exit code $?"
echo "Output: ${INVOKE_OUTPUT:-<empty>}"
exit 1
}

echo "Invoke output: ${INVOKE_OUTPUT}"
RESPONSE=$(cat /tmp/integ-test-response.json)
echo "Response payload: ${RESPONSE}"

# check for lambda execution errors
FUNCTION_ERROR=$(echo "${INVOKE_OUTPUT}" | jq -r '.FunctionError // empty')
if [ -n "${FUNCTION_ERROR}" ]; then
echo "FAIL: Lambda function returned an execution error (FunctionError: ${FUNCTION_ERROR})"
echo "Error response: ${RESPONSE}"
exit 1
fi

# verify the function executed successfully
if echo "${RESPONSE}" | grep -q "OK:${MARKER}"; then
echo ">>> Function invocation successful."
else
echo "FAIL: Unexpected response from Lambda function."
echo "Expected response containing: OK:${MARKER}"
echo "Got: ${RESPONSE}"
exit 1
fi

# query CloudWatch logs for the marker
LOG_GROUP="/aws/lambda/${FUNCTION_NAME}"
echo ""
echo ">>> Querying CloudWatch Logs group: ${LOG_GROUP}"

MAX_ATTEMPTS=5
WAIT_SECONDS=10
FOUND=false

for attempt in $(seq 1 $MAX_ATTEMPTS); do
echo ">>> Attempt ${attempt}/${MAX_ATTEMPTS}: waiting ${WAIT_SECONDS}s for log propagation..."
sleep "${WAIT_SECONDS}"

LOGS_OUTPUT=$(aws logs filter-log-events \
--log-group-name "${LOG_GROUP}" \
--region "${REGION}" \
--filter-pattern "\"INTEG_TEST_MARKER\" \"${MARKER}\"" \
--start-time $(($(date +%s) * 1000 - 120000)) \
--output json 2>&1)

if echo "${LOGS_OUTPUT}" | grep -q "INTEG_TEST_MARKER: ${MARKER}"; then
FOUND=true
break
fi

echo " Marker not found yet."
WAIT_SECONDS=$((WAIT_SECONDS * 2))
done

# verify the marker was found
if [ "${FOUND}" = true ]; then
echo ""
echo "=== PASS: Log4j2 integration test succeeded ==="
echo "The marker '${MARKER}' was found in CloudWatch Logs (attempt ${attempt})."
echo "This confirms that the LambdaAppender plugin was discovered by Log4j2"
echo "and logs are being delivered to CloudWatch correctly."
else
echo ""
echo "=== FAIL: Log4j2 integration test failed ==="
echo "The marker '${MARKER}' was NOT found in CloudWatch Logs after ${MAX_ATTEMPTS} attempts."
echo "This indicates that the LambdaAppender was not discovered by Log4j2,"
echo "likely due to a missing Log4j2Plugins.dat in the packaged JAR."
echo ""
echo "Dumping all recent log events for debugging:"
aws logs filter-log-events \
--log-group-name "${LOG_GROUP}" \
--region "${REGION}" \
--start-time $(($(date +%s) * 1000 - 120000)) \
--limit 50 \
--output text 2>&1 || true
exit 1
fi
Loading